diff options
Diffstat (limited to 'examples/afl_untracer')
-rw-r--r-- | examples/afl_untracer/Makefile | 10 | ||||
-rw-r--r-- | examples/afl_untracer/README.md | 47 | ||||
-rw-r--r-- | examples/afl_untracer/afl-untracer.c | 85 | ||||
-rw-r--r-- | examples/afl_untracer/ida_get_patchpoints.py | 3 |
4 files changed, 125 insertions, 20 deletions
diff --git a/examples/afl_untracer/Makefile b/examples/afl_untracer/Makefile index 5c525877..14a09b41 100644 --- a/examples/afl_untracer/Makefile +++ b/examples/afl_untracer/Makefile @@ -1,10 +1,16 @@ +ifdef DEBUG + OPT=-O0 +else + OPT=-O3 +endif + all: afl-untracer libtestinstr.so afl-untracer: afl-untracer.c - $(CC) -I../../include -g -o afl-untracer afl-untracer.c -ldl -pthread + $(CC) $(OPT) -I../../include -g -o afl-untracer afl-untracer.c -ldl libtestinstr.so: libtestinstr.c - $(CC) -fPIC -o libtestinstr.so -shared libtestinstr.c + $(CC) -g -O0 -fPIC -o libtestinstr.so -shared libtestinstr.c clean: rm -f afl-untracer libtestinstr.so *~ core diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md index 4ff96423..29234889 100644 --- a/examples/afl_untracer/README.md +++ b/examples/afl_untracer/README.md @@ -1,19 +1,58 @@ -# afl-untracer +# afl-untracer - fast fuzzing of binary-only libraries + +## Introduction afl-untracer is an example skeleton file which can easily be used to fuzz a closed source library. -It requires less memory than qemu_mode however it is way +It requires less memory and is x3-5 faster than qemu_mode however it is way more course grained and does not provide interesting features like compcov or cmplog. -Read and modify afl-untracer.c then `make` and use it as the afl-fuzz target -(or even remote via afl-network-proxy). +Supported is so far Intel (i386/x86_64) and AARCH64. + +## How-to + +### Modify afl-untracer.c + +Read and modify afl-untracer.c then `make`. +To adapt afl-untracer.c to your need read the header of the file and then +search and edit the `STEP 1`, `STEP 2` and `STEP 3` locations. + +### Generate patches.txt file To generate the `patches.txt` file for your target library use the `ida_get_patchpoints.py` script for IDA Pro or `ghidra_get_patchpoints.java` for Ghidra. +The patches.txt file has to pointed to by `AFL_UNTRACER_FILE`. + +To easily run the scripts without needing to run the GUI with Ghidra: +``` +$ /opt/ghidra/support/analyzeHeadless /tmp/ tmp$$ -import libtestinstr.so -postscript ./ghidra_get_patchpoints.java +$ rm -rf /tmp/tmp$$ +``` + +### Fuzzing + +Example (after modifying afl-untracer.c to your needs, compiling and creating +patches.txt): +``` +AFL_UNTRACER_FILE=./patches.txt afl-fuzz -i in -o out -- ./afl-untracer +``` +(or even remote via afl-network-proxy). + +### Testing and debugging + +For testing/debugging you can try: +``` +make DEBUG=1 +AFL_UNTRACER_FILE=./patches.txt AFL_DEBUG=1 gdb ./afl-untracer +``` +and then you can easily set breakpoints to "breakpoint" and "fuzz". + +# Background + This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL) and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz). This implementation is slower because the traps are not patched out with each diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index d319b530..5dbc71bf 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -156,7 +156,7 @@ void read_library_information() { liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); if (debug) fprintf( - stderr, "%s:%x (%lx-%lx)\n", liblist[liblist_cnt].name, + stderr, "%s:%llx (%llx-%llx)\n", liblist[liblist_cnt].name, liblist[liblist_cnt].addr_end - liblist[liblist_cnt].addr_start, liblist[liblist_cnt].addr_start, liblist[liblist_cnt].addr_end - 1); @@ -276,6 +276,18 @@ library_list_t *find_library(char *name) { } +/* for having an easy breakpoint after load the shared library */ +// this seems to work for clang too. nice :) requires gcc 4.4+ +#pragma GCC push_options +#pragma GCC optimize("O0") +void breakpoint() { + + if (debug) fprintf(stderr, "Breakpoint function \"breakpoint\" reached.\n"); + +} + +#pragma GCC pop_options + /* Error reporting to forkserver controller */ void send_forkserver_error(int error) { @@ -433,10 +445,17 @@ static void __afl_end_testcase(int status) { } +#ifdef __aarch64__ +#define SHADOW(addr) \ + ((uint64_t *)(((uintptr_t)addr & 0xfffffffffffffff8) - \ + MEMORY_MAP_DECREMENT - \ + ((uintptr_t)addr & 0x7) * 0x10000000000)) +#else #define SHADOW(addr) \ ((uint32_t *)(((uintptr_t)addr & 0xfffffffffffffffc) - \ MEMORY_MAP_DECREMENT - \ ((uintptr_t)addr & 0x3) * 0x10000000000)) +#endif void setup_trap_instrumentation() { @@ -452,8 +471,12 @@ void setup_trap_instrumentation() { FILE *patches = fopen(filename, "r"); if (!patches) FATAL("Couldn't open AFL_UNTRACER_FILE file %s", filename); - // Index into the coverage bitmap for the current trap instruction. - int bitmap_index = 0; + // Index into the coverage bitmap for the current trap instruction. +#ifdef __aarch64__ + uint64_t bitmap_index = 0; +#else + uint32_t bitmap_index = 0; +#endif while ((nread = getline(&line, &len, patches)) != -1) { @@ -485,9 +508,15 @@ void setup_trap_instrumentation() { PROT_READ | PROT_WRITE | PROT_EXEC) != 0) FATAL("Failed to mprotect library %s writable", line); - // Create shadow memory. + // Create shadow memory. +#ifdef __aarch64__ + for (int i = 0; i < 8; i++) { + +#else for (int i = 0; i < 4; i++) { +#endif + void *shadow_addr = SHADOW(lib_addr + i); void *shadow = mmap(shadow_addr, lib_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0); @@ -513,12 +542,18 @@ void setup_trap_instrumentation() { if (bitmap_index >= __afl_map_size) FATAL("Too many basic blocks to instrument"); - uint32_t *shadow = SHADOW(lib_addr + offset); +#ifdef __arch64__ + uint64_t +#else + uint32_t +#endif + *shadow = SHADOW(lib_addr + offset); if (*shadow != 0) continue; // skip duplicates // Make lookup entry in shadow memory. -#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__)) +#if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__) || \ + defined(__i386__)) // this is for Intel x64 @@ -531,15 +566,29 @@ void setup_trap_instrumentation() { lib_addr, offset, lib_addr + offset, orig_byte, shadow, bitmap_index, *shadow); +#elif defined(__aarch64__) + + // this is for aarch64 + + uint32_t *patch_bytes = (uint32_t *)(lib_addr + offset); + uint32_t orig_bytes = *patch_bytes; + *shadow = (bitmap_index << 32) | orig_bytes; + *patch_bytes = 0xd4200000; // replace instruction with debug trap + if (debug) + fprintf(stderr, + "Patch entry: %p[%x] = %p = %02x -> SHADOW(%p) #%d -> %016x\n", + lib_addr, offset, lib_addr + offset, orig_bytes, shadow, + bitmap_index, *shadow); + #else - // this will be ARM and AARCH64 - // for ARM we will need to identify if the code is in thumb or ARM -#error "non x86_64 not supported yet" - //__arm__: - // linux thumb: 0xde01 - // linux arm: 0xe7f001f0 - //__aarch64__: - // linux aarch64: 0xd4200000 + // this will be ARM and AARCH64 + // for ARM we will need to identify if the code is in thumb or ARM +#error "non x86_64/aarch64 not supported yet" + //__arm__: + // linux thumb: 0xde01 + // linux arm: 0xe7f001f0 + //__aarch64__: + // linux aarch64: 0xd4200000 #endif bitmap_index++; @@ -573,8 +622,15 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { ctx->uc_mcontext->__ss.__rip -= 1; addr = ctx->uc_mcontext->__ss.__rip; #elif defined(__linux__) +#if defined(__x86_64__) || defined(__i386__) ctx->uc_mcontext.gregs[REG_RIP] -= 1; addr = ctx->uc_mcontext.gregs[REG_RIP]; +#elif defined(__aarch64__) + ctx->uc_mcontext.pc -= 4; + addr = ctx->uc_mcontext.pc; +#else +#error "Unsupported processor" +#endif #elif defined(__FreeBSD__) && defined(__LP64__) ctx->uc_mcontext.mc_rip -= 1; addr = ctx->uc_mcontext.mc_rip; @@ -642,6 +698,7 @@ int main(int argc, char *argv[]) { // END STEP 2 /* setup instrumentation, shared memory and forkserver */ + breakpoint(); read_library_information(); setup_trap_instrumentation(); __afl_map_shm(); diff --git a/examples/afl_untracer/ida_get_patchpoints.py b/examples/afl_untracer/ida_get_patchpoints.py index c7e8f899..43cf6d89 100644 --- a/examples/afl_untracer/ida_get_patchpoints.py +++ b/examples/afl_untracer/ida_get_patchpoints.py @@ -57,3 +57,6 @@ with open(home + "/Desktop/patches.txt", "w") as f: f.write('\n') print("Done, found {} patchpoints".format(len(patchpoints))) + +# For headless script running remove the comment from the next line +#ida_pro.qexit() |