diff options
-rw-r--r-- | examples/qemu_persistent_hook/README.md | 20 | ||||
-rw-r--r-- | examples/qemu_persistent_hook/read_into_rdi.c | 42 | ||||
-rw-r--r-- | examples/qemu_persistent_hook/test.c | 34 | ||||
-rw-r--r-- | include/afl-fuzz.h | 2 | ||||
-rwxr-xr-x | qemu_mode/build_qemu_support.sh | 10 | ||||
-rw-r--r-- | qemu_mode/patches/afl-qemu-common.h | 6 | ||||
-rw-r--r-- | qemu_mode/patches/afl-qemu-cpu-inl.h | 35 | ||||
-rw-r--r-- | qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 112 | ||||
-rw-r--r-- | qemu_mode/patches/configure.diff | 26 | ||||
-rw-r--r-- | src/afl-fuzz-cmplog.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz-globals.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz-init.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz.c | 2 |
13 files changed, 235 insertions, 60 deletions
diff --git a/examples/qemu_persistent_hook/README.md b/examples/qemu_persistent_hook/README.md new file mode 100644 index 00000000..3278b60c --- /dev/null +++ b/examples/qemu_persistent_hook/README.md @@ -0,0 +1,20 @@ +# QEMU persistent hook example + +Compile the test binary and the library: + +``` +gcc -no-pie test.c -o test +gcc -fPIC -shared read_into_rdi.c -o read_into_rdi.so +``` + +Fuzz with: + +``` +export AFL_QEMU_PERSISTENT_ADDR=0x$(nm test | grep "T target_func" | awk '{print $1}') +export AFL_QEMU_PERSISTENT_HOOK=./read_into_rdi.so + +mkdir in +echo 0000 > in/in + +../../afl-fuzz -Q -i in -o out -- ./test +``` diff --git a/examples/qemu_persistent_hook/read_into_rdi.c b/examples/qemu_persistent_hook/read_into_rdi.c new file mode 100644 index 00000000..4c5119e0 --- /dev/null +++ b/examples/qemu_persistent_hook/read_into_rdi.c @@ -0,0 +1,42 @@ +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> + +#define g2h(x) ((void *)((unsigned long)(x) + guest_base)) +#define h2g(x) ((uint64_t)(x) - guest_base) + +enum { + R_EAX = 0, + R_ECX = 1, + R_EDX = 2, + R_EBX = 3, + R_ESP = 4, + R_EBP = 5, + R_ESI = 6, + R_EDI = 7, + R_R8 = 8, + R_R9 = 9, + R_R10 = 10, + R_R11 = 11, + R_R12 = 12, + R_R13 = 13, + R_R14 = 14, + R_R15 = 15, + + R_AL = 0, + R_CL = 1, + R_DL = 2, + R_BL = 3, + R_AH = 4, + R_CH = 5, + R_DH = 6, + R_BH = 7, +}; + +void afl_persistent_hook(uint64_t* regs, uint64_t guest_base) { + + printf("reading into %p\n", regs[R_EDI]); + size_t r = read(0, g2h(regs[R_EDI]), 1024); + printf("readed %ld bytes\n", r); + +} diff --git a/examples/qemu_persistent_hook/test.c b/examples/qemu_persistent_hook/test.c new file mode 100644 index 00000000..079d2be4 --- /dev/null +++ b/examples/qemu_persistent_hook/test.c @@ -0,0 +1,34 @@ +#include <stdio.h> + +int target_func(char *buf, int size) { + + printf("buffer:%p, size:%p\n", buf, size); + switch (buf[0]) { + + case 1: + if (buf[1] == '\x44') { + puts("a"); + } + break; + case 0xff: + if (buf[2] == '\xff') { + if (buf[1] == '\x44') { + puts("b"); + } + } + break; + default: break; + + } + + return 1; + +} + +char data[1024]; + +int main() { + + target_func(data, 1024); + +} diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 751bd93c..c62fcc84 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -455,7 +455,7 @@ u8* (*post_handler)(u8* buf, u32* len); /* CmpLog */ extern u8* cmplog_binary; -extern s32 cmplog_forksrv_pid; +extern s32 cmplog_child_pid, cmplog_forksrv_pid; /* hooks for the custom mutator function */ /** diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 6f2bc448..0413228c 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -156,16 +156,18 @@ patch -p1 <../patches/arm-translate.diff || exit 1 patch -p1 <../patches/i386-ops_sse.diff || exit 1 patch -p1 <../patches/i386-fpu_helper.diff || exit 1 patch -p1 <../patches/softfloat.diff || exit 1 +patch -p1 <../patches/configure.diff || exit 1 echo "[+] Patching done." if [ "$STATIC" = "1" ]; then - CFLAGS="-O3 -ggdb" ./configure --disable-bsd-user --disable-guest-agent --disable-strip --disable-werror \ + ./configure --extra-cflags="-O3 -ggdb -DAFL_QEMU_STATIC_BUILD=1" \ + --disable-bsd-user --disable-guest-agent --disable-strip --disable-werror \ --disable-gcrypt --disable-debug-info --disable-debug-tcg --disable-tcg-interpreter \ --enable-attr --disable-brlapi --disable-linux-aio --disable-bzip2 --disable-bluez --disable-cap-ng \ --disable-curl --disable-fdt --disable-glusterfs --disable-gnutls --disable-nettle --disable-gtk \ - --disable-rdma --disable-libiscsi --disable-vnc-jpeg --enable-kvm --disable-lzo --disable-curses \ + --disable-rdma --disable-libiscsi --disable-vnc-jpeg --disable-lzo --disable-curses \ --disable-libnfs --disable-numa --disable-opengl --disable-vnc-png --disable-rbd --disable-vnc-sasl \ --disable-sdl --disable-seccomp --disable-smartcard --disable-snappy --disable-spice --disable-libssh2 \ --disable-libusb --disable-usb-redir --disable-vde --disable-vhost-net --disable-virglrenderer \ @@ -178,9 +180,9 @@ else # --enable-pie seems to give a couple of exec's a second performance # improvement, much to my surprise. Not sure how universal this is.. - CFLAGS="-O3 -ggdb" ./configure --disable-system \ + ./configure --disable-system \ --enable-linux-user --disable-gtk --disable-sdl --disable-vnc \ - --target-list="${CPU_TARGET}-linux-user" --enable-pie --enable-kvm $CROSS_PREFIX || exit 1 + --target-list="${CPU_TARGET}-linux-user" --enable-pie $CROSS_PREFIX || exit 1 fi diff --git a/qemu_mode/patches/afl-qemu-common.h b/qemu_mode/patches/afl-qemu-common.h index 18c36f73..de6c7b73 100644 --- a/qemu_mode/patches/afl-qemu-common.h +++ b/qemu_mode/patches/afl-qemu-common.h @@ -59,6 +59,8 @@ #define INC_AFL_AREA(loc) afl_area_ptr[loc]++ #endif +typedef void (*afl_persistent_hook_fn)(uint64_t* regs, uint64_t guest_base); + /* Declared in afl-qemu-cpu-inl.h */ extern unsigned char *afl_area_ptr; @@ -72,9 +74,11 @@ extern unsigned char is_persistent; extern target_long persistent_stack_offset; extern unsigned char persistent_first_pass; extern unsigned char persistent_save_gpr; -extern target_ulong persistent_saved_gpr[AFL_REGS_NUM]; +extern uint64_t persistent_saved_gpr[AFL_REGS_NUM]; extern int persisent_retaddr_offset; +extern afl_persistent_hook_fn afl_persistent_hook_ptr; + extern __thread abi_ulong afl_prev_loc; extern struct cmp_map* __afl_cmp_map; diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 9a98fde3..7ef54d78 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -34,6 +34,10 @@ #include <sys/shm.h> #include "afl-qemu-common.h" +#ifndef AFL_QEMU_STATIC_BUILD +#include <dlfcn.h> +#endif + /*************************** * VARIOUS AUXILIARY STUFF * ***************************/ @@ -95,6 +99,8 @@ unsigned char persistent_save_gpr; target_ulong persistent_saved_gpr[AFL_REGS_NUM]; int persisent_retaddr_offset; +afl_persistent_hook_fn afl_persistent_hook_ptr; + /* Instrumentation ratio: */ unsigned int afl_inst_rms = MAP_SIZE; /* Exported for afl_gen_trace */ @@ -192,7 +198,7 @@ static void afl_setup(void) { __afl_cmp_map = shmat(shm_id, NULL, 0); - if (__afl_cmp_map == (void*)-1) _exit(1); + if (__afl_cmp_map == (void*)-1) exit(1); } @@ -240,6 +246,33 @@ static void afl_setup(void) { if (getenv("AFL_QEMU_PERSISTENT_GPR")) persistent_save_gpr = 1; + if (getenv("AFL_QEMU_PERSISTENT_HOOK")) { + +#ifdef AFL_QEMU_STATIC_BUILD + + fprintf(stderr, "[AFL] ERROR: you cannot use AFL_QEMU_PERSISTENT_HOOK when afl-qemu-trace is static\n"); + exit(1); + +#else + + persistent_save_gpr = 1; + + void* plib = dlopen(getenv("AFL_QEMU_PERSISTENT_HOOK"), RTLD_NOW); + if (!plib) { + fprintf(stderr, "[AFL] ERROR: invalid AFL_QEMU_PERSISTENT_HOOK=%s\n", getenv("AFL_QEMU_PERSISTENT_HOOK")); + exit(1); + } + + afl_persistent_hook_ptr = dlsym(plib, "afl_persistent_hook"); + if (!afl_persistent_hook_ptr) { + fprintf(stderr, "[AFL] ERROR: failed to find the function \"afl_persistent_hook\" in %s\n", getenv("AFL_QEMU_PERSISTENT_HOOK")); + exit(1); + } + +#endif + + } + if (getenv("AFL_QEMU_PERSISTENT_RETADDR_OFFSET")) persisent_retaddr_offset = strtoll(getenv("AFL_QEMU_PERSISTENT_RETADDR_OFFSET"), NULL, 0); diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index 9f032feb..d081060f 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -254,62 +254,71 @@ static void log_x86_sp_content(void) { }*/ -#define I386_RESTORE_STATE_FOR_PERSISTENT \ - do { \ - \ - if (persistent_save_gpr) { \ - \ - int i; \ - TCGv_ptr gpr_sv; \ - \ - TCGv_ptr first_pass_ptr = tcg_const_ptr(&persistent_first_pass); \ - TCGv first_pass = tcg_temp_local_new(); \ - TCGv one = tcg_const_tl(1); \ - tcg_gen_ld8u_tl(first_pass, first_pass_ptr, 0); \ - \ - TCGLabel *lbl_save_gpr = gen_new_label(); \ - TCGLabel *lbl_finish_restore_gpr = gen_new_label(); \ - tcg_gen_brcond_tl(TCG_COND_EQ, first_pass, one, lbl_save_gpr); \ - \ - for (i = 0; i < CPU_NB_REGS; ++i) { \ - \ - gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]); \ - tcg_gen_ld_tl(cpu_regs[i], gpr_sv, 0); \ - \ - } \ - \ - tcg_gen_br(lbl_finish_restore_gpr); \ - \ - gen_set_label(lbl_save_gpr); \ - \ - for (i = 0; i < CPU_NB_REGS; ++i) { \ - \ - gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]); \ - tcg_gen_st_tl(cpu_regs[i], gpr_sv, 0); \ - \ - } \ - \ - gen_set_label(lbl_finish_restore_gpr); \ - tcg_temp_free(first_pass); \ - \ - } else if (afl_persistent_ret_addr == 0) { \ - \ - TCGv_ptr stack_off_ptr = tcg_const_ptr(&persistent_stack_offset); \ - TCGv stack_off = tcg_temp_new(); \ - tcg_gen_ld_tl(stack_off, stack_off_ptr, 0); \ - tcg_gen_sub_tl(cpu_regs[R_ESP], cpu_regs[R_ESP], stack_off); \ - tcg_temp_free(stack_off); \ - \ - } \ - \ - } while (0) + +static void callback_to_persistent_hook(void) { + + afl_persistent_hook_ptr(persistent_saved_gpr, guest_base); + +} + +static void i386_restore_state_for_persistent(TCGv* cpu_regs) { + + if (persistent_save_gpr) { + + int i; + TCGv_ptr gpr_sv; + + TCGv_ptr first_pass_ptr = tcg_const_ptr(&persistent_first_pass); + TCGv first_pass = tcg_temp_local_new(); + TCGv one = tcg_const_tl(1); + tcg_gen_ld8u_tl(first_pass, first_pass_ptr, 0); + + TCGLabel *lbl_restore_gpr = gen_new_label(); + tcg_gen_brcond_tl(TCG_COND_NE, first_pass, one, lbl_restore_gpr); + + // save GRP registers + for (i = 0; i < CPU_NB_REGS; ++i) { + + gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]); + tcg_gen_st_tl(cpu_regs[i], gpr_sv, 0); + + } + + gen_set_label(lbl_restore_gpr); + + tcg_gen_afl_call0(&afl_persistent_loop); + + if (afl_persistent_hook_ptr) + tcg_gen_afl_call0(callback_to_persistent_hook); + + // restore GRP registers + for (i = 0; i < CPU_NB_REGS; ++i) { + + gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]); + tcg_gen_ld_tl(cpu_regs[i], gpr_sv, 0); + + } + + tcg_temp_free(first_pass); + + } else if (afl_persistent_ret_addr == 0) { + + TCGv_ptr stack_off_ptr = tcg_const_ptr(&persistent_stack_offset); + TCGv stack_off = tcg_temp_new(); + tcg_gen_ld_tl(stack_off, stack_off_ptr, 0); + tcg_gen_sub_tl(cpu_regs[R_ESP], cpu_regs[R_ESP], stack_off); + tcg_temp_free(stack_off); + + } + +} #define AFL_QEMU_TARGET_i386_SNIPPET \ if (is_persistent) { \ \ if (s->pc == afl_persistent_addr) { \ \ - I386_RESTORE_STATE_FOR_PERSISTENT; \ + i386_restore_state_for_persistent(cpu_regs); \ /*tcg_gen_afl_call0(log_x86_saved_gpr); \ tcg_gen_afl_call0(log_x86_sp_content);*/ \ \ @@ -319,7 +328,8 @@ static void log_x86_sp_content(void) { tcg_gen_st_tl(paddr, cpu_regs[R_ESP], persisent_retaddr_offset); \ \ } \ - tcg_gen_afl_call0(&afl_persistent_loop); \ + \ + if (!persistent_save_gpr) tcg_gen_afl_call0(&afl_persistent_loop); \ /*tcg_gen_afl_call0(log_x86_sp_content);*/ \ \ } else if (afl_persistent_ret_addr && s->pc == afl_persistent_ret_addr) { \ diff --git a/qemu_mode/patches/configure.diff b/qemu_mode/patches/configure.diff new file mode 100644 index 00000000..acb96294 --- /dev/null +++ b/qemu_mode/patches/configure.diff @@ -0,0 +1,26 @@ +diff --git a/configure b/configure +index 1c9f609..3edc9a7 100755 +--- a/configure ++++ b/configure +@@ -4603,6 +4603,21 @@ if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \ + libs_softmmu="-lutil $libs_softmmu" + fi + ++########################################## ++cat > $TMPC << EOF ++#include <dlfcn.h> ++#include <stdlib.h> ++int main(int argc, char **argv) { return dlopen("libc.so", RTLD_NOW) != NULL; } ++EOF ++if compile_prog "" "" ; then ++ : ++elif compile_prog "" "-ldl" ; then ++ LIBS="-ldl $LIBS" ++ libs_qga="-ldl $libs_qga" ++else ++ error_exit "libdl check failed" ++fi ++ + ########################################## + # spice probe + if test "$spice" != "no" ; then diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 69efcffa..709abefe 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -27,7 +27,7 @@ #include "afl-fuzz.h" #include "cmplog.h" -static s32 cmplog_child_pid, cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd; +static s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd; void init_cmplog_forkserver(char** argv) { diff --git a/src/afl-fuzz-globals.c b/src/afl-fuzz-globals.c index 154f281e..d5d70542 100644 --- a/src/afl-fuzz-globals.c +++ b/src/afl-fuzz-globals.c @@ -252,7 +252,7 @@ u32 a_extras_cnt; /* Total number of tokens available */ u8 *(*post_handler)(u8 *buf, u32 *len); u8 *cmplog_binary; -s32 cmplog_forksrv_pid; +s32 cmplog_child_pid, cmplog_forksrv_pid; /* hooks for the custom mutator function */ size_t (*custom_mutator)(u8 *data, size_t size, u8 *mutated_out, diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 9265e4a5..fc3e1140 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1822,6 +1822,8 @@ static void handle_stop_sig(int sig) { if (child_pid > 0) kill(child_pid, SIGKILL); if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL); + if (cmplog_child_pid > 0) kill(cmplog_child_pid, SIGKILL); + if (cmplog_forksrv_pid > 0) kill(cmplog_forksrv_pid, SIGKILL); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8833244d..5f453a27 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1017,6 +1017,8 @@ int main(int argc, char** argv) { if (child_pid > 0) kill(child_pid, SIGKILL); if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL); + if (cmplog_child_pid > 0) kill(cmplog_child_pid, SIGKILL); + if (cmplog_forksrv_pid > 0) kill(cmplog_forksrv_pid, SIGKILL); /* Now that we've killed the forkserver, we wait for it to be able to get * rusage stats. */ if (waitpid(forksrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); } |