From e5972efa41c6371a6d1fed14492418ad0a756eae Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 6 Feb 2020 21:43:50 +0100 Subject: cmplog for qemu mode --- qemu_mode/patches/afl-qemu-common.h | 6 ++ qemu_mode/patches/afl-qemu-cpu-inl.h | 22 +++++- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 96 ++++++++++++++++++++++---- 3 files changed, 109 insertions(+), 15 deletions(-) (limited to 'qemu_mode') diff --git a/qemu_mode/patches/afl-qemu-common.h b/qemu_mode/patches/afl-qemu-common.h index 4d651385..18c36f73 100644 --- a/qemu_mode/patches/afl-qemu-common.h +++ b/qemu_mode/patches/afl-qemu-common.h @@ -35,6 +35,9 @@ #define __AFL_QEMU_COMMON #include "../../config.h" +#include "../../include/cmplog.h" + +#define PERSISTENT_DEFAULT_MAX_CNT 1000 #ifndef CPU_NB_REGS #define AFL_REGS_NUM 1000 @@ -74,6 +77,9 @@ extern int persisent_retaddr_offset; extern __thread abi_ulong afl_prev_loc; +extern struct cmp_map* __afl_cmp_map; +extern __thread u32 __afl_cmp_counter; + void afl_debug_dump_saved_regs(); void afl_persistent_loop(); diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index ac847371..0ae6364b 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -32,11 +32,8 @@ */ #include -#include "../../config.h" #include "afl-qemu-common.h" -#define PERSISTENT_DEFAULT_MAX_CNT 1000 - /*************************** * VARIOUS AUXILIARY STUFF * ***************************/ @@ -81,6 +78,9 @@ u8 afl_compcov_level; __thread abi_ulong afl_prev_loc; +struct cmp_map* __afl_cmp_map; +__thread u32 __afl_cmp_counter; + /* Set in the child process in forkserver mode: */ static int forkserver_installed = 0; @@ -181,6 +181,22 @@ static void afl_setup(void) { if (inst_r) afl_area_ptr[0] = 1; } + + if (getenv("___AFL_EINS_ZWEI_POLIZEI___")) { // CmpLog forkserver + + id_str = getenv(CMPLOG_SHM_ENV_VAR); + + if (id_str) { + + u32 shm_id = atoi(id_str); + + __afl_cmp_map = shmat(shm_id, NULL, 0); + + if (__afl_cmp_map == (void*)-1) _exit(1); + + } + + } if (getenv("AFL_INST_LIBS")) { diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index 6d42bf3d..9f032feb 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -102,31 +102,103 @@ static void afl_compcov_log_64(target_ulong cur_loc, target_ulong arg1, } +static void afl_cmplog_16(target_ulong cur_loc, target_ulong arg1, + target_ulong arg2) { + + register uintptr_t k = (uintptr_t)cur_loc; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + // if (!__afl_cmp_map->headers[k].cnt) + // __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++; + + __afl_cmp_map->headers[k].shape = 1; + //__afl_cmp_map->headers[k].type = CMP_TYPE_INS; + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = arg1; + __afl_cmp_map->log[k][hits].v1 = arg2; + +} + +static void afl_cmplog_32(target_ulong cur_loc, target_ulong arg1, + target_ulong arg2) { + + register uintptr_t k = (uintptr_t)cur_loc; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = 3; + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = arg1; + __afl_cmp_map->log[k][hits].v1 = arg2; + +} + +static void afl_cmplog_64(target_ulong cur_loc, target_ulong arg1, + target_ulong arg2) { + + register uintptr_t k = (uintptr_t)cur_loc; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + + __afl_cmp_map->headers[k].shape = 7; + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = arg1; + __afl_cmp_map->log[k][hits].v1 = arg2; + +} + + static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2, TCGMemOp ot, int is_imm) { void *func; - if (!afl_compcov_level || cur_loc > afl_end_code || cur_loc < afl_start_code) + if (cur_loc > afl_end_code || cur_loc < afl_start_code) return; - if (!is_imm && afl_compcov_level < 2) return; + if (__afl_cmp_map) { + + cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); + cur_loc &= CMP_MAP_W - 1; - switch (ot) { + switch (ot) { - case MO_64: func = &afl_compcov_log_64; break; - case MO_32: func = &afl_compcov_log_32; break; - case MO_16: func = &afl_compcov_log_16; break; - default: return; + case MO_64: func = &afl_cmplog_64; break; + case MO_32: func = &afl_cmplog_32; break; + case MO_16: func = &afl_cmplog_16; break; + default: return; - } + } + + tcg_gen_afl_compcov_log_call(func, cur_loc, arg1, arg2); + + } else if (afl_compcov_level) { + + if (!is_imm && afl_compcov_level < 2) return; + + cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); + cur_loc &= MAP_SIZE - 7; - cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); - cur_loc &= MAP_SIZE - 7; + if (cur_loc >= afl_inst_rms) return; + + switch (ot) { - if (cur_loc >= afl_inst_rms) return; + case MO_64: func = &afl_compcov_log_64; break; + case MO_32: func = &afl_compcov_log_32; break; + case MO_16: func = &afl_compcov_log_16; break; + default: return; - tcg_gen_afl_compcov_log_call(func, cur_loc, arg1, arg2); + } + + tcg_gen_afl_compcov_log_call(func, cur_loc, arg1, arg2); + + } } -- cgit 1.4.1 From 1e10e452aaa366c3d06e7eda9f56f127fbf25319 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 7 Feb 2020 17:00:11 +0100 Subject: fix empty range bug in colorization --- Makefile | 2 +- qemu_mode/patches/afl-qemu-cpu-inl.h | 4 +++- src/afl-fuzz-redqueen.c | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'qemu_mode') diff --git a/Makefile b/Makefile index 13be4ec9..70eac6b9 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ ifneq "$(shell uname -m)" "x86_64" endif CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT) -CFLAGS += -Wall -g -Wno-pointer-sign -I include/ \ +override CFLAGS += -Wall -g -Wno-pointer-sign -I include/ \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ -DDOC_PATH=\"$(DOC_PATH)\" -Wno-unused-function diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 0ae6364b..9a98fde3 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -368,8 +368,10 @@ static void afl_forkserver(CPUState *cpu) { if (WIFSTOPPED(status)) child_stopped = 1; - else if (unlikely(first_run && is_persistent)) + else if (unlikely(first_run && is_persistent)) { + fprintf(stderr, "[AFL] ERROR: no persistent iteration executed\n"); exit(12); // Persistent is wrong + } first_run = 0; if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7); diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index d46d2b19..bac7357e 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -122,6 +122,9 @@ u8 colorization(u8* buf, u32 len, u32 exec_cksum) { while ((rng = pop_biggest_range(&ranges)) != NULL && stage_cur) { u32 s = rng->end - rng->start; + if (s == 0) + goto empty_range; + memcpy(backup, buf + rng->start, s); rand_replace(buf + rng->start, s); @@ -136,6 +139,7 @@ u8 colorization(u8* buf, u32 len, u32 exec_cksum) { } else needs_write = 1; +empty_range: ck_free(rng); --stage_cur; -- cgit 1.4.1 From f2f6be5e999632b05ce92b4934ee97531d546a44 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 7 Feb 2020 20:43:17 +0100 Subject: afl qemu persistent hook --- examples/qemu_persistent_hook/README.md | 20 +++++ examples/qemu_persistent_hook/read_into_rdi.c | 42 ++++++++++ examples/qemu_persistent_hook/test.c | 34 ++++++++ include/afl-fuzz.h | 2 +- qemu_mode/build_qemu_support.sh | 10 ++- qemu_mode/patches/afl-qemu-common.h | 6 +- qemu_mode/patches/afl-qemu-cpu-inl.h | 35 +++++++- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 112 ++++++++++++++----------- qemu_mode/patches/configure.diff | 26 ++++++ src/afl-fuzz-cmplog.c | 2 +- src/afl-fuzz-globals.c | 2 +- src/afl-fuzz-init.c | 2 + src/afl-fuzz.c | 2 + 13 files changed, 235 insertions(+), 60 deletions(-) create mode 100644 examples/qemu_persistent_hook/README.md create mode 100644 examples/qemu_persistent_hook/read_into_rdi.c create mode 100644 examples/qemu_persistent_hook/test.c create mode 100644 qemu_mode/patches/configure.diff (limited to 'qemu_mode') 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 +#include +#include + +#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 + +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 #include "afl-qemu-common.h" +#ifndef AFL_QEMU_STATIC_BUILD +#include +#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 ++#include ++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"); } -- cgit 1.4.1 From aa2cb66ea23884eb03cb0220dcfafbdd7343f54d Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 7 Feb 2020 20:44:36 +0100 Subject: code format --- examples/qemu_persistent_hook/read_into_rdi.c | 57 ++++++++------- examples/qemu_persistent_hook/test.c | 12 ++-- qemu_mode/patches/afl-qemu-common.h | 4 +- qemu_mode/patches/afl-qemu-cpu-inl.h | 43 +++++++---- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 98 ++++++++++++-------------- src/afl-fuzz-cmplog.c | 2 +- src/afl-fuzz-redqueen.c | 55 ++++++++------- src/afl-fuzz-stats.c | 14 ++-- 8 files changed, 151 insertions(+), 134 deletions(-) (limited to 'qemu_mode') diff --git a/examples/qemu_persistent_hook/read_into_rdi.c b/examples/qemu_persistent_hook/read_into_rdi.c index 4c5119e0..fd4c9000 100644 --- a/examples/qemu_persistent_hook/read_into_rdi.c +++ b/examples/qemu_persistent_hook/read_into_rdi.c @@ -2,35 +2,37 @@ #include #include -#define g2h(x) ((void *)((unsigned long)(x) + guest_base)) -#define h2g(x) ((uint64_t)(x) - guest_base) +#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, + + 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) { @@ -40,3 +42,4 @@ void afl_persistent_hook(uint64_t* regs, uint64_t guest_base) { printf("readed %ld bytes\n", r); } + diff --git a/examples/qemu_persistent_hook/test.c b/examples/qemu_persistent_hook/test.c index 079d2be4..83001545 100644 --- a/examples/qemu_persistent_hook/test.c +++ b/examples/qemu_persistent_hook/test.c @@ -6,16 +6,15 @@ int target_func(char *buf, int size) { switch (buf[0]) { case 1: - if (buf[1] == '\x44') { - puts("a"); - } + if (buf[1] == '\x44') { puts("a"); } break; case 0xff: if (buf[2] == '\xff') { - if (buf[1] == '\x44') { - puts("b"); - } + + if (buf[1] == '\x44') { puts("b"); } + } + break; default: break; @@ -32,3 +31,4 @@ int main() { target_func(data, 1024); } + diff --git a/qemu_mode/patches/afl-qemu-common.h b/qemu_mode/patches/afl-qemu-common.h index de6c7b73..da3d563e 100644 --- a/qemu_mode/patches/afl-qemu-common.h +++ b/qemu_mode/patches/afl-qemu-common.h @@ -59,7 +59,7 @@ #define INC_AFL_AREA(loc) afl_area_ptr[loc]++ #endif -typedef void (*afl_persistent_hook_fn)(uint64_t* regs, uint64_t guest_base); +typedef void (*afl_persistent_hook_fn)(uint64_t *regs, uint64_t guest_base); /* Declared in afl-qemu-cpu-inl.h */ @@ -81,7 +81,7 @@ extern afl_persistent_hook_fn afl_persistent_hook_ptr; extern __thread abi_ulong afl_prev_loc; -extern struct cmp_map* __afl_cmp_map; +extern struct cmp_map *__afl_cmp_map; extern __thread u32 __afl_cmp_counter; void afl_debug_dump_saved_regs(); diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 7ef54d78..5e155c74 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -82,7 +82,7 @@ u8 afl_compcov_level; __thread abi_ulong afl_prev_loc; -struct cmp_map* __afl_cmp_map; +struct cmp_map *__afl_cmp_map; __thread u32 __afl_cmp_counter; /* Set in the child process in forkserver mode: */ @@ -187,9 +187,9 @@ static void afl_setup(void) { if (inst_r) afl_area_ptr[0] = 1; } - - if (getenv("___AFL_EINS_ZWEI_POLIZEI___")) { // CmpLog forkserver - + + if (getenv("___AFL_EINS_ZWEI_POLIZEI___")) { // CmpLog forkserver + id_str = getenv(CMPLOG_SHM_ENV_VAR); if (id_str) { @@ -198,10 +198,10 @@ 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); } - + } if (getenv("AFL_INST_LIBS")) { @@ -247,32 +247,42 @@ 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"); + 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); + + 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")); + + 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")); + + 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); @@ -402,9 +412,12 @@ static void afl_forkserver(CPUState *cpu) { if (WIFSTOPPED(status)) child_stopped = 1; else if (unlikely(first_run && is_persistent)) { + fprintf(stderr, "[AFL] ERROR: no persistent iteration executed\n"); exit(12); // Persistent is wrong + } + first_run = 0; if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7); diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index d081060f..3c230c30 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -153,17 +153,15 @@ static void afl_cmplog_64(target_ulong cur_loc, target_ulong arg1, } - static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2, TCGMemOp ot, int is_imm) { void *func; - if (cur_loc > afl_end_code || cur_loc < afl_start_code) - return; + if (cur_loc > afl_end_code || cur_loc < afl_start_code) return; if (__afl_cmp_map) { - + cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc &= CMP_MAP_W - 1; @@ -177,16 +175,16 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2, } tcg_gen_afl_compcov_log_call(func, cur_loc, arg1, arg2); - + } else if (afl_compcov_level) { - + if (!is_imm && afl_compcov_level < 2) return; cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); cur_loc &= MAP_SIZE - 7; if (cur_loc >= afl_inst_rms) return; - + switch (ot) { case MO_64: func = &afl_compcov_log_64; break; @@ -197,7 +195,7 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2, } tcg_gen_afl_compcov_log_call(func, cur_loc, arg1, arg2); - + } } @@ -254,62 +252,60 @@ static void log_x86_sp_content(void) { }*/ - 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); - +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); - + 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); - + + 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); - + + 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); - - } + 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); + + } } diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 709abefe..3d34bf71 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -442,7 +442,7 @@ u8 run_cmplog_target(char** argv, u32 timeout) { setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":" "symbolize=0:" "msan_track_origins=0", 0); - + setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); if (!qemu_mode) argv[0] = cmplog_binary; diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index bac7357e..296fcd98 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -122,9 +122,8 @@ u8 colorization(u8* buf, u32 len, u32 exec_cksum) { while ((rng = pop_biggest_range(&ranges)) != NULL && stage_cur) { u32 s = rng->end - rng->start; - if (s == 0) - goto empty_range; - + if (s == 0) goto empty_range; + memcpy(backup, buf + rng->start, s); rand_replace(buf + rng->start, s); @@ -137,9 +136,11 @@ u8 colorization(u8* buf, u32 len, u32 exec_cksum) { ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end); memcpy(buf + rng->start, backup, s); - } else needs_write = 1; + } else + + needs_write = 1; -empty_range: + empty_range: ck_free(rng); --stage_cur; @@ -156,9 +157,9 @@ empty_range: ck_free(rng); } - + // save the input with the high entropy - + if (needs_write) { s32 fd; @@ -169,7 +170,7 @@ empty_range: } else { - unlink(queue_cur->fname); /* ignore errors */ + unlink(queue_cur->fname); /* ignore errors */ fd = open(queue_cur->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); } @@ -177,10 +178,10 @@ empty_range: if (fd < 0) PFATAL("Unable to create '%s'", queue_cur->fname); ck_write(fd, buf, len, queue_cur->fname); - queue_cur->len = len; // no-op, just to be 100% safe - + queue_cur->len = len; // no-op, just to be 100% safe + close(fd); - + } return 0; @@ -305,24 +306,27 @@ u8 cmp_extend_encoding(struct cmp_header* h, u64 pattern, u64 repl, u32 idx, void try_to_add_to_dict(u64 v, u8 shape) { u8* b = (u8*)&v; - + u32 k; - u8 cons_ff = 0, cons_0 = 0; + u8 cons_ff = 0, cons_0 = 0; for (k = 0; k < shape; ++k) { - if (b[k] == 0) ++cons_0; - else if (b[k] == 0xff) ++cons_0; - else cons_0 = cons_ff = 0; - - if (cons_0 > 1 || cons_ff > 1) - return; + if (b[k] == 0) + ++cons_0; + else if (b[k] == 0xff) + ++cons_0; + else + cons_0 = cons_ff = 0; + + if (cons_0 > 1 || cons_ff > 1) return; } - + maybe_add_auto((u8*)&v, shape); - + u64 rev; switch (shape) { + case 1: break; case 2: rev = SWAP16((u16)v); @@ -336,8 +340,9 @@ void try_to_add_to_dict(u64 v, u8 shape) { rev = SWAP64(v); maybe_add_auto((u8*)&rev, shape); break; + } - + } u8 cmp_fuzz(u32 key, u8* orig_buf, u8* buf, u32 len) { @@ -380,13 +385,13 @@ u8 cmp_fuzz(u32 key, u8* orig_buf, u8* buf, u32 len) { break; } - + // If failed, add to dictionary if (fails == 8) { - + try_to_add_to_dict(o->v0, SHAPE_BYTES(h->shape)); try_to_add_to_dict(o->v1, SHAPE_BYTES(h->shape)); - + } cmp_fuzz_next_iter: diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 1b7e5226..d09b4fe6 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -334,9 +334,9 @@ void show_stats(void) { /* Lord, forgive me this. */ - SAYF(SET_G1 bSTG bLT bH bSTOP cCYA + SAYF(SET_G1 bSTG bLT bH bSTOP cCYA " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA - " overall results " bSTG bH2 bH2 bRT "\n"); + " overall results " bSTG bH2 bH2 bRT "\n"); if (dumb_mode) { @@ -413,9 +413,9 @@ void show_stats(void) { " uniq hangs : " cRST "%-6s" bSTG bV "\n", DTD(cur_ms, last_hang_time), tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA - " map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); + " map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); /* This gets funny because we want to print several variable-length variables together, but then cram them into a fixed-width field - so we need to @@ -443,9 +443,9 @@ void show_stats(void) { SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA - " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); + " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); sprintf(tmp, "%s (%0.02f%%)", DI(queued_favored), ((double)queued_favored) * 100 / queued_paths); @@ -514,7 +514,7 @@ void show_stats(void) { /* Aaaalmost there... hold on! */ - SAYF(bVR bH cCYA bSTOP + SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); -- cgit 1.4.1 From 0403f008e3c68a9b212d38a5fc0de79eb2f40895 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Sat, 8 Feb 2020 12:14:00 +0100 Subject: solve small error on building new qemu patches for not x86 targets --- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qemu_mode') diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index 3c230c30..06e73831 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -274,7 +274,7 @@ static void i386_restore_state_for_persistent(TCGv *cpu_regs) { tcg_gen_brcond_tl(TCG_COND_NE, first_pass, one, lbl_restore_gpr); // save GRP registers - for (i = 0; i < CPU_NB_REGS; ++i) { + for (i = 0; i < AFL_REGS_NUM; ++i) { gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]); tcg_gen_st_tl(cpu_regs[i], gpr_sv, 0); @@ -288,7 +288,7 @@ static void i386_restore_state_for_persistent(TCGv *cpu_regs) { if (afl_persistent_hook_ptr) tcg_gen_afl_call0(callback_to_persistent_hook); // restore GRP registers - for (i = 0; i < CPU_NB_REGS; ++i) { + for (i = 0; i < AFL_REGS_NUM; ++i) { gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]); tcg_gen_ld_tl(cpu_regs[i], gpr_sv, 0); -- cgit 1.4.1 From 079f177cdaf43f017bf320912cd97f86dea586be Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 8 Feb 2020 15:41:17 +0100 Subject: persistent mode doc --- docs/Changelog.md | 1 + examples/qemu_persistent_hook/read_into_rdi.c | 4 ++ qemu_mode/README.md | 30 ++------ qemu_mode/README.persistent.md | 99 +++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 25 deletions(-) create mode 100644 qemu_mode/README.persistent.md (limited to 'qemu_mode') diff --git a/docs/Changelog.md b/docs/Changelog.md index 96cfa935..f2c39e65 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -29,6 +29,7 @@ sending a mail to . - CmpLog instrumentation for QEMU (-c afl-fuzz command line option) - AFL_PERSISTENT_HOOK callback module for persistent QEMU (see examples/qemu_persistent_hook) + - added qemu_mode/README.persistent.md documentation - afl-cmin is now a sh script (invoking awk) instead of bash for portability the original script is still present as afl-cmin.bash - afl-showmap: -i dir option now allows processing multiple inputs using the diff --git a/examples/qemu_persistent_hook/read_into_rdi.c b/examples/qemu_persistent_hook/read_into_rdi.c index fd4c9000..3994e790 100644 --- a/examples/qemu_persistent_hook/read_into_rdi.c +++ b/examples/qemu_persistent_hook/read_into_rdi.c @@ -37,8 +37,12 @@ enum { void afl_persistent_hook(uint64_t* regs, uint64_t guest_base) { + // In this example the register RDI is pointing to the memory location + // of the target buffer, and the length of the input is in RAX. + printf("reading into %p\n", regs[R_EDI]); size_t r = read(0, g2h(regs[R_EDI]), 1024); + regs[R_EAX] = r; printf("readed %ld bytes\n", r); } diff --git a/qemu_mode/README.md b/qemu_mode/README.md index ccfd50e3..95b75e9c 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -71,31 +71,11 @@ must be an address of a basic block. ## 4) Bonus feature #2: persistent mode -QEMU mode supports also persistent mode for x86 and x86_64 targets. -The environment variable to enable it is AFL_QEMU_PERSISTENT_ADDR=`start addr`. -In this variable you must specify the address of the function that -has to be the body of the persistent loop. -The code in this function must be stateless like in the LLVM persistent mode. -The return address on stack is patched like in WinAFL in order to repeat the -execution of such function. -Another modality to execute the persistent loop is to specify also the -AFL_QEMU_PERSISTENT_RET=`end addr` env variable. -With this variable assigned, instead of patching the return address, the -specified instruction is transformed to a jump towards `start addr`. -Note that the format of the addresses in such variables is hex. - -Note that the base address of PIE binaries in QEMU user mode is 0x4000000000. - -With the env variable AFL_QEMU_PERSISTENT_GPR you can tell QEMU to save the -original value of general purpose registers and restore them in each cycle. -This allows to use as persistent loop functions that make use of arguments on -x86_64. - -With AFL_QEMU_PERSISTENT_RETADDR_OFFSET you can specify the offset from the -stack pointer in which QEMU can find the return address when `start addr` is -hitted. - -Use this mode with caution, probably it will not work at the first shot. +AFL++'s QEMU mode now supports also persistent mode for x86 and x86_64 targets. +This increases the speed by several factors, however it is a bit of work to set +up - but worth the effort. + +Please see the extra documentation for it: [README.persistent.md](README.persistent.md) ## 5) Bonus feature #3: CompareCoverage diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md new file mode 100644 index 00000000..6dba5a00 --- /dev/null +++ b/qemu_mode/README.persistent.md @@ -0,0 +1,99 @@ +# How to use the persistent mode in AFL++'s QEMU mode + +## 1) Introduction + +Persistent mode let you fuzz your target persistently between to +addresses - without forking for every fuzzing attempt. +This increases the speed by a factor between x2 and x5, hence it is +very, very valuable. + +The persistent mode is currently only available for x86/x86_64 targets. + + +## 2) How use the persistent mode + +### 2.1) The START address + +The start of the persistent mode has to be set with AFL_QEMU_PERSISTENT_ADDR. + +This address must be at the start of a function or the starting address of +basic block. This (as well as the RET address, see below) has to be defined +in hexadecimal with the 0x prefix. + +If the target is compiled with position independant code (PIE/PIC), you must +add 0x4000000000 to that address, because qemu loads to this base address. + +If this address is not valid, afl-fuzz will error during startup with the +message that the forkserver was not found. + + +### 2.2) the RET address + +The RET address is optional, and only needed if the the return should not be +at the end of the function to which the START address points into, but earlier. + +It is defined by setting AFL_QEMU_PERSISTENT_RET, and too 0x4000000000 has to +be set if the target is position independant. + + +### 2.3) the OFFSET + +If the START address is *not* the beginning of a function, and *no* RET has +been set (so the end of the loop will be at the end of the function), the +ESP pointer very likely has to be reset correctly. + +The value by which the ESP pointer has to be corrected has to set in the +variable AFL_QEMU_PERSISTENT_RETADDR_OFFSET + +Now to get this value right here some help: +1. use gdb on the target +2. set a breakpoint to your START address +3. set a breakpoint to the end of the same function +4. "run" the target with a valid commandline +5. at the first breakpoint print the ESP value with +``` +print $esp +``` +6. "continue" the target until the second breakpoint +7. again print the ESP value +8. calculate the difference between the two values - and this is the offset + + +### 2.4) resetting the register state + +It is very, very likely you need to reste the register state when starting +a new loop. Because of this you 99% of the time should set + +AFL_QEMU_PERSISTENT_GPR=1 + + +## 3) optional parameters + +### 3.1) loop counter value + +The more stable your loop in the target, the longer you can run it, the more +unstable it is the lower the loop count should be. A low value would be 100, +the maximum value should be 10000. The default is 1000. +This value can be set with AFL_QEMU_PERSISTENT_CNT + +This is the same concept as in the llvm_mode persistent mode with __AFL_LOOP(). + + +### 3.2) a hook for in-memory fuzzing + +You can increase the speed of the persistent mode even more by bypassing all +the reading of the fuzzing input via a file by reading directly into the +memory address space of the target process. + +All this needs is that the START address has a register pointing to the +memory buffer, and another register holding the value of the read length +(or pointing to the memory where that value is held). + +If the target reads from an input file you have to supply an input file +that is of least of the size that your fuzzing input will be (and do not +supply @@). + +An example that you can use with little modification for your target can +be found here: [examples/qemu_persistent_hook](../examples/qemu_persistent_hook) +This shared library is specified via AFL_QEMU_PERSISTENT_HOOK + -- cgit 1.4.1 From 5fa4f47baec7e3dc78e685f9f8a44bf34c3eba53 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Sat, 8 Feb 2020 18:07:31 +0100 Subject: persistent qemu mode arm/arm64 && compcov arm64 --- qemu_mode/build_qemu_support.sh | 1 + qemu_mode/patches/afl-qemu-common.h | 10 ++- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 119 +++++++++++++++++++------ qemu_mode/patches/arm-translate-a64.diff | 64 +++++++++++++ qemu_mode/patches/arm-translate.diff | 20 ++++- qemu_mode/patches/i386-translate.diff | 2 +- 6 files changed, 183 insertions(+), 33 deletions(-) create mode 100644 qemu_mode/patches/arm-translate-a64.diff (limited to 'qemu_mode') diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 0413228c..79993ce2 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -153,6 +153,7 @@ patch -p1 <../patches/translate-all.diff || exit 1 patch -p1 <../patches/tcg.diff || exit 1 patch -p1 <../patches/i386-translate.diff || exit 1 patch -p1 <../patches/arm-translate.diff || exit 1 +patch -p1 <../patches/arm-translate-a64.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 diff --git a/qemu_mode/patches/afl-qemu-common.h b/qemu_mode/patches/afl-qemu-common.h index da3d563e..4303a5e6 100644 --- a/qemu_mode/patches/afl-qemu-common.h +++ b/qemu_mode/patches/afl-qemu-common.h @@ -39,10 +39,14 @@ #define PERSISTENT_DEFAULT_MAX_CNT 1000 -#ifndef CPU_NB_REGS -#define AFL_REGS_NUM 1000 -#else +#ifdef CPU_NB_REGS #define AFL_REGS_NUM CPU_NB_REGS +#elif TARGET_ARM +#define AFL_REGS_NUM 32 +#elif TARGET_AARCH64 +#define AFL_REGS_NUM 32 +#else +#define AFL_REGS_NUM 100 #endif /* NeverZero */ diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index 06e73831..2b9472b8 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -67,7 +67,7 @@ static void afl_compcov_log_64(target_ulong cur_loc, target_ulong arg1, target_ulong arg2) { register uintptr_t idx = cur_loc; - + if ((arg1 & 0xff00000000000000) == (arg2 & 0xff00000000000000)) { INC_AFL_AREA(idx + 6); @@ -258,63 +258,72 @@ static void callback_to_persistent_hook(void) { } -static void i386_restore_state_for_persistent(TCGv *cpu_regs) { +static void gpr_saving(TCGv *cpu_regs, int regs_num) { - if (persistent_save_gpr) { + int i; + TCGv_ptr gpr_sv; - 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); - 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); - TCGLabel *lbl_restore_gpr = gen_new_label(); - tcg_gen_brcond_tl(TCG_COND_NE, first_pass, one, lbl_restore_gpr); + // save GPR registers + for (i = 0; i < regs_num; ++i) { - // save GRP registers - for (i = 0; i < AFL_REGS_NUM; ++i) { + gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]); + tcg_gen_st_tl(cpu_regs[i], gpr_sv, 0); - 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); - gen_set_label(lbl_restore_gpr); + tcg_gen_afl_call0(&afl_persistent_loop); - tcg_gen_afl_call0(&afl_persistent_loop); + if (afl_persistent_hook_ptr) tcg_gen_afl_call0(callback_to_persistent_hook); - if (afl_persistent_hook_ptr) tcg_gen_afl_call0(callback_to_persistent_hook); + // restore GPR registers + for (i = 0; i < regs_num; ++i) { - // restore GRP registers - for (i = 0; i < AFL_REGS_NUM; ++i) { + gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]); + tcg_gen_ld_tl(cpu_regs[i], gpr_sv, 0); - gpr_sv = tcg_const_ptr(&persistent_saved_gpr[i]); - tcg_gen_ld_tl(cpu_regs[i], gpr_sv, 0); + } - } + tcg_temp_free_ptr(first_pass_ptr); + tcg_temp_free(first_pass); + tcg_temp_free(one); - tcg_temp_free(first_pass); +} + + +static void restore_state_for_persistent(TCGv *cpu_regs, int regs_num, int sp) { + + if (persistent_save_gpr) { + + gpr_saving(cpu_regs, regs_num); } 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_gen_sub_tl(cpu_regs[sp], cpu_regs[sp], stack_off); tcg_temp_free(stack_off); } } -#define AFL_QEMU_TARGET_i386_SNIPPET \ +#define AFL_QEMU_TARGET_I386_SNIPPET \ if (is_persistent) { \ \ if (s->pc == afl_persistent_addr) { \ \ - i386_restore_state_for_persistent(cpu_regs); \ + restore_state_for_persistent(cpu_regs, AFL_REGS_NUM, R_ESP); \ /*tcg_gen_afl_call0(log_x86_saved_gpr); \ tcg_gen_afl_call0(log_x86_sp_content);*/ \ \ @@ -322,6 +331,7 @@ static void i386_restore_state_for_persistent(TCGv *cpu_regs) { \ TCGv_ptr paddr = tcg_const_ptr(afl_persistent_addr); \ tcg_gen_st_tl(paddr, cpu_regs[R_ESP], persisent_retaddr_offset); \ + tcg_temp_free_ptr(paddr); \ \ } \ \ @@ -337,3 +347,56 @@ static void i386_restore_state_for_persistent(TCGv *cpu_regs) { \ } +// SP = 13, LINK = 14 + +#define AFL_QEMU_TARGET_ARM_SNIPPET \ + if (is_persistent) { \ + \ + if (dc->pc == afl_persistent_addr) { \ + \ + if (persistent_save_gpr) gpr_saving(cpu_R, AFL_REGS_NUM); \ + \ + if (afl_persistent_ret_addr == 0) { \ + \ + TCGv_ptr paddr = tcg_const_ptr(afl_persistent_addr); \ + tcg_gen_mov_i32(cpu_R[14], paddr); \ + tcg_temp_free_ptr(paddr); \ + \ + } \ + \ + if (!persistent_save_gpr) tcg_gen_afl_call0(&afl_persistent_loop); \ + \ + } else if (afl_persistent_ret_addr && dc->pc == afl_persistent_ret_addr) {\ + \ + gen_bx_im(dc, afl_persistent_addr); \ + \ + } \ + \ + } + +// SP = 31, LINK = 30 + +#define AFL_QEMU_TARGET_ARM64_SNIPPET \ + if (is_persistent) { \ + \ + if (s->pc == afl_persistent_addr) { \ + \ + if (persistent_save_gpr) gpr_saving(cpu_X, AFL_REGS_NUM); \ + \ + if (afl_persistent_ret_addr == 0) { \ + \ + TCGv_ptr paddr = tcg_const_ptr(afl_persistent_addr); \ + tcg_gen_mov_i32(cpu_X[30], paddr); \ + tcg_temp_free_ptr(paddr); \ + \ + } \ + \ + if (!persistent_save_gpr) tcg_gen_afl_call0(&afl_persistent_loop); \ + \ + } else if (afl_persistent_ret_addr && s->pc == afl_persistent_ret_addr) { \ + \ + gen_goto_tb(s, 0, afl_persistent_addr); \ + \ + } \ + \ + } diff --git a/qemu_mode/patches/arm-translate-a64.diff b/qemu_mode/patches/arm-translate-a64.diff new file mode 100644 index 00000000..83856217 --- /dev/null +++ b/qemu_mode/patches/arm-translate-a64.diff @@ -0,0 +1,64 @@ +diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c +index fd36425..992bf17 100644 +--- a/target/arm/translate-a64.c ++++ b/target/arm/translate-a64.c +@@ -39,6 +39,8 @@ + #include "translate-a64.h" + #include "qemu/atomic128.h" + ++#include "../patches/afl-qemu-cpu-translate-inl.h" ++ + static TCGv_i64 cpu_X[32]; + static TCGv_i64 cpu_pc; + +@@ -3365,6 +3367,12 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t insn) + return; + } + ++ if (rd == 31 && sub_op) { // cmp xX, imm ++ TCGv_i64 tcg_imm = tcg_const_i64(imm); ++ afl_gen_compcov(s->pc, tcg_rn, tcg_imm, is_64bit ? MO_64 : MO_32, 1); ++ tcg_temp_free_i64(tcg_imm); ++ } ++ + tcg_result = tcg_temp_new_i64(); + if (!setflags) { + if (sub_op) { +@@ -3972,6 +3980,9 @@ static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn) + + tcg_rm = read_cpu_reg(s, rm, sf); + ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3); ++ ++ if (rd == 31 && sub_op) // cmp xX, xY ++ afl_gen_compcov(s->pc, tcg_rn, tcg_rm, sf ? MO_64 : MO_32, 0); + + tcg_result = tcg_temp_new_i64(); + +@@ -4037,6 +4048,9 @@ static void disas_add_sub_reg(DisasContext *s, uint32_t insn) + + shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6); + ++ if (rd == 31 && sub_op) // cmp xX, xY ++ afl_gen_compcov(s->pc, tcg_rn, tcg_rm, sf ? MO_64 : MO_32, 0); ++ + tcg_result = tcg_temp_new_i64(); + + if (!setflags) { +@@ -4246,6 +4260,8 @@ static void disas_cc(DisasContext *s, uint32_t insn) + tcg_y = cpu_reg(s, y); + } + tcg_rn = cpu_reg(s, rn); ++ ++ afl_gen_compcov(s->pc, tcg_rn, tcg_y, sf ? MO_64 : MO_32, is_imm); + + /* Set the flags for the new comparison. */ + tcg_tmp = tcg_temp_new_i64(); +@@ -13317,6 +13333,8 @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn) + static void disas_a64_insn(CPUARMState *env, DisasContext *s) + { + uint32_t insn; ++ ++ AFL_QEMU_TARGET_ARM64_SNIPPET + + insn = arm_ldl_code(env, s->pc, s->sctlr_b); + s->insn = insn; diff --git a/qemu_mode/patches/arm-translate.diff b/qemu_mode/patches/arm-translate.diff index 58b4a873..daa5d43b 100644 --- a/qemu_mode/patches/arm-translate.diff +++ b/qemu_mode/patches/arm-translate.diff @@ -1,5 +1,5 @@ diff --git a/target/arm/translate.c b/target/arm/translate.c -index 7c4675ff..0f0928b6 100644 +index 7c4675f..e3d999a 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -59,6 +59,8 @@ @@ -132,3 +132,21 @@ index 7c4675ff..0f0928b6 100644 rd = 16; break; case 0xb: /* cmn */ +@@ -13233,6 +13247,8 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) + return; + } + ++ AFL_QEMU_TARGET_ARM_SNIPPET ++ + insn = arm_ldl_code(env, dc->pc, dc->sctlr_b); + dc->insn = insn; + dc->pc += 4; +@@ -13301,6 +13317,8 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) + return; + } + ++ AFL_QEMU_TARGET_ARM_SNIPPET ++ + insn = arm_lduw_code(env, dc->pc, dc->sctlr_b); + is_16bit = thumb_insn_is_16bit(dc, insn); + dc->pc += 2; diff --git a/qemu_mode/patches/i386-translate.diff b/qemu_mode/patches/i386-translate.diff index 00337e2c..8ccd6f4e 100644 --- a/qemu_mode/patches/i386-translate.diff +++ b/qemu_mode/patches/i386-translate.diff @@ -35,7 +35,7 @@ index 0dd5fbe4..a23da128 100644 rex_w = -1; rex_r = 0; -+ AFL_QEMU_TARGET_i386_SNIPPET ++ AFL_QEMU_TARGET_I386_SNIPPET + next_byte: b = x86_ldub_code(env, s); -- cgit 1.4.1 From 49acc388dd9d318cfe7aa7766be7eea0daf2cbf1 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Feb 2020 09:29:56 +0100 Subject: update documentation --- README.md | 3 ++- docs/Changelog.md | 2 ++ qemu_mode/README.md | 31 +++++++++++++++++++++++-------- qemu_mode/README.persistent.md | 3 ++- 4 files changed, 29 insertions(+), 10 deletions(-) (limited to 'qemu_mode') diff --git a/README.md b/README.md index e7b216e7..c3e8dc48 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,10 @@ | Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode | | ----------------------- |:-------:|:---------:|:----------:|:---------:|:------------:| - | laf-intel / CompCov | | x | | x86/arm | x86/arm | | NeverZero | x | x(1) | (2) | x | x | | Persistent mode | | x | x | x86 | x | + | laf-intel / CompCov | | x | | x86/arm | x86/arm | + | CmpLog | | x | | x | | | Whitelist | | x | x | | | | InsTrim | | x | | | | diff --git a/docs/Changelog.md b/docs/Changelog.md index f2c39e65..8b56603f 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -26,7 +26,9 @@ sending a mail to . - LLVM 11 is supported - CmpLog instrumentation using SanCov (see llvm_mode/README.cmplog) - qemu_mode: + - persistent mode is now also available for arm and aarch64 - CmpLog instrumentation for QEMU (-c afl-fuzz command line option) + for x86, x86_64, arm and aarch64 - AFL_PERSISTENT_HOOK callback module for persistent QEMU (see examples/qemu_persistent_hook) - added qemu_mode/README.persistent.md documentation diff --git a/qemu_mode/README.md b/qemu_mode/README.md index 95b75e9c..4198af14 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -71,7 +71,8 @@ must be an address of a basic block. ## 4) Bonus feature #2: persistent mode -AFL++'s QEMU mode now supports also persistent mode for x86 and x86_64 targets. +AFL++'s QEMU mode now supports also persistent mode for x86, x86_64, arm +and aarch64 targets. This increases the speed by several factors, however it is a bit of work to set up - but worth the effort. @@ -85,6 +86,7 @@ The option that enables QEMU CompareCoverage is AFL_COMPCOV_LEVEL. There is also ./libcompcov/ which implements CompareCoverage for *cmp functions (splitting memcmp, strncmp, etc. to make these conditions easier solvable by afl-fuzz). + AFL_COMPCOV_LEVEL=1 is to instrument comparisons with only immediate values / read-only memory. AFL_COMPCOV_LEVEL=2 instruments all comparison instructions and memory comparison functions when libcompcov @@ -93,11 +95,23 @@ AFL_COMPCOV_LEVEL=3 has the same effects of AFL_COMPCOV_LEVEL=2 but enables also the instrumentation of the floating-point comparisons on x86 and x86_64 (experimental). Integer comparison instructions are currently instrumented only -on the x86, x86_64 and ARM targets. +on the x86, x86_64, arm and aarch64 targets. Highly recommended. -## 6) Bonus feature #4: Wine mode +## 6) CMPLOG mode + +Another new feature is CMPLOG, which is based on the redqueen project. +Here all immidiates in CMP instructions are learned and put into a dynamic +dictionary and applied to all locations in the input that reached that +CMP, trying to solve and pass it. +This is a very effective feature and it is available for x86, x86_64, arm +and aarch64. + +To enable it you must pass on the command line of afl-fuzz: + -c /path/to/your/target + +## 7) Bonus feature #4: Wine mode AFL++ QEMU can use Wine to fuzz WIn32 PE binaries. Use the -W flag of afl-fuzz. @@ -105,7 +119,7 @@ Note that some binaries require user interaction with the GUI and must be patche For examples look [here](https://github.com/andreafioraldi/WineAFLplusplusDEMO). -## 7) Notes on linking +## 8) Notes on linking The feature is supported only on Linux. Supporting BSD may amount to porting the changes made to linux-user/elfload.c and applying them to @@ -126,7 +140,7 @@ practice, this means two things: Setting AFL_INST_LIBS=1 can be used to circumvent the .text detection logic and instrument every basic block encountered. -## 8) Benchmarking +## 9) Benchmarking If you want to compare the performance of the QEMU instrumentation with that of afl-gcc compiled code against the same target, you need to build the @@ -141,7 +155,7 @@ Comparative measurements of execution speed or instrumentation coverage will be fairly meaningless if the optimization levels or instrumentation scopes don't match. -## 9) Gotchas, feedback, bugs +## 10) Gotchas, feedback, bugs If you need to fix up checksums or do other cleanup on mutated test cases, see examples/post_library/ for a viable solution. @@ -162,7 +176,7 @@ with -march=core2, can help. Beyond that, this is an early-stage mechanism, so fields reports are welcome. You can send them to . -## 10) Alternatives: static rewriting +## 11) Alternatives: static rewriting Statically rewriting binaries just once, instead of attempting to translate them at run time, can be a faster alternative. That said, static rewriting is @@ -176,4 +190,5 @@ The best implementation is this one: The issue however is Dyninst which is not rewriting the binaries so that they run stable. A lot of crashes happen, especially in C++ programs that use throw/catch. Try it first, and if it works for you be happy as it is -2-3x as fast as qemu_mode. +2-3x as fast as qemu_mode, however usually not as fast as QEMU persistent mode. + diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md index 6dba5a00..e2e372d8 100644 --- a/qemu_mode/README.persistent.md +++ b/qemu_mode/README.persistent.md @@ -7,7 +7,8 @@ addresses - without forking for every fuzzing attempt. This increases the speed by a factor between x2 and x5, hence it is very, very valuable. -The persistent mode is currently only available for x86/x86_64 targets. +The persistent mode is currently only available for x86/x86_64, arm +and aarch64 targets. ## 2) How use the persistent mode -- cgit 1.4.1 From e2ef2428986f45add509a6402de76678ca75b5da Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Feb 2020 09:43:33 +0100 Subject: fuzzer_stat eps is now overall not current, clang-format fixed to v8 --- .custom-format.py | 32 ++++---- docs/Changelog.md | 2 + docs/status_screen.md | 2 +- libdislocator/libdislocator.so.c | 3 +- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 50 ++++++------ src/afl-fuzz-stats.c | 103 +++++++++++++------------ src/afl-showmap.c | 9 +-- 7 files changed, 104 insertions(+), 97 deletions(-) (limited to 'qemu_mode') diff --git a/.custom-format.py b/.custom-format.py index f493a2d9..e3779b68 100755 --- a/.custom-format.py +++ b/.custom-format.py @@ -29,27 +29,29 @@ CLANG_FORMAT_BIN = os.getenv("CLANG_FORMAT_BIN") if CLANG_FORMAT_BIN is None: o = 0 try: - p = subprocess.Popen(["clang-format", "--version"], stdout=subprocess.PIPE) + p = subprocess.Popen(["clang-format-8", "--version"], stdout=subprocess.PIPE) o, _ = p.communicate() o = str(o, "utf-8") o = o[len("clang-format version "):].strip() o = o[:o.find(".")] o = int(o) - except: pass - if o < 7: - if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0: - CLANG_FORMAT_BIN = 'clang-format-7' - elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0: - CLANG_FORMAT_BIN = 'clang-format-8' - elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0: - CLANG_FORMAT_BIN = 'clang-format-9' - elif subprocess.call(['which', 'clang-format-10'], stdout=subprocess.PIPE) == 0: - CLANG_FORMAT_BIN = 'clang-format-10' - else: - print ("clang-format 7 or above is needed. Aborted.") - exit(1) + except: + print ("clang-format-8 is needed. Aborted.") + exit(1) + #if o < 7: + # if subprocess.call(['which', 'clang-format-7'], stdout=subprocess.PIPE) == 0: + # CLANG_FORMAT_BIN = 'clang-format-7' + # elif subprocess.call(['which', 'clang-format-8'], stdout=subprocess.PIPE) == 0: + # CLANG_FORMAT_BIN = 'clang-format-8' + # elif subprocess.call(['which', 'clang-format-9'], stdout=subprocess.PIPE) == 0: + # CLANG_FORMAT_BIN = 'clang-format-9' + # elif subprocess.call(['which', 'clang-format-10'], stdout=subprocess.PIPE) == 0: + # CLANG_FORMAT_BIN = 'clang-format-10' + # else: + # print ("clang-format 7 or above is needed. Aborted.") + # exit(1) else: - CLANG_FORMAT_BIN = 'clang-format' + CLANG_FORMAT_BIN = 'clang-format-8' COLUMN_LIMIT = 80 for line in fmt.split("\n"): diff --git a/docs/Changelog.md b/docs/Changelog.md index 8b56603f..751b051a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -19,6 +19,8 @@ sending a mail to . - CmpLog forkserver - Redqueen input-2-state mutator (cmp instructions only ATM) - all Python 2+3 versions supported now + - changed execs_per_sec in fuzzer_stats from "current" execs per second + (which is pointless) to total execs per second - afl-clang-fast: - show in the help output for which llvm version it was compiled for - now does not need to be recompiled between trace-pc and pass diff --git a/docs/status_screen.md b/docs/status_screen.md index 1ea98415..066c2c07 100644 --- a/docs/status_screen.md +++ b/docs/status_screen.md @@ -377,7 +377,7 @@ directory. This includes: - `fuzzer_pid` - PID of the fuzzer process - `cycles_done` - queue cycles completed so far - `execs_done` - number of execve() calls attempted - - `execs_per_sec` - current number of execs per second + - `execs_per_sec` - overall number of execs per second - `paths_total` - total number of entries in the queue - `paths_found` - number of entries discovered through local fuzzing - `paths_imported` - number of entries imported from other instances diff --git a/libdislocator/libdislocator.so.c b/libdislocator/libdislocator.so.c index bb767495..a0795c87 100644 --- a/libdislocator/libdislocator.so.c +++ b/libdislocator/libdislocator.so.c @@ -68,7 +68,8 @@ #include "config.h" #include "types.h" -#if __STDC_VERSION__ < 201112L || (defined(__FreeBSD__) && __FreeBSD_version < 1200000) +#if __STDC_VERSION__ < 201112L || \ + (defined(__FreeBSD__) && __FreeBSD_version < 1200000) // use this hack if not C11 typedef struct { diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index 2b9472b8..6f526d92 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -67,7 +67,7 @@ static void afl_compcov_log_64(target_ulong cur_loc, target_ulong arg1, target_ulong arg2) { register uintptr_t idx = cur_loc; - + if ((arg1 & 0xff00000000000000) == (arg2 & 0xff00000000000000)) { INC_AFL_AREA(idx + 6); @@ -299,7 +299,6 @@ static void gpr_saving(TCGv *cpu_regs, int regs_num) { } - static void restore_state_for_persistent(TCGv *cpu_regs, int regs_num, int sp) { if (persistent_save_gpr) { @@ -349,29 +348,29 @@ static void restore_state_for_persistent(TCGv *cpu_regs, int regs_num, int sp) { // SP = 13, LINK = 14 -#define AFL_QEMU_TARGET_ARM_SNIPPET \ - if (is_persistent) { \ - \ - if (dc->pc == afl_persistent_addr) { \ - \ - if (persistent_save_gpr) gpr_saving(cpu_R, AFL_REGS_NUM); \ - \ - if (afl_persistent_ret_addr == 0) { \ - \ - TCGv_ptr paddr = tcg_const_ptr(afl_persistent_addr); \ - tcg_gen_mov_i32(cpu_R[14], paddr); \ - tcg_temp_free_ptr(paddr); \ - \ - } \ - \ - if (!persistent_save_gpr) tcg_gen_afl_call0(&afl_persistent_loop); \ - \ - } else if (afl_persistent_ret_addr && dc->pc == afl_persistent_ret_addr) {\ - \ - gen_bx_im(dc, afl_persistent_addr); \ - \ - } \ - \ +#define AFL_QEMU_TARGET_ARM_SNIPPET \ + if (is_persistent) { \ + \ + if (dc->pc == afl_persistent_addr) { \ + \ + if (persistent_save_gpr) gpr_saving(cpu_R, AFL_REGS_NUM); \ + \ + if (afl_persistent_ret_addr == 0) { \ + \ + TCGv_ptr paddr = tcg_const_ptr(afl_persistent_addr); \ + tcg_gen_mov_i32(cpu_R[14], paddr); \ + tcg_temp_free_ptr(paddr); \ + \ + } \ + \ + if (!persistent_save_gpr) tcg_gen_afl_call0(&afl_persistent_loop); \ + \ + } else if (afl_persistent_ret_addr && dc->pc == afl_persistent_ret_addr) { \ + \ + gen_bx_im(dc, afl_persistent_addr); \ + \ + } \ + \ } // SP = 31, LINK = 30 @@ -400,3 +399,4 @@ static void restore_state_for_persistent(TCGv *cpu_regs, int regs_num, int sp) { } \ \ } + diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d09b4fe6..344e0abf 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -65,59 +65,62 @@ void write_stats_file(double bitmap_cvg, double stability, double eps) { if (getrusage(RUSAGE_CHILDREN, &rus)) rus.ru_maxrss = 0; - fprintf(f, - "start_time : %llu\n" - "last_update : %llu\n" - "fuzzer_pid : %d\n" - "cycles_done : %llu\n" - "execs_done : %llu\n" - "execs_per_sec : %0.02f\n" - "paths_total : %u\n" - "paths_favored : %u\n" - "paths_found : %u\n" - "paths_imported : %u\n" - "max_depth : %u\n" - "cur_path : %u\n" /* Must match find_start_position() */ - "pending_favs : %u\n" - "pending_total : %u\n" - "variable_paths : %u\n" - "stability : %0.02f%%\n" - "bitmap_cvg : %0.02f%%\n" - "unique_crashes : %llu\n" - "unique_hangs : %llu\n" - "last_path : %llu\n" - "last_crash : %llu\n" - "last_hang : %llu\n" - "execs_since_crash : %llu\n" - "exec_timeout : %u\n" - "slowest_exec_ms : %llu\n" - "peak_rss_mb : %lu\n" - "afl_banner : %s\n" - "afl_version : " VERSION - "\n" - "target_mode : %s%s%s%s%s%s%s%s\n" - "command_line : %s\n", - start_time / 1000, get_cur_time() / 1000, getpid(), - queue_cycle ? (queue_cycle - 1) : 0, total_execs, eps, queued_paths, - queued_favored, queued_discovered, queued_imported, max_depth, - current_entry, pending_favored, pending_not_fuzzed, queued_variable, - stability, bitmap_cvg, unique_crashes, unique_hangs, - last_path_time / 1000, last_crash_time / 1000, last_hang_time / 1000, - total_execs - last_crash_execs, exec_tmout, slowest_exec_ms, + fprintf( + f, + "start_time : %llu\n" + "last_update : %llu\n" + "fuzzer_pid : %d\n" + "cycles_done : %llu\n" + "execs_done : %llu\n" + "execs_per_sec : %0.02f\n" + // "real_execs_per_sec: %0.02f\n" // damn the name is too long + "paths_total : %u\n" + "paths_favored : %u\n" + "paths_found : %u\n" + "paths_imported : %u\n" + "max_depth : %u\n" + "cur_path : %u\n" /* Must match find_start_position() */ + "pending_favs : %u\n" + "pending_total : %u\n" + "variable_paths : %u\n" + "stability : %0.02f%%\n" + "bitmap_cvg : %0.02f%%\n" + "unique_crashes : %llu\n" + "unique_hangs : %llu\n" + "last_path : %llu\n" + "last_crash : %llu\n" + "last_hang : %llu\n" + "execs_since_crash : %llu\n" + "exec_timeout : %u\n" + "slowest_exec_ms : %llu\n" + "peak_rss_mb : %lu\n" + "afl_banner : %s\n" + "afl_version : " VERSION + "\n" + "target_mode : %s%s%s%s%s%s%s%s\n" + "command_line : %s\n", + start_time / 1000, get_cur_time() / 1000, getpid(), + queue_cycle ? (queue_cycle - 1) : 0, total_execs, + /*eps,*/ total_execs / ((double)(get_cur_time() - start_time) / 1000), + queued_paths, queued_favored, queued_discovered, queued_imported, + max_depth, current_entry, pending_favored, pending_not_fuzzed, + queued_variable, stability, bitmap_cvg, unique_crashes, unique_hangs, + last_path_time / 1000, last_crash_time / 1000, last_hang_time / 1000, + total_execs - last_crash_execs, exec_tmout, slowest_exec_ms, #ifdef __APPLE__ - (unsigned long int)(rus.ru_maxrss >> 20), + (unsigned long int)(rus.ru_maxrss >> 20), #else - (unsigned long int)(rus.ru_maxrss >> 10), + (unsigned long int)(rus.ru_maxrss >> 10), #endif - use_banner, unicorn_mode ? "unicorn" : "", qemu_mode ? "qemu " : "", - dumb_mode ? " dumb " : "", no_forkserver ? "no_forksrv " : "", - crash_mode ? "crash " : "", persistent_mode ? "persistent " : "", - deferred_mode ? "deferred " : "", - (unicorn_mode || qemu_mode || dumb_mode || no_forkserver || - crash_mode || persistent_mode || deferred_mode) - ? "" - : "default", - orig_cmdline); + use_banner, unicorn_mode ? "unicorn" : "", qemu_mode ? "qemu " : "", + dumb_mode ? " dumb " : "", no_forkserver ? "no_forksrv " : "", + crash_mode ? "crash " : "", persistent_mode ? "persistent " : "", + deferred_mode ? "deferred " : "", + (unicorn_mode || qemu_mode || dumb_mode || no_forkserver || crash_mode || + persistent_mode || deferred_mode) + ? "" + : "default", + orig_cmdline); /* ignore errors */ fclose(f); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 1686a750..1fd425a2 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -926,7 +926,7 @@ int main(int argc, char** argv) { int done = 0; u8 infile[4096], outfile[4096]; #if !defined(DT_REG) - struct stat statbuf; + struct stat statbuf; #endif dev_null_fd = open("/dev/null", O_RDWR); @@ -974,15 +974,14 @@ int main(int argc, char** argv) { if (dir_ent->d_name[0] == '.') continue; // skip anything that starts with '.' -#if defined(DT_REG) /* Posix and Solaris do not know d_type and DT_REG */ +#if defined(DT_REG) /* Posix and Solaris do not know d_type and DT_REG */ if (dir_ent->d_type != DT_REG) continue; // only regular files #endif snprintf(infile, sizeof(infile), "%s/%s", in_dir, dir_ent->d_name); -#if !defined(DT_REG) /* use stat() */ - if (-1 == stat(infile, &statbuf) - || !S_ISREG(statbuf.st_mode)) continue; +#if !defined(DT_REG) /* use stat() */ + if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue; #endif snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name); -- cgit 1.4.1 From d84cd978d452fc8ab723aadd30e3db9e33bd7709 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Sun, 9 Feb 2020 11:27:49 +0100 Subject: persistent readme --- qemu_mode/README.persistent.md | 87 +++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 31 deletions(-) (limited to 'qemu_mode') diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md index e2e372d8..e4ac5cee 100644 --- a/qemu_mode/README.persistent.md +++ b/qemu_mode/README.persistent.md @@ -10,67 +10,86 @@ very, very valuable. The persistent mode is currently only available for x86/x86_64, arm and aarch64 targets. - ## 2) How use the persistent mode ### 2.1) The START address -The start of the persistent mode has to be set with AFL_QEMU_PERSISTENT_ADDR. +The start of the persistent loop has to be set with AFL_QEMU_PERSISTENT_ADDR. -This address must be at the start of a function or the starting address of -basic block. This (as well as the RET address, see below) has to be defined -in hexadecimal with the 0x prefix. +This address can be the address of whatever instruction but the way in which +you setup persistent mode change if it is the starting instruction of a +function (suggested). This (as well as the RET address, see below) has to be +defined in hexadecimal with the 0x prefix or as a decimal value. If the target is compiled with position independant code (PIE/PIC), you must add 0x4000000000 to that address, because qemu loads to this base address. +On strange setups the base address set by QEMU for PIE executable may change, +you can check it printing the process map using AFL_QEMU_DEBUG_MAPS=1. If this address is not valid, afl-fuzz will error during startup with the message that the forkserver was not found. - ### 2.2) the RET address -The RET address is optional, and only needed if the the return should not be +The RET address is the last instruction of the persistent loop. +The emulator will emit a jump to START when translating the instruction at RET. +It is optional, and only needed if the the return should not be at the end of the function to which the START address points into, but earlier. +It is not set, QEMU will assume that START points to a function and will patch +the return address (on stack or in the link register) to return to START +(like WinAFL). + It is defined by setting AFL_QEMU_PERSISTENT_RET, and too 0x4000000000 has to be set if the target is position independant. - ### 2.3) the OFFSET +This option is for x86 only, arm doesn't save the return address on stack. + If the START address is *not* the beginning of a function, and *no* RET has -been set (so the end of the loop will be at the end of the function), the -ESP pointer very likely has to be reset correctly. +been set (so the end of the loop will be at the end of the function but START +will not be at the beginning), we need an offset from the ESP pointer to locate +the return address to patch. The value by which the ESP pointer has to be corrected has to set in the variable AFL_QEMU_PERSISTENT_RETADDR_OFFSET Now to get this value right here some help: 1. use gdb on the target -2. set a breakpoint to your START address -3. set a breakpoint to the end of the same function +2. set a breakpoint to the function in which START is contained +3. set a breakpoint to your START address 4. "run" the target with a valid commandline -5. at the first breakpoint print the ESP value with -``` -print $esp -``` +5. at the first breakpoint print the ESP value with `p $esp` and take not of it 6. "continue" the target until the second breakpoint 7. again print the ESP value 8. calculate the difference between the two values - and this is the offset - ### 2.4) resetting the register state -It is very, very likely you need to reste the register state when starting -a new loop. Because of this you 99% of the time should set +It is very, very likely you need to restore the general purpose registers state +when starting a new loop. Because of this you 99% of the time should set AFL_QEMU_PERSISTENT_GPR=1 +An example, is when you want to use main() as persistent START: -## 3) optional parameters +```c +int main(int argc, char **argv) { -### 3.1) loop counter value + if (argc < 2) return 1; + + // do stuffs + +} +``` + +If you don't save and restore the registers in x86_64, the paramteter argc +will be lost at the second execution of the loop. + +## 3) Optional parameters + +### 3.1) Loop counter value The more stable your loop in the target, the longer you can run it, the more unstable it is the lower the loop count should be. A low value would be 100, @@ -79,22 +98,28 @@ This value can be set with AFL_QEMU_PERSISTENT_CNT This is the same concept as in the llvm_mode persistent mode with __AFL_LOOP(). - -### 3.2) a hook for in-memory fuzzing +### 3.2) A hook for in-memory fuzzing You can increase the speed of the persistent mode even more by bypassing all the reading of the fuzzing input via a file by reading directly into the memory address space of the target process. -All this needs is that the START address has a register pointing to the -memory buffer, and another register holding the value of the read length -(or pointing to the memory where that value is held). +All this needs is that the START address has a register that can reach the +memory buffer or that the memory buffer is at a know location. You probably need +the value of the size of the buffer (maybe it is in a register when START is +hitted). + +The persistent hook will execute a function on every persistent iteration +(at the start START) defined in a shared object specified with +AFL_QEMU_PERSISTENT_HOOK=/path/to/hook.so. -If the target reads from an input file you have to supply an input file -that is of least of the size that your fuzzing input will be (and do not -supply @@). +The signature is: + +```c +void afl_persistent_hook(uint64_t* regs, uint64_t guest_base); +``` + +In this hook, you can inspect and change the saved GPR state at START. An example that you can use with little modification for your target can be found here: [examples/qemu_persistent_hook](../examples/qemu_persistent_hook) -This shared library is specified via AFL_QEMU_PERSISTENT_HOOK - -- cgit 1.4.1 From a86f740995ffe7c2a456390403d1c78df42d9dcd Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Sun, 9 Feb 2020 11:31:34 +0100 Subject: typo --- qemu_mode/README.persistent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qemu_mode') diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md index e4ac5cee..6948c316 100644 --- a/qemu_mode/README.persistent.md +++ b/qemu_mode/README.persistent.md @@ -60,7 +60,7 @@ Now to get this value right here some help: 2. set a breakpoint to the function in which START is contained 3. set a breakpoint to your START address 4. "run" the target with a valid commandline -5. at the first breakpoint print the ESP value with `p $esp` and take not of it +5. at the first breakpoint print the ESP value with `p $esp` and take note of it 6. "continue" the target until the second breakpoint 7. again print the ESP value 8. calculate the difference between the two values - and this is the offset -- cgit 1.4.1 From 34a9419b8990fe36da3148c006f6278b20205e94 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 9 Feb 2020 12:22:39 +0100 Subject: readme fixes --- PATCHES | 1 - qemu_mode/README.persistent.md | 40 +++++++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 18 deletions(-) delete mode 120000 PATCHES (limited to 'qemu_mode') diff --git a/PATCHES b/PATCHES deleted file mode 120000 index b34f8c1d..00000000 --- a/PATCHES +++ /dev/null @@ -1 +0,0 @@ -docs/PATCHES \ No newline at end of file diff --git a/qemu_mode/README.persistent.md b/qemu_mode/README.persistent.md index 6948c316..c96a451b 100644 --- a/qemu_mode/README.persistent.md +++ b/qemu_mode/README.persistent.md @@ -2,7 +2,7 @@ ## 1) Introduction -Persistent mode let you fuzz your target persistently between to +Persistent mode let you fuzz your target persistently between two addresses - without forking for every fuzzing attempt. This increases the speed by a factor between x2 and x5, hence it is very, very valuable. @@ -16,10 +16,12 @@ and aarch64 targets. The start of the persistent loop has to be set with AFL_QEMU_PERSISTENT_ADDR. -This address can be the address of whatever instruction but the way in which -you setup persistent mode change if it is the starting instruction of a -function (suggested). This (as well as the RET address, see below) has to be -defined in hexadecimal with the 0x prefix or as a decimal value. +This address can be the address of whatever instruction. +Setting this address to the start of a function makes the usage simple. +If the address is however within a function, either RET or OFFSET (see below +in 2.2 and 2.3) have to be set. +This address (as well as the RET address, see below) has to be defined in +hexadecimal with the 0x prefix or as a decimal value. If the target is compiled with position independant code (PIE/PIC), you must add 0x4000000000 to that address, because qemu loads to this base address. @@ -36,8 +38,8 @@ The emulator will emit a jump to START when translating the instruction at RET. It is optional, and only needed if the the return should not be at the end of the function to which the START address points into, but earlier. -It is not set, QEMU will assume that START points to a function and will patch -the return address (on stack or in the link register) to return to START +If it is not set, QEMU will assume that START points to a function and will +patch the return address (on stack or in the link register) to return to START (like WinAFL). It is defined by setting AFL_QEMU_PERSISTENT_RET, and too 0x4000000000 has to @@ -45,25 +47,29 @@ be set if the target is position independant. ### 2.3) the OFFSET -This option is for x86 only, arm doesn't save the return address on stack. +This option is valid only for x86/x86_64 only, arm/aarch64 do not save the +return address on stack. If the START address is *not* the beginning of a function, and *no* RET has been set (so the end of the loop will be at the end of the function but START -will not be at the beginning), we need an offset from the ESP pointer to locate -the return address to patch. +will not be at the beginning of it), we need an offset from the ESP pointer +to locate the return address to patch. The value by which the ESP pointer has to be corrected has to set in the variable AFL_QEMU_PERSISTENT_RETADDR_OFFSET Now to get this value right here some help: 1. use gdb on the target -2. set a breakpoint to the function in which START is contained -3. set a breakpoint to your START address -4. "run" the target with a valid commandline -5. at the first breakpoint print the ESP value with `p $esp` and take note of it -6. "continue" the target until the second breakpoint -7. again print the ESP value -8. calculate the difference between the two values - and this is the offset +2. set a breakpoint to "main" (this is required for PIE/PIC binaries so the + addresses are set up) +3. "run" the target with a valid commandline +4. set a breakpoint to the function in which START is contained +5. set a breakpoint to your START address +6. "continue" to the function start breakpoint +6. print the ESP value with `print $esp` and take note of it +7. "continue" the target until the second breakpoint +8. again print the ESP value +9. calculate the difference between the two values - and this is the offset ### 2.4) resetting the register state -- cgit 1.4.1