diff options
Diffstat (limited to 'examples/afl_untracer')
-rw-r--r-- | examples/afl_untracer/Makefile | 2 | ||||
-rw-r--r-- | examples/afl_untracer/README.md | 7 | ||||
-rw-r--r-- | examples/afl_untracer/afl-untracer.c | 96 | ||||
-rw-r--r-- | examples/afl_untracer/patches.txt | 23 |
4 files changed, 70 insertions, 58 deletions
diff --git a/examples/afl_untracer/Makefile b/examples/afl_untracer/Makefile index bfef8fa8..5c525877 100644 --- a/examples/afl_untracer/Makefile +++ b/examples/afl_untracer/Makefile @@ -7,4 +7,4 @@ libtestinstr.so: libtestinstr.c $(CC) -fPIC -o libtestinstr.so -shared libtestinstr.c clean: - rm -f afl-untracer *~ core + rm -f afl-untracer libtestinstr.so *~ core diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md index 90798028..d3af0ceb 100644 --- a/examples/afl_untracer/README.md +++ b/examples/afl_untracer/README.md @@ -3,9 +3,14 @@ afl-untracer is an example skeleton file which can easily be used to fuzz a closed source library. -It is faster and requires less memory than qemu_mode however it is way +It requires less memory 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). + +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 +run, but on the other hand gives much better coverage information. diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c index 420f09a2..4d512356 100644 --- a/examples/afl_untracer/afl-untracer.c +++ b/examples/afl_untracer/afl-untracer.c @@ -76,16 +76,9 @@ static u32 use_stdin = 1; /* This is were the testcase data is written into */ static u8 buf[10000]; // this is the maximum size for a test case! set it! -/* if you want to use fork() then uncomment the following line. Otherwise - threads are used. The differences: - fork() pthread() - speed slow fast - coverage detailed minimal - memory leaks no problem an issue */ -//#define USE_FORK - -/* If you want to have debug output set this to 1 */ -static u32 debug = 1; +/* If you want to have debug output set this to 1, can also be set with + AFL_DEBUG */ +static u32 debug = 0; // END STEP 1 @@ -130,7 +123,7 @@ void read_library_information() { if (debug) fprintf(stderr, "Library list:\n"); while (fgets(buf, sizeof(buf), f)) { - if (strstr(buf, " r-xp ")) { + if (strstr(buf, " r-x")) { if (liblist_cnt >= MAX_LIB_COUNT) { @@ -159,9 +152,9 @@ void read_library_information() { liblist[liblist_cnt].addr_start = strtoull(b, NULL, 16); liblist[liblist_cnt].addr_end = strtoull(m, NULL, 16); if (debug) - fprintf(stderr, "%s:%x (%x-%x)\n", liblist[liblist_cnt].name, + fprintf(stderr, "%s:%x (%lx-%lx)\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); + liblist[liblist_cnt].addr_start, liblist[liblist_cnt].addr_end - 1); liblist_cnt++; } @@ -367,17 +360,13 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) { if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1; // fprintf(stderr, "write1 %d\n", do_exit); - if (!do_exit) - __afl_area_ptr[0] = 1; // otherwise afl-fuzz will exit with NOINST return status; } -static void __afl_end_testcase(void) { +static void __afl_end_testcase(int status) { - s32 res = 0xffffff; - if (write(FORKSRV_FD + 1, &res, 4) != 4) do_exit = 1; - // if (write(FORKSRV_FD + 1, &pid, 4) != 4) do_exit = 1; + if (write(FORKSRV_FD + 1, &status, 4) != 4) do_exit = 1; // fprintf(stderr, "write2 %d\n", do_exit); if (do_exit) exit(0); @@ -455,6 +444,19 @@ void setup_trap_instrumentation() { // It's an offset, parse it and do the patching. unsigned long offset = strtoul(line, NULL, 16); + + // I dont know what it is. /proc/<pid>/maps shows the right start address + // and the offsets generated by the python scripts are fine as well. + // And loading the library into gdb also shows the offsets generated + // by the script are correct. However when loaded via dlopen the first + // 0x1000 are skipped ... +#if defined(__linux__) + if (offset >= 0x1000) + offset -= 0x1000; + else + fprintf(stderr, "Warning: offset is < 0x1000: %x\n", offset); +#endif + if (offset > lib_size) FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large", offset, lib_size); @@ -482,11 +484,10 @@ void setup_trap_instrumentation() { // 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__ + //__arm__: // linux thumb: 0xde01 - // linux thumb2: 0xf7f0a000 // linux arm: 0xe7f001f0 - //__aarch64__ + //__aarch64__: // linux aarch64: 0xd4200000 #endif @@ -510,6 +511,8 @@ void setup_trap_instrumentation() { } +/* the signal handler for the traps / debugging interrupts + No debug output here because this would cost speed */ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { uint64_t addr; @@ -525,31 +528,25 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { #error "Unsupported platform" #endif - if (debug) - fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr, - si->si_addr); + //fprintf(stderr, "TRAP at context addr = %lx, fault addr = %lx\n", addr, si->si_addr); // If the trap didn't come from our instrumentation, then we probably will // just segfault here uint8_t *faultaddr; - if (si->si_addr) + if (unlikely(si->si_addr)) faultaddr = (u8 *)si->si_addr - 1; else faultaddr = (u8 *)addr; - // u8 *loc = SHADOW(faultaddr); - if (debug) - fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr)); + //if (debug) fprintf(stderr, "Shadow location: %p\n", SHADOW(faultaddr)); uint32_t shadow = *SHADOW(faultaddr); uint8_t orig_byte = shadow & 0xff; uint32_t index = shadow >> 8; - if (debug) - fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n", shadow, - orig_byte, index); + //if (debug) fprintf(stderr, "shadow data: %x, orig_byte %02x, index %d\n", shadow, orig_byte, index); // Index zero is invalid so that it is still possible to catch actual trap // instructions in instrumented libraries. - if (index == 0) abort(); + if (unlikely(index == 0)) abort(); // Restore original instruction *faultaddr = orig_byte; @@ -561,6 +558,7 @@ static void sigtrap_handler(int signum, siginfo_t *si, void *context) { /* here you need to specify the parameter for the target function */ static void *(*o_function)(u8 *buf, int len); +/* the MAIN function */ int main(int argc, char *argv[]) { pid = getpid(); @@ -579,11 +577,11 @@ int main(int argc, char *argv[]) { // inclusive of the cleanup functions // NOTE: above the main() you have to define the functions! - /* setup the target */ void *dl = dlopen("./libtestinstr.so", RTLD_LAZY); if (!dl) FATAL("could not find target library"); o_function = dlsym(dl, "testinstr"); if (!o_function) FATAL("could not resolve target function from library"); + if (debug) fprintf(stderr, "Function address: %p\n", o_function); // END STEP 2 @@ -595,42 +593,33 @@ int main(int argc, char *argv[]) { while (1) { -#ifdef USE_FORK if ((pid = fork()) == -1) PFATAL("fork failed"); + if (pid) { u32 status; if (waitpid(pid, &status, 0) < 0) exit(1); + /* report the test case is done and wait for the next */ + __afl_end_testcase(status); } else { -#endif pid = getpid(); while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { -#ifdef USE_FORK + // in this function the fuzz magic happens, this is STEP 3 fuzz(); -#else - if (pthread_create(&__afl_thread, NULL, (void *)fuzz, NULL) != 0) - PFATAL("cannot create thread"); - pthread_join(__afl_thread, NULL); -#endif - /* report the test case is done and wait for the next */ - __afl_end_testcase(); -#ifdef USE_FORK - exit(0); -#endif + // we can use _exit which is faster because our target library + // was loaded via dlopen and there cannot have deconstructors + // registered. + _exit(0); } -#ifdef USE_FORK - } -#endif - } return 0; @@ -651,9 +640,4 @@ static void fuzz() { // END STEP 3 -#ifndef USE_FORK - pthread_exit(NULL); -#endif - } - diff --git a/examples/afl_untracer/patches.txt b/examples/afl_untracer/patches.txt new file mode 100644 index 00000000..b3063e3a --- /dev/null +++ b/examples/afl_untracer/patches.txt @@ -0,0 +1,23 @@ +libtestinstr.so:0x2000L +0x1050L +0x1063L +0x106fL +0x1078L +0x1080L +0x10a4L +0x10b0L +0x10b8L +0x10c0L +0x10c9L +0x10d7L +0x10e3L +0x10f8L +0x1100L +0x1105L +0x111aL +0x1135L +0x1143L +0x114eL +0x115cL +0x116aL +0x116bL |