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 ++++++++++++++++++++++ 3 files changed, 96 insertions(+) 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 (limited to 'examples/qemu_persistent_hook') 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); + +} -- 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 'examples/qemu_persistent_hook') 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 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 'examples/qemu_persistent_hook') 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