From d6beac5235118b251deb18a6579aab85271eaa7b Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 29 Jul 2019 16:09:28 +0200 Subject: compcov levels to enable the instrumentation of only immediates --- qemu_mode/libcompcov/README.compcov | 8 +++- qemu_mode/libcompcov/libcompcov.so.c | 54 +++++++++++++++++++++++--- qemu_mode/patches/afl-qemu-cpu-inl.h | 9 ++++- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 9 +++-- qemu_mode/patches/i386-translate.diff | 6 +-- 5 files changed, 71 insertions(+), 15 deletions(-) diff --git a/qemu_mode/libcompcov/README.compcov b/qemu_mode/libcompcov/README.compcov index 2a4a0ee5..9be13d88 100644 --- a/qemu_mode/libcompcov/README.compcov +++ b/qemu_mode/libcompcov/README.compcov @@ -18,15 +18,19 @@ For optimized binaries this is an issue, those functions are often inlined and this module is not capable to log the coverage in this case. If you have the source code of the fuzzing target you should nto use this -library and QEMU but build ot with afl-clang-fast and the laf-intel options. +library and QEMU but build it with afl-clang-fast and the laf-intel options. To use this library make sure to preload it with AFL_PRELOAD. export AFL_PRELOAD=/path/to/libcompcov.so - export AFL_QEMU_COMPCOV=1 + export AFL_COMPCOV_LEVEL=1 afl-fuzz -Q -i input -o output -- +The AFL_COMPCOV_LEVEL tells to QEMU and libcompcov how to log comaprisons. +Level 1 logs just comparison with immediates / read-only memory and level 2 +logs all the comparisons. + The library make use of https://github.com/ouadev/proc_maps_parser and so it is Linux specific. However this is not a strict dependency, other UNIX operating systems can be supported simply replacing the code related to the diff --git a/qemu_mode/libcompcov/libcompcov.so.c b/qemu_mode/libcompcov/libcompcov.so.c index 582230db..92e4dbaa 100644 --- a/qemu_mode/libcompcov/libcompcov.so.c +++ b/qemu_mode/libcompcov/libcompcov.so.c @@ -45,6 +45,8 @@ static void *__compcov_code_start, static u8 *__compcov_afl_map; +static u32 __compcov_level; + static int (*__libc_strcmp)(const char*, const char*); static int (*__libc_strncmp)(const char*, const char*, size_t); static int (*__libc_strcasecmp)(const char*, const char*); @@ -54,6 +56,28 @@ static int (*__libc_memcmp)(const void*, const void*, size_t); static int debug_fd = -1; +#define MAX_MAPPINGS 1024 + +static struct mapping { + void *st, *en; +} __compcov_ro[MAX_MAPPINGS]; + +static u32 __compcov_ro_cnt; + + +/* Check an address against the list of read-only mappings. */ + +static u8 __compcov_is_ro(const void* ptr) { + + u32 i; + + for (i = 0; i < __compcov_ro_cnt; i++) + if (ptr >= __compcov_ro[i].st && ptr <= __compcov_ro[i].en) return 1; + + return 0; +} + + static size_t __strlen2(const char *s1, const char *s2, size_t max_length) { // from https://github.com/googleprojectzero/CompareCoverage @@ -71,6 +95,15 @@ static void __compcov_load(void) { __libc_strcasecmp = dlsym(RTLD_NEXT, "strcasecmp"); __libc_strncasecmp = dlsym(RTLD_NEXT, "strncasecmp"); __libc_memcmp = dlsym(RTLD_NEXT, "memcmp"); + + if (getenv("AFL_QEMU_COMPCOV")) { + + __compcov_level = 1; + } + if (getenv("AFL_COMPCOV_LEVEL")) { + + __compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL")); + } char *id_str = getenv(SHM_ENV_VAR); int shm_id; @@ -110,6 +143,12 @@ static void __compcov_load(void) { __compcov_code_end = maps_tmp->addr_end; } } + + if ((maps_tmp->is_w && !maps_tmp->is_r) || __compcov_ro_cnt == MAX_MAPPINGS) + continue; + + __compcov_ro[__compcov_ro_cnt].st = maps_tmp->addr_start; + __compcov_ro[__compcov_ro_cnt].en = maps_tmp->addr_end; } pmparser_free(maps); @@ -149,7 +188,8 @@ int strcmp(const char* str1, const char* str2) { void* retaddr = __builtin_return_address(0); - if (__compcov_is_in_bound(retaddr)) { + if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 && + !__compcov_is_ro(str1) && !__compcov_is_ro(str2))) { size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1); @@ -173,7 +213,8 @@ int strncmp(const char* str1, const char* str2, size_t len) { void* retaddr = __builtin_return_address(0); - if (__compcov_is_in_bound(retaddr)) { + if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 && + !__compcov_is_ro(str1) && !__compcov_is_ro(str2))) { size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1); n = MIN(n, len); @@ -198,7 +239,8 @@ int strcasecmp(const char* str1, const char* str2) { void* retaddr = __builtin_return_address(0); - if (__compcov_is_in_bound(retaddr)) { + if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 && + !__compcov_is_ro(str1) && !__compcov_is_ro(str2))) { /* Fallback to strcmp, maybe improve in future */ size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1); @@ -223,7 +265,8 @@ int strncasecmp(const char* str1, const char* str2, size_t len) { void* retaddr = __builtin_return_address(0); - if (__compcov_is_in_bound(retaddr)) { + if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 && + !__compcov_is_ro(str1) && !__compcov_is_ro(str2))) { /* Fallback to strncmp, maybe improve in future */ size_t n = __strlen2(str1, str2, MAX_CMP_LENGTH +1); @@ -249,7 +292,8 @@ int memcmp(const void* mem1, const void* mem2, size_t len) { void* retaddr = __builtin_return_address(0); - if (__compcov_is_in_bound(retaddr)) { + if (__compcov_is_in_bound(retaddr) && !(__compcov_level < 2 && + !__compcov_is_ro(mem1) && !__compcov_is_ro(mem2))) { size_t n = len; diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 03951fea..b769f62e 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -66,7 +66,7 @@ abi_ulong afl_entry_point, /* ELF entry point (_start) */ afl_start_code, /* .text start pointer */ afl_end_code; /* .text end pointer */ -u8 afl_enable_compcov; +u8 afl_compcov_level; /* Set in the child process in forkserver mode: */ @@ -159,9 +159,14 @@ static void afl_setup(void) { } + /* Maintain for compatibility */ if (getenv("AFL_QEMU_COMPCOV")) { - afl_enable_compcov = 1; + afl_compcov_level = 1; + } + if (getenv("AFL_COMPCOV_LEVEL")) { + + afl_compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL")); } /* pthread_atfork() seems somewhat broken in util/rcu.c, and I'm diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index 0ca89c98..4716c2ac 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -40,7 +40,7 @@ extern unsigned char *afl_area_ptr; extern unsigned int afl_inst_rms; extern abi_ulong afl_start_code, afl_end_code; -extern u8 afl_enable_compcov; +extern u8 afl_compcov_level; void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2); @@ -95,11 +95,14 @@ static void afl_compcov_log_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) { + TCGMemOp ot, int is_imm) { void *func; - if (!afl_enable_compcov || cur_loc > afl_end_code || cur_loc < afl_start_code) + if (!afl_compcov_level || cur_loc > afl_end_code || cur_loc < afl_start_code) + return; + + if (!is_imm && afl_compcov_level < 2) return; switch (ot) { diff --git a/qemu_mode/patches/i386-translate.diff b/qemu_mode/patches/i386-translate.diff index 0bc48828..239b2404 100644 --- a/qemu_mode/patches/i386-translate.diff +++ b/qemu_mode/patches/i386-translate.diff @@ -15,11 +15,11 @@ index 0dd5fbe4..b95d341e 100644 tcg_gen_atomic_fetch_add_tl(s1->cc_srcT, s1->A0, s1->T0, s1->mem_index, ot | MO_LE); tcg_gen_sub_tl(s1->T0, s1->cc_srcT, s1->T1); -+ afl_gen_compcov(s1->pc, s1->cc_srcT, s1->T1, ot); ++ afl_gen_compcov(s1->pc, s1->cc_srcT, s1->T1, ot, d == OR_EAX); } else { tcg_gen_mov_tl(s1->cc_srcT, s1->T0); tcg_gen_sub_tl(s1->T0, s1->T0, s1->T1); -+ afl_gen_compcov(s1->pc, s1->T0, s1->T1, ot); ++ afl_gen_compcov(s1->pc, s1->T0, s1->T1, ot, d == OR_EAX); gen_op_st_rm_T0_A0(s1, ot, d); } gen_op_update2_cc(s1); @@ -27,7 +27,7 @@ index 0dd5fbe4..b95d341e 100644 tcg_gen_mov_tl(cpu_cc_src, s1->T1); tcg_gen_mov_tl(s1->cc_srcT, s1->T0); tcg_gen_sub_tl(cpu_cc_dst, s1->T0, s1->T1); -+ afl_gen_compcov(s1->pc, s1->T0, s1->T1, ot); ++ afl_gen_compcov(s1->pc, s1->T0, s1->T1, ot, d == OR_EAX); set_cc_op(s1, CC_OP_SUBB + ot); break; } -- cgit 1.4.1 From 8b6a4e575978fac83155efd90d39030c84b2a755 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 30 Jul 2019 07:25:56 +0000 Subject: For BSD/APPLE platform use native random calls Solution not involving file descriptors, seeded upon fork and on a regular basis. Signed-off-by: Tobias Kortkamp --- afl-fuzz.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/afl-fuzz.c b/afl-fuzz.c index a1388a55..9397d5be 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -62,6 +62,7 @@ #if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) # include +# define HAVE_ARC4RANDOM 1 #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ /* For systems that have sched_setaffinity; right now just Linux, but one @@ -219,7 +220,9 @@ EXP_ST u8 skip_deterministic, /* Skip deterministic stages? */ fast_cal; /* Try to calibrate faster? */ static s32 out_fd, /* Persistent fd for out_file */ +#ifndef HAVE_ARC4RANDOM dev_urandom_fd = -1, /* Persistent fd for /dev/urandom */ +#endif dev_null_fd = -1, /* Persistent fd for /dev/null */ fsrv_ctl_fd, /* Fork server control pipe (write) */ fsrv_st_fd; /* Fork server status pipe (read) */ @@ -297,7 +300,9 @@ static u8 stage_val_type; /* Value type (STAGE_VAL_*) */ static u64 stage_finds[32], /* Patterns found per fuzz stage */ stage_cycles[32]; /* Execs per fuzz stage */ +#ifndef HAVE_ARC4RANDOM static u32 rand_cnt; /* Random number counter */ +#endif static u64 total_cal_us, /* Total calibration time (us) */ total_cal_cycles; /* Total calibration cycles */ @@ -641,14 +646,8 @@ static void trim_py(char** ret, size_t* retlen) { int select_algorithm(void) { int i_puppet, j_puppet; - u32 seed[2]; - - if (!fixed_seed) { - ck_read(dev_urandom_fd, &seed, sizeof(seed), "/dev/urandom"); - srandom(seed[0]); - } - double sele = ((double)(random()%10000)*0.0001); + double sele = ((double)(UR(10000))*0.0001); j_puppet = 0; for (i_puppet = 0; i_puppet < operator_num; i_puppet++) { if (unlikely(i_puppet == 0)) { @@ -699,7 +698,15 @@ static u64 get_cur_time_us(void) { have slight bias. */ static inline u32 UR(u32 limit) { +#ifdef HAVE_ARC4RANDOM + if (fixed_seed) { + return random() % limit; + } + /* The boundary not being necessarily a power of 2, + we need to ensure the result uniformity. */ + return arc4random_uniform(limit); +#else if (!fixed_seed && unlikely(!rand_cnt--)) { u32 seed[2]; @@ -709,6 +716,7 @@ static inline u32 UR(u32 limit) { } return random() % limit; +#endif } @@ -2407,7 +2415,9 @@ EXP_ST void init_forkserver(char** argv) { close(out_dir_fd); close(dev_null_fd); +#ifndef HAVE_ARC4RANDOM close(dev_urandom_fd); +#endif close(fileno(plot_file)); /* This should improve performance a bit, since it stops the linker from @@ -2681,7 +2691,9 @@ static u8 run_target(char** argv, u32 timeout) { close(dev_null_fd); close(out_dir_fd); +#ifndef HAVE_ARC4RANDOM close(dev_urandom_fd); +#endif close(fileno(plot_file)); /* Set sane defaults for ASAN if nothing else specified. */ @@ -11466,8 +11478,10 @@ EXP_ST void setup_dirs_fds(void) { dev_null_fd = open("/dev/null", O_RDWR); if (dev_null_fd < 0) PFATAL("Unable to open /dev/null"); +#ifndef HAVE_ARC4RANDOM dev_urandom_fd = open("/dev/urandom", O_RDONLY); if (dev_urandom_fd < 0) PFATAL("Unable to open /dev/urandom"); +#endif /* Gnuplot output file. */ -- cgit 1.4.1 From 96c76a8333d39b06096e4cbb668a52ffa5575e9a Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Wed, 14 Aug 2019 22:41:39 +0200 Subject: more sed compatibility for Freebsd, avoid grouping --- llvm_mode/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile index fc7a6fd9..160a8fe6 100644 --- a/llvm_mode/Makefile +++ b/llvm_mode/Makefile @@ -75,7 +75,7 @@ endif # sanity check. # Are versions of clang --version and llvm-config --version equal? -CLANGVER = $(shell $(CC) --version | sed -E -ne '1{/^.*([0-9]\.[0-9]\.[0-9]).*/s//\1/p}') +CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*version\ ([0-9]\.[0-9]\.[0-9]).*/s//\1/p') ifeq "$(shell echo '\#include @\#include @int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 )" "1" -- cgit 1.4.1 From 2053731ebc9a4c881f52c1de51fab51f79bcf980 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 17 Aug 2019 12:07:22 +0200 Subject: update readme and todo --- README.md | 4 ++++ TODO | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index dff6463b..9ff7c24b 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,10 @@ afl++ is maintained by Marc Heuse , Heiko Eißfeldt and Andrea Fioraldi . + Note that although afl now has a Google afl repository [https://github.com/Google/afl](https://github.com/Google/afl), + it is unlikely to receive any noteable enhancements: [https://twitter.com/Dor3s/status/1154737061787660288](https://twitter.com/Dor3s/status/1154737061787660288) + + ## The enhancements compared to the original stock afl Many improvements were made over the official afl release - which did not diff --git a/TODO b/TODO index 42987cb9..692f6609 100644 --- a/TODO +++ b/TODO @@ -10,7 +10,6 @@ afl-fuzz: gcc_plugin: - needs to be rewritten - - fix crashes when compiling :( - whitelist support - skip over uninteresting blocks - laf-intel @@ -29,7 +28,8 @@ Problem: Average targets (tiff, jpeg, unrar) go through 1500 edges. At afl's default map that means ~16 collisions and ~3 wrappings. Solution #1: increase map size. every +1 decreases fuzzing speed by ~10% and halfs the collisions - birthday paradox predicts at collisions at this # of edges: + birthday paradox predicts collisions at this # of edges: + mapsize => collisions 2^16 = 302 2^17 = 427 2^18 = 603 @@ -39,10 +39,10 @@ Problem: Average targets (tiff, jpeg, unrar) go through 1500 edges. 2^22 = 2412 2^23 = 3411 2^24 = 4823 - Its an easy solution but also not a good one. + Increasing the map is an easy solution but also not a good one. Solution #2: use dynamic map size and collision free basic block IDs This only works in llvm_mode and llvm >= 9 though - A potential good future solution + A potential good future solution. Heiko/hexcoder follows this up Solution #3: write instruction pointers to a big shared map 512kb/1MB shared map and the instrumented code writes the instruction pointer into the map. Map must be big enough but could be command line @@ -51,7 +51,7 @@ Problem: Average targets (tiff, jpeg, unrar) go through 1500 edges. impacts speed, but this can be decided by user options Neutral: a little bit slower but no loss of coverage Bad: completely changes how afl uses the map and the scheduling. - Overall another very good solution + Overall another very good solution, Marc Heuse/vanHauser follows this up qemu_mode: - persistent mode patching the return address (WinAFL style) -- cgit 1.4.1 From dd734a01dc65e2a5dc5ae7498658743e70b14f6a Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 18 Aug 2019 09:40:33 +0100 Subject: system-config: making it more compatible with BSD systems. The following knobs are Linux specifics but have few counterparts in those systems. --- afl-system-config | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/afl-system-config b/afl-system-config index 366762ef..28793c5b 100755 --- a/afl-system-config +++ b/afl-system-config @@ -1,9 +1,11 @@ #!/bin/sh +PLATFORM=`uname -s` echo This reconfigures the system to have a better fuzzing performance if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then echo Error you need to be root to run this exit 1 fi +if [ "$PLATFORM" = "Linux" ] ; then sysctl -w kernel.core_pattern=core sysctl -w kernel.randomize_va_space=0 sysctl -w kernel.sched_child_runs_first=1 @@ -19,5 +21,19 @@ test -e /sys/devices/system/cpu/cpufreq/boost && echo 1 > /sys/devices/system/cp echo echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this: echo '/etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off spectre_v2=off stf_barrier=off"' +fi +if [ "$PLATFORM" = "FreeBSD" ] ; then +sysctl kern.elf32.aslr.enable=0 +sysctl kern.elf64.aslr.enable=0 +echo +echo It is recommended to boot the kernel with lots of security off - if you are running a machine that is in a secured network - so set this: +echo 'sysctl hw.ibrs_disable=1' +echo +echo 'Setting kern.pmap.pg_ps_enabled=0 into /boot/loader.conf might be helpful too.' +fi +if [ "$PLATFORM" = "OpenBSD" ] ; then +echo +echo 'System security features cannot be disabled on OpenBSD.' +fi echo echo Also use AFL_TMPDIR to use a tmpfs for the input file -- cgit 1.4.1 From 742aed4f2e8d46cd9a92c4eafb89986049bedfe4 Mon Sep 17 00:00:00 2001 From: Joey Jiao Date: Thu, 25 Jul 2019 09:12:48 +0800 Subject: Add support for Android --- afl-analyze.c | 3 ++ afl-fuzz.c | 8 +++-- afl-gotcpu.c | 3 ++ afl-showmap.c | 3 ++ afl-tmin.c | 3 ++ afl-whatsup | 2 +- android-ashmem.h | 81 +++++++++++++++++++++++++++++++++++++++++++ llvm_mode/afl-llvm-pass.so.cc | 5 +++ llvm_mode/afl-llvm-rt.o.c | 7 ++++ sharedmem.c | 3 ++ 10 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 android-ashmem.h diff --git a/afl-analyze.c b/afl-analyze.c index 53b694ec..0e8c9fb0 100644 --- a/afl-analyze.c +++ b/afl-analyze.c @@ -21,6 +21,9 @@ #define AFL_MAIN +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif #include "config.h" #include "types.h" #include "debug.h" diff --git a/afl-fuzz.c b/afl-fuzz.c index e9fb8bf0..0e252bea 100644 --- a/afl-fuzz.c +++ b/afl-fuzz.c @@ -28,6 +28,9 @@ #endif #define _FILE_OFFSET_BITS 64 +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif #include "config.h" #include "types.h" #include "debug.h" @@ -11318,6 +11321,7 @@ static void check_term_size(void) { if (ioctl(1, TIOCGWINSZ, &ws)) return; + if (ws.ws_row == 0 || ws.ws_col == 0) return; if (ws.ws_row < 24 || ws.ws_col < 79) term_too_small = 1; } @@ -12370,8 +12374,8 @@ int main(int argc, char** argv) { if (unicorn_mode) FATAL("-U and -n are mutually exclusive"); } - - if (index(argv[optind], '/') == NULL) WARNF(cLRD "Target binary called without a prefixed path, make sure you are fuzzing the right binary: " cRST "%s", argv[optind]); + + if (strchr(argv[optind], '/') == NULL) WARNF(cLRD "Target binary called without a prefixed path, make sure you are fuzzing the right binary: " cRST "%s", argv[optind]); OKF("afl++ is maintained by Marc \"van Hauser\" Heuse, Heiko \"hexcoder\" Eissfeldt and Andrea Fioraldi"); OKF("afl++ is open source, get it at https://github.com/vanhauser-thc/AFLplusplus"); diff --git a/afl-gotcpu.c b/afl-gotcpu.c index 4163ad65..8c04b205 100644 --- a/afl-gotcpu.c +++ b/afl-gotcpu.c @@ -28,6 +28,9 @@ #define AFL_MAIN #define _GNU_SOURCE +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif #include #include #include diff --git a/afl-showmap.c b/afl-showmap.c index bce7cb4e..a490bca6 100644 --- a/afl-showmap.c +++ b/afl-showmap.c @@ -23,6 +23,9 @@ #define AFL_MAIN +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif #include "config.h" #include "types.h" #include "debug.h" diff --git a/afl-tmin.c b/afl-tmin.c index 94f3bb3f..a36acd10 100644 --- a/afl-tmin.c +++ b/afl-tmin.c @@ -21,6 +21,9 @@ #define AFL_MAIN +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif #include "config.h" #include "types.h" #include "debug.h" diff --git a/afl-whatsup b/afl-whatsup index a4d30418..c1e41529 100755 --- a/afl-whatsup +++ b/afl-whatsup @@ -54,7 +54,7 @@ fi CUR_TIME=`date +%s` -TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || exit 1 +TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || exit 1 ALIVE_CNT=0 DEAD_CNT=0 diff --git a/android-ashmem.h b/android-ashmem.h new file mode 100644 index 00000000..a787c04b --- /dev/null +++ b/android-ashmem.h @@ -0,0 +1,81 @@ +#ifndef _ANDROID_ASHMEM_H +#define _ANDROID_ASHMEM_H + +#include +#include +#include +#include +#include + +#if __ANDROID_API__ >= 26 +#define shmat bionic_shmat +#define shmctl bionic_shmctl +#define shmdt bionic_shmdt +#define shmget bionic_shmget +#endif + #include +#undef shmat +#undef shmctl +#undef shmdt +#undef shmget +#include + +#define ASHMEM_DEVICE "/dev/ashmem" + +static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) +{ + int ret = 0; + if (__cmd == IPC_RMID) { + int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + struct ashmem_pin pin = {0, length}; + ret = ioctl(__shmid, ASHMEM_UNPIN, &pin); + close(__shmid); + } + + return ret; +} + +static inline int shmget (key_t __key, size_t __size, int __shmflg) +{ + int fd,ret; + char ourkey[11]; + + fd = open(ASHMEM_DEVICE, O_RDWR); + if (fd < 0) + return fd; + + sprintf(ourkey,"%d",__key); + ret = ioctl(fd, ASHMEM_SET_NAME, ourkey); + if (ret < 0) + goto error; + + ret = ioctl(fd, ASHMEM_SET_SIZE, __size); + if (ret < 0) + goto error; + + return fd; + +error: + close(fd); + return ret; +} + +static inline void *shmat (int __shmid, const void *__shmaddr, int __shmflg) +{ + int size; + void *ptr; + + size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL); + if (size < 0) { + return NULL; + } + + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0); + if (ptr == MAP_FAILED) { + return NULL; + } + + return ptr; +} + +#endif diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index cfeff968..bdad835f 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -129,9 +129,14 @@ bool AFLCoverage::runOnModule(Module &M) { new GlobalVariable(M, PointerType::get(Int8Ty, 0), false, GlobalValue::ExternalLinkage, 0, "__afl_area_ptr"); +#ifdef __ANDROID__ + GlobalVariable *AFLPrevLoc = new GlobalVariable( + M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc"); +#else GlobalVariable *AFLPrevLoc = new GlobalVariable( M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); +#endif /* Instrument all the things! */ diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index debde204..67208454 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -19,6 +19,9 @@ */ +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif #include "../config.h" #include "../types.h" @@ -55,7 +58,11 @@ u8 __afl_area_initial[MAP_SIZE]; u8* __afl_area_ptr = __afl_area_initial; +#ifdef __ANDROID__ +u32 __afl_prev_loc; +#else __thread u32 __afl_prev_loc; +#endif /* Running in persistent mode? */ diff --git a/sharedmem.c b/sharedmem.c index 3fd38444..ce3b76e6 100644 --- a/sharedmem.c +++ b/sharedmem.c @@ -4,6 +4,9 @@ #define AFL_MAIN +#ifdef __ANDROID__ + #include "android-ashmem.h" +#endif #include "config.h" #include "types.h" #include "debug.h" -- cgit 1.4.1 From a51d4227b6c1a6fec2a471aa9497b6d8201411ae Mon Sep 17 00:00:00 2001 From: Joey Jiao Date: Mon, 19 Aug 2019 09:31:50 +0800 Subject: Symlink Makefile to Android.mk --- Android.mk | 1 + 1 file changed, 1 insertion(+) create mode 120000 Android.mk diff --git a/Android.mk b/Android.mk new file mode 120000 index 00000000..33ceb8f0 --- /dev/null +++ b/Android.mk @@ -0,0 +1 @@ +Makefile \ No newline at end of file -- cgit 1.4.1 From cc55e5c6d8ead610606649fa5aad39671f55bece Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 21 Aug 2019 09:36:31 +0200 Subject: remove compcov immediates only instrumentation from TODO --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index 692f6609..89e307cf 100644 --- a/TODO +++ b/TODO @@ -55,5 +55,3 @@ Problem: Average targets (tiff, jpeg, unrar) go through 1500 edges. qemu_mode: - persistent mode patching the return address (WinAFL style) - - instrument only comparison with immediate values by default when using compcov - -- cgit 1.4.1 From b1ebd62c78e81bcd0731782f102276e4af459cea Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 21 Aug 2019 09:57:26 +0200 Subject: update env_variables.txt with compcov levels --- docs/env_variables.txt | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/env_variables.txt b/docs/env_variables.txt index 93066dbc..821463ae 100644 --- a/docs/env_variables.txt +++ b/docs/env_variables.txt @@ -245,9 +245,19 @@ The QEMU wrapper used to instrument binary-only code supports several settings: - Setting AFL_INST_LIBS causes the translator to also instrument the code inside any dynamically linked libraries (notably including glibc). + - Setting AFL_COMPCOV_LEVEL enables the CompareCoverage tracing of all cmp + and sub in x86 and x86_64 and memory comparions functions (e.g. strcmp, + memcmp, ...) when libcompcov is preloaded using AFL_PRELOAD. + More info at qemu_mode/libcompcov/README.compcov. + There are two levels at the moment, AFL_COMPCOV_LEVEL=1 that instruments + only comparisons with immediate values / read-only memory and + AFL_COMPCOV_LEVEL=2 that instruments all the comparions. Level 2 is more + accurate but may need a larger shared memory. + - Setting AFL_QEMU_COMPCOV enables the CompareCoverage tracing of all - cmp and sub in x86 and x86_64. Support for other architectures and - comparison functions (mem/strcmp et al.) is planned. + cmp and sub in x86 and x86_64. + This is an alias of AFL_COMPCOV_LEVEL=1 when AFL_COMPCOV_LEVEL is + not specified. - The underlying QEMU binary will recognize any standard "user space emulation" variables (e.g., QEMU_STACK_SIZE), but there should be no @@ -260,10 +270,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings: - AFL_ENTRYPOINT allows you to specify a specific entrypoint into the binary (this can be very good for the performance!). The entrypoint is specified as hex address, e.g. 0x4004110 - - - AFL_QEMU_COMPCOV is for a sub-project in qemu_mode called ./libcompcov - which implements laf-intel for qemu. It also needs AFL_PRELOAD and - you can find more information in qemu_mode/libcompcov/README.compcov + Note that the address must be the address of a basic block. 5) Settings for afl-cmin ------------------------ -- cgit 1.4.1 From 790d717543ae415ee30224644dd45fa408bba0c5 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 21 Aug 2019 10:09:46 +0200 Subject: update README.qemu with compcov levels --- qemu_mode/README.qemu | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/qemu_mode/README.qemu b/qemu_mode/README.qemu index 754c0259..cd8559ad 100644 --- a/qemu_mode/README.qemu +++ b/qemu_mode/README.qemu @@ -16,14 +16,16 @@ with afl-gcc. The usual performance cost is 2-5x, which is considerably better than seen so far in experiments with tools such as DynamoRIO and PIN. -The idea and much of the implementation comes from Andrew Griffiths. +The idea and much of the initial implementation comes from Andrew Griffiths. +The actual implementation on QEMU 3 (shipped with afl++) is from +Andrea Fioraldi. Special thanks to abiondo that re-enabled TCG chaining. 2) How to use ------------- -The feature is implemented with a fairly simple patch to QEMU 2.10.0. The -simplest way to build it is to run ./build_qemu_support.sh. The script will -download, configure, and compile the QEMU binary for you. +The feature is implemented with a patch to QEMU 3.1.0. The simplest way +to build it is to run ./build_qemu_support.sh. The script will download, +configure, and compile the QEMU binary for you. QEMU is a big project, so this will take a while, and you may have to resolve a couple of dependencies (most notably, you will definitely need @@ -53,10 +55,18 @@ There is ./libcompcov/ which implements laf-intel (splitting memcmp, strncmp, etc. to make these conditions easier solvable by afl-fuzz). Highly recommended. +The option that enables QEMU CompareCoverage is QEMU_COMPCOV_LEVEL. +QEMU_COMPCOV_LEVEL=1 is to instrument comparisons with only immediate +values / read-only memory. QEMU_COMPCOV_LEVEL=2 instruments all +comparison instructions and memory comparison functions when libcompcov +is preloaded. Comparison instructions are currently instrumented only +on the x86 and x86_64 targets. + Another option is the environment variable AFL_ENTRYPOINT which allows move the forkserver to a different part, e.g. just before the file is opened (e.g. way after command line parsing and config file loading, etc) -which can be a huge speed improvement. +which can be a huge speed improvement. Note that the specified address +must be an address of a basic block. 4) Notes on linking ------------------- -- cgit 1.4.1 From e72d4a96bf50b9ae66b95203159f89e1adf2644a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 26 Aug 2019 02:51:14 +0200 Subject: Make install script executable --- unicorn_mode/build_unicorn_support.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 unicorn_mode/build_unicorn_support.sh diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh old mode 100644 new mode 100755 -- cgit 1.4.1 From b6f5e1635cbdcc3031c4af18ef3a877d2d7db77f Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 27 Aug 2019 14:02:48 +0200 Subject: added afl++ patches authors to special thanks --- README.md | 8 +++++--- qemu_mode/patches/afl-qemu-cpu-inl.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9ff7c24b..76bd98c8 100644 --- a/README.md +++ b/README.md @@ -559,8 +559,8 @@ Beyond this, see INSTALL for platform-specific tips. ## 15) Special thanks ------------------ -Many of the improvements to the original afl wouldn't be possible without -feedback, bug reports, or patches from: +Many of the improvements to the original afl and afl++ wouldn't be possible +without feedback, bug reports, or patches from: ``` Jann Horn Hanno Boeck @@ -602,7 +602,9 @@ feedback, bug reports, or patches from: Rene Freingruber Sergey Davidoff Sami Liedes Craig Young Andrzej Jackowski Daniel Hodson - Nathan Voss Dominik Maier + Nathan Voss Dominik Maier + Andrea Biondo Vincent Le Garrec + Khaled Yakdan Kuang-che Wu ``` Thank you! diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index d7bb4d25..04d9007d 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -332,7 +332,7 @@ static void afl_wait_tsl(CPUState *cpu, int fd) { if (is_valid_addr(t.tb.pc)) { mmap_lock(); - tb = tb_gen_code(cpu, t.tb.pc, t.tb.cs_base, t.tb.flags, 0); + tb = tb_gen_code(cpu, t.tb.pc, t.tb.cs_base, t.tb.flags, t.tb.cf_mask); mmap_unlock(); } else { -- cgit 1.4.1 From 7338568125f4a3831079550294275ef18b603ab2 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 27 Aug 2019 15:17:43 +0200 Subject: removed sepration lines from README --- README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/README.md b/README.md index 76bd98c8..2bd31a54 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,6 @@ ## 1) Challenges of guided fuzzing -------------------------------- Fuzzing is one of the most powerful and proven strategies for identifying security issues in real-world software; it is responsible for the vast @@ -177,7 +176,6 @@ file for important caveats. ## 4) Instrumenting binary-only apps ---------------------------------- When source code is *NOT* available, the fuzzer offers experimental support for fast, on-the-fly instrumentation of black-box binaries. This is accomplished @@ -205,7 +203,6 @@ A more comprehensive description of these and other options can be found in ## 5) Power schedules ------------------- The power schedules were copied from Marcel Böhme's excellent AFLfast implementation and expands on the ability to discover new paths and @@ -237,7 +234,6 @@ Computer and Communications Security (CCS'16): ## 6) Choosing initial test cases ------------------------------- To operate correctly, the fuzzer requires one or more starting file that contains a good example of the input data normally expected by the targeted @@ -259,7 +255,6 @@ exercise different code paths in the target binary. ## 7) Fuzzing binaries -------------------- The fuzzing process itself is carried out by the afl-fuzz utility. This program requires a read-only directory with initial test cases, a separate place to @@ -298,7 +293,6 @@ fuzzers - add the -d option to the command line. ## 8) Interpreting output ----------------------- See the [docs/status_screen.txt](docs/status_screen.txt) file for information on how to interpret the displayed stats and monitor the health of the process. Be @@ -360,7 +354,6 @@ see [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/) ## 9) Parallelized fuzzing ------------------------ Every instance of afl-fuzz takes up roughly one core. This means that on multi-core systems, parallelization is necessary to fully utilize the hardware. @@ -373,7 +366,6 @@ last section of [docs/parallel_fuzzing.txt](docs/parallel_fuzzing.txt) for tips. ## 10) Fuzzer dictionaries ----------------------- By default, afl-fuzz mutation engine is optimized for compact data formats - say, images, multimedia, compressed data, regular expression syntax, or shell @@ -410,7 +402,6 @@ utility with AFL. For that, see [libtokencap/README.tokencap](libtokencap/README ## 11) Crash triage ----------------- The coverage-based grouping of crashes usually produces a small data set that can be quickly triaged manually or with a very simple GDB or Valgrind script. @@ -459,7 +450,6 @@ near the end of [docs/technical_details.txt](docs/technical_details.txt). ## 12) Going beyond crashes ------------------------- Fuzzing is a wonderful and underutilized technique for discovering non-crashing design and implementation errors, too. Quite a few interesting bugs have been @@ -484,7 +474,6 @@ shared with libfuzzer) or `#ifdef __AFL_COMPILER` (this one is just for AFL). ## 13) Common-sense risks ----------------------- Please keep in mind that, similarly to many other computationally-intensive tasks, fuzzing may put strain on your hardware and on the OS. In particular: @@ -515,7 +504,6 @@ tasks, fuzzing may put strain on your hardware and on the OS. In particular: ## 14) Known limitations & areas for improvement ---------------------------------------------- Here are some of the most important caveats for AFL: @@ -557,7 +545,6 @@ Beyond this, see INSTALL for platform-specific tips. ## 15) Special thanks ------------------- Many of the improvements to the original afl and afl++ wouldn't be possible without feedback, bug reports, or patches from: @@ -611,7 +598,6 @@ Thank you! ## 16) Contact ------------ Questions? Concerns? Bug reports? The contributors can be reached via [https://github.com/vanhauser-thc/AFLplusplus](https://github.com/vanhauser-thc/AFLplusplus) -- cgit 1.4.1 From 10df5ad0ac3dcff705f6932487fecbdaf690e1f0 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 27 Aug 2019 16:22:25 +0200 Subject: docu update --- README.md | 3 ++- TODO | 2 ++ docs/ChangeLog | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2bd31a54..14e1ae59 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,8 @@ Among others afl++ has, e.g. more performant llvm_mode, supporting llvm up to version 9, Qemu 3.1, more speed and crashfixes for Qemu, - laf-intel feature for Qemu (with libcompcov) and more. + laf-intel feature for Qemu (with libcompcov), better *BSD and Android + support and more. Additionally the following patches have been integrated: diff --git a/TODO b/TODO index 89e307cf..cb95f899 100644 --- a/TODO +++ b/TODO @@ -7,6 +7,8 @@ Roadmap 2.53d: afl-fuzz: - put mutator, scheduler, forkserver and input channels in individual files - reuse forkserver for showmap, afl-cmin, etc. + - custom mutator lib: example and readme + - env var to exclusively run the custom lib/py mutator gcc_plugin: - needs to be rewritten diff --git a/docs/ChangeLog b/docs/ChangeLog index dfebb68a..6d56d314 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -18,6 +18,7 @@ Version ++2.53d (dev): ---------------------- - llvm 9 is now supported (still needs testing) + - Android is now supported (thank to JoeyJiao!) - still need to modify the Makefile though - fix building qemu on some Ubuntus (thanks to floyd!) - custom mutator by a loaded library is now supported (thanks to kyakdan!) - fix for a few features to support different map sized than 2^16 -- cgit 1.4.1 From bec9b307db299b586c2574031d3cc1a491dc00c3 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 27 Aug 2019 20:57:52 +0200 Subject: neverzero qemu for x86/x86_64 --- config.h | 4 ++++ qemu_mode/patches/afl-qemu-translate-inl.h | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/config.h b/config.h index 37a2a794..29c33d46 100644 --- a/config.h +++ b/config.h @@ -339,6 +339,10 @@ #define CTEST_CORE_TRG_MS 1000 #define CTEST_BUSY_CYCLES (10 * 1000 * 1000) +/* Enable NeverZero counters in QEMU mode */ + +#define AFL_QEMU_NOT_ZERO + /* Uncomment this to use inferior block-coverage-based instrumentation. Note that you need to recompile the target binary for this to have any effect: */ diff --git a/qemu_mode/patches/afl-qemu-translate-inl.h b/qemu_mode/patches/afl-qemu-translate-inl.h index bfb2897e..9c3580e5 100644 --- a/qemu_mode/patches/afl-qemu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-translate-inl.h @@ -42,11 +42,25 @@ extern abi_ulong afl_start_code, afl_end_code; void tcg_gen_afl_maybe_log_call(target_ulong cur_loc); -void afl_maybe_log(target_ulong cur_loc) { +void afl_maybe_log(target_ulong cur_loc) { static __thread abi_ulong prev_loc; - afl_area_ptr[cur_loc ^ prev_loc]++; + register target_ulong afl_idx = cur_loc ^ prev_loc; + +#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) + asm volatile ( + "incb (%0, %1, 1)\n" + "seto %%al\n" + "addb %%al, (%0, %1, 1)\n" + : /* no out */ + : "r" (afl_area_ptr), "r" (afl_idx) + : "memory", "eax" + ); +#else + afl_area_ptr[afl_idx]++; +#endif + prev_loc = cur_loc >> 1; } -- cgit 1.4.1 From c5e0b29a22a126a90942fd31a85fcfe8486fa67c Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 27 Aug 2019 21:10:51 +0200 Subject: neverzero for unicorn_mode --- qemu_mode/patches/afl-qemu-translate-inl.h | 2 +- unicorn_mode/build_unicorn_support.sh | 2 +- unicorn_mode/patches/afl-unicorn-cpu-inl.h | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/qemu_mode/patches/afl-qemu-translate-inl.h b/qemu_mode/patches/afl-qemu-translate-inl.h index 9c3580e5..f82d1217 100644 --- a/qemu_mode/patches/afl-qemu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-translate-inl.h @@ -46,7 +46,7 @@ void afl_maybe_log(target_ulong cur_loc) { static __thread abi_ulong prev_loc; - register target_ulong afl_idx = cur_loc ^ prev_loc; + register uintptr_t afl_idx = cur_loc ^ prev_loc; #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) asm volatile ( diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh index 9dcf6773..3219e54c 100755 --- a/unicorn_mode/build_unicorn_support.sh +++ b/unicorn_mode/build_unicorn_support.sh @@ -144,7 +144,7 @@ echo "[+] Configuration complete." echo "[*] Attempting to build Unicorn (fingers crossed!)..." -UNICORN_QEMU_FLAGS='--python=python2' make || exit 1 +UNICORN_QEMU_FLAGS='--python=python2' make -j `nproc` || exit 1 echo "[+] Build process successful!" diff --git a/unicorn_mode/patches/afl-unicorn-cpu-inl.h b/unicorn_mode/patches/afl-unicorn-cpu-inl.h index 892c3f72..ed422725 100644 --- a/unicorn_mode/patches/afl-unicorn-cpu-inl.h +++ b/unicorn_mode/patches/afl-unicorn-cpu-inl.h @@ -241,7 +241,21 @@ static inline void afl_maybe_log(unsigned long cur_loc) { // DEBUG //printf("cur_loc = 0x%lx\n", cur_loc); - afl_area_ptr[cur_loc ^ prev_loc]++; + register uintptr_t afl_idx = cur_loc ^ prev_loc; + +#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) + asm volatile ( + "incb (%0, %1, 1)\n" + "seto %%al\n" + "addb %%al, (%0, %1, 1)\n" + : /* no out */ + : "r" (afl_area_ptr), "r" (afl_idx) + : "memory", "eax" + ); +#else + afl_area_ptr[afl_idx]++; +#endif + prev_loc = cur_loc >> 1; } -- cgit 1.4.1 From 80f175daac0e2dac12aad908abb19316e85552c8 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 28 Aug 2019 13:45:37 +0200 Subject: unicorn compcov for x86 --- .gitignore | 1 + unicorn_mode/build_unicorn_support.sh | 7 +- unicorn_mode/patches/afl-unicorn-cpu-inl.h | 52 ++++--- .../patches/afl-unicorn-cpu-translate-inl.h | 62 ++++++++ unicorn_mode/patches/afl-unicorn-tcg-op-inl.h | 56 +++++++ unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h | 88 +++++++++++ unicorn_mode/patches/compcov.diff | 113 ++++++++++++++ unicorn_mode/samples/compcov_x64/COMPILE.md | 20 +++ .../samples/compcov_x64/compcov_target.bin | Bin 0 -> 86 bytes unicorn_mode/samples/compcov_x64/compcov_target.c | 28 ++++ .../samples/compcov_x64/compcov_target.elf | Bin 0 -> 5728 bytes .../samples/compcov_x64/compcov_test_harness.py | 170 +++++++++++++++++++++ .../samples/compcov_x64/sample_inputs/sample1.bin | 1 + 13 files changed, 572 insertions(+), 26 deletions(-) create mode 100644 unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h create mode 100644 unicorn_mode/patches/afl-unicorn-tcg-op-inl.h create mode 100644 unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h create mode 100644 unicorn_mode/patches/compcov.diff create mode 100644 unicorn_mode/samples/compcov_x64/COMPILE.md create mode 100644 unicorn_mode/samples/compcov_x64/compcov_target.bin create mode 100644 unicorn_mode/samples/compcov_x64/compcov_target.c create mode 100755 unicorn_mode/samples/compcov_x64/compcov_target.elf create mode 100644 unicorn_mode/samples/compcov_x64/compcov_test_harness.py create mode 100644 unicorn_mode/samples/compcov_x64/sample_inputs/sample1.bin diff --git a/.gitignore b/.gitignore index bb3c82eb..2ee40f62 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ qemu_mode/qemu-3.1.0 qemu_mode/qemu-3.1.0.tar.xz unicorn_mode/unicorn unicorn_mode/unicorn-* +unicorn_mode/*.tar.gz diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh index 3219e54c..2c0fe4b1 100755 --- a/unicorn_mode/build_unicorn_support.sh +++ b/unicorn_mode/build_unicorn_support.sh @@ -127,12 +127,13 @@ tar xzf "$ARCHIVE" -C ./unicorn --strip-components=1 || exit 1 echo "[+] Unpacking successful." -rm -rf "$ARCHIVE" || exit 1 +#rm -rf "$ARCHIVE" || exit 1 echo "[*] Applying patches..." -cp patches/afl-unicorn-cpu-inl.h unicorn || exit 1 -patch -p1 --directory unicorn uc); \ afl_forkserver(env); \ afl_first_instr = 1; \ } \ - afl_maybe_log(tb->pc); \ + afl_maybe_log(env->uc, tb->pc); \ } while (0) /* We use one additional file descriptor to relay "needs translation" @@ -66,24 +66,16 @@ #define TSL_FD (FORKSRV_FD - 1) -/* This is equivalent to afl-as.h: */ - -static unsigned char *afl_area_ptr; - /* Set in the child process in forkserver mode: */ static unsigned char afl_fork_child; static unsigned int afl_forksrv_pid; -/* Instrumentation ratio: */ - -static unsigned int afl_inst_rms = MAP_SIZE; - /* Function declarations. */ -static void afl_setup(void); +static void afl_setup(struct uc_struct* uc); static void afl_forkserver(CPUArchState*); -static inline void afl_maybe_log(unsigned long); +static inline void afl_maybe_log(struct uc_struct* uc, unsigned long); static void afl_wait_tsl(CPUArchState*, int); static void afl_request_tsl(target_ulong, target_ulong, uint64_t); @@ -105,7 +97,7 @@ struct afl_tsl { /* Set up SHM region and initialize other stuff. */ -static void afl_setup(void) { +static void afl_setup(struct uc_struct* uc) { char *id_str = getenv(SHM_ENV_VAR), *inst_r = getenv("AFL_INST_RATIO"); @@ -121,21 +113,35 @@ static void afl_setup(void) { if (r > 100) r = 100; if (!r) r = 1; - afl_inst_rms = MAP_SIZE * r / 100; + uc->afl_inst_rms = MAP_SIZE * r / 100; + } else { + + uc->afl_inst_rms = MAP_SIZE; + } if (id_str) { shm_id = atoi(id_str); - afl_area_ptr = shmat(shm_id, NULL, 0); + uc->afl_area_ptr = shmat(shm_id, NULL, 0); - if (afl_area_ptr == (void*)-1) exit(1); + if (uc->afl_area_ptr == (void*)-1) exit(1); /* With AFL_INST_RATIO set to a low value, we want to touch the bitmap so that the parent doesn't give up on us. */ - if (inst_r) afl_area_ptr[0] = 1; + if (inst_r) uc->afl_area_ptr[0] = 1; + } + + /* Maintain for compatibility */ + if (getenv("AFL_QEMU_COMPCOV")) { + + uc->afl_compcov_level = 1; + } + if (getenv("AFL_COMPCOV_LEVEL")) { + + uc->afl_compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL")); } } @@ -145,7 +151,7 @@ static void afl_forkserver(CPUArchState *env) { static unsigned char tmp[4]; - if (!afl_area_ptr) return; + if (!env->uc->afl_area_ptr) return; /* Tell the parent that we're alive. If the parent doesn't want to talk, assume that we're not running in forkserver mode. */ @@ -208,7 +214,7 @@ static void afl_forkserver(CPUArchState *env) { /* The equivalent of the tuple logging routine from afl-as.h. */ -static inline void afl_maybe_log(unsigned long cur_loc) { +static inline void afl_maybe_log(struct uc_struct* uc, unsigned long cur_loc) { static __thread unsigned long prev_loc; @@ -217,7 +223,7 @@ static inline void afl_maybe_log(unsigned long cur_loc) { // MODIFIED FOR UNICORN MODE -> We want to log all addresses, // so the checks for 'start < addr < end' are removed - if(!afl_area_ptr) + if(!uc->afl_area_ptr) return; // DEBUG @@ -236,7 +242,7 @@ static inline void afl_maybe_log(unsigned long cur_loc) { // DEBUG //printf("afl_inst_rms = 0x%lx\n", afl_inst_rms); - if (cur_loc >= afl_inst_rms) return; + if (cur_loc >= uc->afl_inst_rms) return; // DEBUG //printf("cur_loc = 0x%lx\n", cur_loc); @@ -249,11 +255,11 @@ static inline void afl_maybe_log(unsigned long cur_loc) { "seto %%al\n" "addb %%al, (%0, %1, 1)\n" : /* no out */ - : "r" (afl_area_ptr), "r" (afl_idx) + : "r" (uc->afl_area_ptr), "r" (afl_idx) : "memory", "eax" ); #else - afl_area_ptr[afl_idx]++; + uc->afl_area_ptr[afl_idx]++; #endif prev_loc = cur_loc >> 1; diff --git a/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h b/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h new file mode 100644 index 00000000..9c7a14dc --- /dev/null +++ b/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h @@ -0,0 +1,62 @@ +/* + american fuzzy lop - high-performance binary-only instrumentation + ----------------------------------------------------------------- + + Written by Andrew Griffiths and + Michal Zalewski + + TCG instrumentation and block chaining support by Andrea Biondo + + Adapted for afl-unicorn by Dominik Maier + + Idea & design very much by Andrew Griffiths. + + Copyright 2015, 2016 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This code is a shim patched into the separately-distributed source + code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality + to implement AFL-style instrumentation and to take care of the remaining + parts of the AFL fork server logic. + + The resulting QEMU binary is essentially a standalone instrumentation + tool; for an example of how to leverage it for other purposes, you can + have a look at afl-showmap.c. + + */ + +#include "../../config.h" + +static void afl_gen_compcov(TCGContext *s, uint64_t cur_loc, TCGv_i64 arg1, + TCGv_i64 arg2, TCGMemOp ot, int is_imm) { + + if (!s->uc->afl_compcov_level || !s->uc->afl_area_ptr) + return; + + if (!is_imm && s->uc->afl_compcov_level < 2) + return; + + cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); + cur_loc &= MAP_SIZE - 1; + + if (cur_loc >= s->uc->afl_inst_rms) return; + + switch (ot) { + case MO_64: + gen_afl_compcov_log_64(s, cur_loc, arg1, arg2); + break; + case MO_32: + gen_afl_compcov_log_32(s, cur_loc, arg1, arg2); + break; + case MO_16: + gen_afl_compcov_log_16(s, cur_loc, arg1, arg2); + break; + default: + return; + } +} diff --git a/unicorn_mode/patches/afl-unicorn-tcg-op-inl.h b/unicorn_mode/patches/afl-unicorn-tcg-op-inl.h new file mode 100644 index 00000000..d5a29cce --- /dev/null +++ b/unicorn_mode/patches/afl-unicorn-tcg-op-inl.h @@ -0,0 +1,56 @@ +/* + american fuzzy lop - high-performance binary-only instrumentation + ----------------------------------------------------------------- + + Written by Andrew Griffiths and + Michal Zalewski + + TCG instrumentation and block chaining support by Andrea Biondo + + Adapted for afl-unicorn by Dominik Maier + + Idea & design very much by Andrew Griffiths. + + Copyright 2015, 2016 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This code is a shim patched into the separately-distributed source + code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality + to implement AFL-style instrumentation and to take care of the remaining + parts of the AFL fork server logic. + + The resulting QEMU binary is essentially a standalone instrumentation + tool; for an example of how to leverage it for other purposes, you can + have a look at afl-showmap.c. + + */ + +static inline void gen_afl_compcov_log_16(TCGContext *tcg_ctx, uint64_t cur_loc, + TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc); + TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc); + gen_helper_afl_compcov_log_16(tcg_ctx, tuc, tcur_loc, arg1, arg2); +} + +static inline void gen_afl_compcov_log_32(TCGContext *tcg_ctx, uint64_t cur_loc, + TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc); + TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc); + gen_helper_afl_compcov_log_32(tcg_ctx, tuc, tcur_loc, arg1, arg2); +} + +static inline void gen_afl_compcov_log_64(TCGContext *tcg_ctx, uint64_t cur_loc, + TCGv_i64 arg1, TCGv_i64 arg2) +{ + TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc); + TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc); + gen_helper_afl_compcov_log_64(tcg_ctx, tuc, tcur_loc, arg1, arg2); +} + diff --git a/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h new file mode 100644 index 00000000..9e56484b --- /dev/null +++ b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h @@ -0,0 +1,88 @@ +/* + american fuzzy lop - high-performance binary-only instrumentation + ----------------------------------------------------------------- + + Written by Andrew Griffiths and + Michal Zalewski + + TCG instrumentation and block chaining support by Andrea Biondo + + Adapted for afl-unicorn by Dominik Maier + + Idea & design very much by Andrew Griffiths. + + Copyright 2015, 2016 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This code is a shim patched into the separately-distributed source + code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality + to implement AFL-style instrumentation and to take care of the remaining + parts of the AFL fork server logic. + + The resulting QEMU binary is essentially a standalone instrumentation + tool; for an example of how to leverage it for other purposes, you can + have a look at afl-showmap.c. + + */ + +#include "uc_priv.h" + +void HELPER(afl_compcov_log_16)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, + uint64_t arg2) { + + struct uc_struct* uc = uc_ptr; + + if ((arg1 & 0xff) == (arg2 & 0xff)) { + uc->afl_area_ptr[cur_loc]++; + } +} + +void HELPER(afl_compcov_log_32)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, + uint64_t arg2) { + + struct uc_struct* uc = uc_ptr; + + if ((arg1 & 0xff) == (arg2 & 0xff)) { + uc->afl_area_ptr[cur_loc]++; + if ((arg1 & 0xffff) == (arg2 & 0xffff)) { + uc->afl_area_ptr[cur_loc +1]++; + if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { + uc->afl_area_ptr[cur_loc +2]++; + } + } + } +} + +void HELPER(afl_compcov_log_64)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, + uint64_t arg2) { + + struct uc_struct* uc = uc_ptr; + + if ((arg1 & 0xff) == (arg2 & 0xff)) { + uc->afl_area_ptr[cur_loc]++; + if ((arg1 & 0xffff) == (arg2 & 0xffff)) { + uc->afl_area_ptr[cur_loc +1]++; + if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { + uc->afl_area_ptr[cur_loc +2]++; + if ((arg1 & 0xffffffff) == (arg2 & 0xffffffff)) { + uc->afl_area_ptr[cur_loc +3]++; + if ((arg1 & 0xffffffffff) == (arg2 & 0xffffffffff)) { + uc->afl_area_ptr[cur_loc +4]++; + if ((arg1 & 0xffffffffffff) == (arg2 & 0xffffffffffff)) { + uc->afl_area_ptr[cur_loc +5]++; + if ((arg1 & 0xffffffffffffff) == (arg2 & 0xffffffffffffff)) { + uc->afl_area_ptr[cur_loc +6]++; + } + } + } + } + } + } + } +} + diff --git a/unicorn_mode/patches/compcov.diff b/unicorn_mode/patches/compcov.diff new file mode 100644 index 00000000..8ec867d1 --- /dev/null +++ b/unicorn_mode/patches/compcov.diff @@ -0,0 +1,113 @@ +diff --git a/include/uc_priv.h b/include/uc_priv.h +index 22f494e..1aa7b3a 100644 +--- a/include/uc_priv.h ++++ b/include/uc_priv.h +@@ -245,6 +245,12 @@ struct uc_struct { + uint32_t target_page_align; + uint64_t next_pc; // save next PC for some special cases + bool hook_insert; // insert new hook at begin of the hook list (append by default) ++ ++#ifdef UNICORN_AFL ++ unsigned char *afl_area_ptr; ++ int afl_compcov_level; ++ unsigned int afl_inst_rms; ++#endif + }; + + // Metadata stub for the variable-size cpu context used with uc_context_*() +diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c +index 36fae09..196d346 100644 +--- a/qemu/target-i386/translate.c ++++ b/qemu/target-i386/translate.c +@@ -33,6 +33,12 @@ + + #include "uc_priv.h" + ++#if defined(UNICORN_AFL) ++#include "../../afl-unicorn-cpu-translate-inl.h" ++#else ++#define afl_gen_compcov(a,b,c,d,e,f) do {} while (0) ++#endif ++ + #define PREFIX_REPZ 0x01 + #define PREFIX_REPNZ 0x02 + #define PREFIX_LOCK 0x04 +@@ -1555,6 +1561,7 @@ static void gen_op(DisasContext *s, int op, TCGMemOp ot, int d) + case OP_SUBL: + tcg_gen_mov_tl(tcg_ctx, cpu_cc_srcT, *cpu_T[0]); + tcg_gen_sub_tl(tcg_ctx, *cpu_T[0], *cpu_T[0], *cpu_T[1]); ++ afl_gen_compcov(tcg_ctx, s->pc, *cpu_T[0], *cpu_T[1], ot, d == OR_EAX); + gen_op_st_rm_T0_A0(s, ot, d); + gen_op_update2_cc(tcg_ctx); + set_cc_op(s, CC_OP_SUBB + ot); +@@ -1582,6 +1589,7 @@ static void gen_op(DisasContext *s, int op, TCGMemOp ot, int d) + tcg_gen_mov_tl(tcg_ctx, cpu_cc_src, *cpu_T[1]); + tcg_gen_mov_tl(tcg_ctx, cpu_cc_srcT, *cpu_T[0]); + tcg_gen_sub_tl(tcg_ctx, cpu_cc_dst, *cpu_T[0], *cpu_T[1]); ++ afl_gen_compcov(tcg_ctx, s->pc, *cpu_T[0], *cpu_T[1], ot, d == OR_EAX); + set_cc_op(s, CC_OP_SUBB + ot); + break; + } +diff --git a/qemu/tcg-runtime.c b/qemu/tcg-runtime.c +index 21b022a..14d7891 100644 +--- a/qemu/tcg-runtime.c ++++ b/qemu/tcg-runtime.c +@@ -31,9 +31,14 @@ + + #define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \ + dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2)); ++#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \ ++ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), dh_ctype(t4)); + + #include "tcg-runtime.h" + ++#ifdef UNICORN_AFL ++#include "../afl-unicorn-tcg-runtime-inl.h" ++#endif + + /* 32-bit helpers */ + +diff --git a/qemu/tcg/tcg-op.h b/qemu/tcg/tcg-op.h +index 38b7dd9..c5a9af9 100644 +--- a/qemu/tcg/tcg-op.h ++++ b/qemu/tcg/tcg-op.h +@@ -27,6 +27,10 @@ + + int gen_new_label(TCGContext *); + ++#ifdef UNICORN_AFL ++#include "../../afl-unicorn-tcg-op-inl.h" ++#endif ++ + static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, int32_t type, void *uc, uint64_t pc) + { + TCGv_i32 tsize = tcg_const_i32(tcg_ctx, size); +diff --git a/qemu/tcg/tcg-runtime.h b/qemu/tcg/tcg-runtime.h +index 23a0c37..90b993c 100644 +--- a/qemu/tcg/tcg-runtime.h ++++ b/qemu/tcg/tcg-runtime.h +@@ -14,3 +14,9 @@ DEF_HELPER_FLAGS_2(sar_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64) + + DEF_HELPER_FLAGS_2(mulsh_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64) + DEF_HELPER_FLAGS_2(muluh_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64) ++ ++#ifdef UNICORN_AFL ++DEF_HELPER_FLAGS_4(afl_compcov_log_16, 0, void, ptr, i64, i64, i64) ++DEF_HELPER_FLAGS_4(afl_compcov_log_32, 0, void, ptr, i64, i64, i64) ++DEF_HELPER_FLAGS_4(afl_compcov_log_64, 0, void, ptr, i64, i64, i64) ++#endif +diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h +index 8dcbb3e..11e18b4 100644 +--- a/qemu/unicorn_common.h ++++ b/qemu/unicorn_common.h +@@ -84,6 +84,10 @@ static inline void uc_common_init(struct uc_struct* uc) + + if (!uc->release) + uc->release = release_common; ++ ++#ifdef UNICORN_AFL ++ uc->afl_area_ptr = 0; ++#endif + } + + #endif diff --git a/unicorn_mode/samples/compcov_x64/COMPILE.md b/unicorn_mode/samples/compcov_x64/COMPILE.md new file mode 100644 index 00000000..db488d30 --- /dev/null +++ b/unicorn_mode/samples/compcov_x64/COMPILE.md @@ -0,0 +1,20 @@ +Compiling compcov_target.c +========================== + +compcov_target.c was compiled without optimization, position-independent, +and without standard libraries using the following command line: + +``` +gcc -o compcov_target.elf compcov_target.c -fPIC -O0 -nostdlib +``` + +The .text section from the resulting ELF binary was then extracted to create +the raw binary blob that is loaded and emulated by compcov_test_harness.py: + +``` +objcopy -O binary --only-section=.text compcov_target.elf compcov_target.bin +``` + +Note that the output of this is padded with nulls for 16-byte alignment. This is +important when emulating it, as NOPs will be added after the return of main() +as necessary. diff --git a/unicorn_mode/samples/compcov_x64/compcov_target.bin b/unicorn_mode/samples/compcov_x64/compcov_target.bin new file mode 100644 index 00000000..091bf1db Binary files /dev/null and b/unicorn_mode/samples/compcov_x64/compcov_target.bin differ diff --git a/unicorn_mode/samples/compcov_x64/compcov_target.c b/unicorn_mode/samples/compcov_x64/compcov_target.c new file mode 100644 index 00000000..71b4cb0e --- /dev/null +++ b/unicorn_mode/samples/compcov_x64/compcov_target.c @@ -0,0 +1,28 @@ +/* + * Sample target file to test afl-unicorn fuzzing capabilities. + * This is a very trivial example that will crash pretty easily + * in several different exciting ways. + * + * Input is assumed to come from a buffer located at DATA_ADDRESS + * (0x00300000), so make sure that your Unicorn emulation of this + * puts user data there. + * + * Written by Nathan Voss + */ + +// Magic address where mutated data will be placed +#define DATA_ADDRESS 0x00300000 + +int main(void) { + unsigned int *data_buf = (unsigned int *) DATA_ADDRESS; + + if (data_buf[0] == 0xabadcafe) { + // Cause an 'invalid read' crash if data[0..3] == '\x01\x02\x03\x04' + unsigned char invalid_read = *(unsigned char *) 0x00000000; + } else if (data_buf[1] == data_buf[2] + 0x4141) { + // Cause an 'invalid read' crash if (0x10 < data[0] < 0x20) and data[1] > data[2] + unsigned char invalid_read = *(unsigned char *) 0x00000000; + } + + return 0; +} diff --git a/unicorn_mode/samples/compcov_x64/compcov_target.elf b/unicorn_mode/samples/compcov_x64/compcov_target.elf new file mode 100755 index 00000000..7015fb46 Binary files /dev/null and b/unicorn_mode/samples/compcov_x64/compcov_target.elf differ diff --git a/unicorn_mode/samples/compcov_x64/compcov_test_harness.py b/unicorn_mode/samples/compcov_x64/compcov_test_harness.py new file mode 100644 index 00000000..5698cbc8 --- /dev/null +++ b/unicorn_mode/samples/compcov_x64/compcov_test_harness.py @@ -0,0 +1,170 @@ +""" + Simple test harness for AFL's Unicorn Mode. + + This loads the compcov_target.bin binary (precompiled as MIPS code) into + Unicorn's memory map for emulation, places the specified input into + compcov_target's buffer (hardcoded to be at 0x300000), and executes 'main()'. + If any crashes occur during emulation, this script throws a matching signal + to tell AFL that a crash occurred. + + Run under AFL as follows: + + $ cd /unicorn_mode/samples/simple/ + $ ../../../afl-fuzz -U -m none -i ./sample_inputs -o ./output -- python compcov_test_harness.py @@ +""" + +import argparse +import os +import signal + +from unicorn import * +from unicorn.x86_const import * + +# Path to the file containing the binary to emulate +BINARY_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'compcov_target.bin') + +# Memory map for the code to be tested +CODE_ADDRESS = 0x00100000 # Arbitrary address where code to test will be loaded +CODE_SIZE_MAX = 0x00010000 # Max size for the code (64kb) +STACK_ADDRESS = 0x00200000 # Address of the stack (arbitrarily chosen) +STACK_SIZE = 0x00010000 # Size of the stack (arbitrarily chosen) +DATA_ADDRESS = 0x00300000 # Address where mutated data will be placed +DATA_SIZE_MAX = 0x00010000 # Maximum allowable size of mutated data + +try: + # If Capstone is installed then we'll dump disassembly, otherwise just dump the binary. + from capstone import * + cs = Cs(CS_ARCH_X86, CS_MODE_64) + def unicorn_debug_instruction(uc, address, size, user_data): + mem = uc.mem_read(address, size) + for (cs_address, cs_size, cs_mnemonic, cs_opstr) in cs.disasm_lite(bytes(mem), size): + print(" Instr: {:#016x}:\t{}\t{}".format(address, cs_mnemonic, cs_opstr)) +except ImportError: + def unicorn_debug_instruction(uc, address, size, user_data): + print(" Instr: addr=0x{0:016x}, size=0x{1:016x}".format(address, size)) + +def unicorn_debug_block(uc, address, size, user_data): + print("Basic Block: addr=0x{0:016x}, size=0x{1:016x}".format(address, size)) + +def unicorn_debug_mem_access(uc, access, address, size, value, user_data): + if access == UC_MEM_WRITE: + print(" >>> Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(address, size, value)) + else: + print(" >>> Read: addr=0x{0:016x} size={1}".format(address, size)) + +def unicorn_debug_mem_invalid_access(uc, access, address, size, value, user_data): + if access == UC_MEM_WRITE_UNMAPPED: + print(" >>> INVALID Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(address, size, value)) + else: + print(" >>> INVALID Read: addr=0x{0:016x} size={1}".format(address, size)) + +def force_crash(uc_error): + # This function should be called to indicate to AFL that a crash occurred during emulation. + # Pass in the exception received from Uc.emu_start() + mem_errors = [ + UC_ERR_READ_UNMAPPED, UC_ERR_READ_PROT, UC_ERR_READ_UNALIGNED, + UC_ERR_WRITE_UNMAPPED, UC_ERR_WRITE_PROT, UC_ERR_WRITE_UNALIGNED, + UC_ERR_FETCH_UNMAPPED, UC_ERR_FETCH_PROT, UC_ERR_FETCH_UNALIGNED, + ] + if uc_error.errno in mem_errors: + # Memory error - throw SIGSEGV + os.kill(os.getpid(), signal.SIGSEGV) + elif uc_error.errno == UC_ERR_INSN_INVALID: + # Invalid instruction - throw SIGILL + os.kill(os.getpid(), signal.SIGILL) + else: + # Not sure what happened - throw SIGABRT + os.kill(os.getpid(), signal.SIGABRT) + +def main(): + + parser = argparse.ArgumentParser(description="Test harness for compcov_target.bin") + parser.add_argument('input_file', type=str, help="Path to the file containing the mutated input to load") + parser.add_argument('-d', '--debug', default=False, action="store_true", help="Enables debug tracing") + args = parser.parse_args() + + # Instantiate a MIPS32 big endian Unicorn Engine instance + uc = Uc(UC_ARCH_X86, UC_MODE_64) + + if args.debug: + uc.hook_add(UC_HOOK_BLOCK, unicorn_debug_block) + uc.hook_add(UC_HOOK_CODE, unicorn_debug_instruction) + uc.hook_add(UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, unicorn_debug_mem_access) + uc.hook_add(UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_READ_INVALID, unicorn_debug_mem_invalid_access) + + #--------------------------------------------------- + # Load the binary to emulate and map it into memory + + print("Loading data input from {}".format(args.input_file)) + binary_file = open(BINARY_FILE, 'rb') + binary_code = binary_file.read() + binary_file.close() + + # Apply constraints to the mutated input + if len(binary_code) > CODE_SIZE_MAX: + print("Binary code is too large (> {} bytes)".format(CODE_SIZE_MAX)) + return + + # Write the mutated command into the data buffer + uc.mem_map(CODE_ADDRESS, CODE_SIZE_MAX) + uc.mem_write(CODE_ADDRESS, binary_code) + + # Set the program counter to the start of the code + start_address = CODE_ADDRESS # Address of entry point of main() + end_address = CODE_ADDRESS + 0x55 # Address of last instruction in main() + uc.reg_write(UC_X86_REG_RIP, start_address) + + #----------------- + # Setup the stack + + uc.mem_map(STACK_ADDRESS, STACK_SIZE) + uc.reg_write(UC_X86_REG_RSP, STACK_ADDRESS + STACK_SIZE) + + #----------------------------------------------------- + # Emulate 1 instruction to kick off AFL's fork server + # THIS MUST BE DONE BEFORE LOADING USER DATA! + # If this isn't done every single run, the AFL fork server + # will not be started appropriately and you'll get erratic results! + # It doesn't matter what this returns with, it just has to execute at + # least one instruction in order to get the fork server started. + + # Execute 1 instruction just to startup the forkserver + print("Starting the AFL forkserver by executing 1 instruction") + try: + uc.emu_start(uc.reg_read(UC_X86_REG_RIP), 0, 0, count=1) + except UcError as e: + print("ERROR: Failed to execute a single instruction (error: {})!".format(e)) + return + + #----------------------------------------------- + # Load the mutated input and map it into memory + + # Load the mutated input from disk + print("Loading data input from {}".format(args.input_file)) + input_file = open(args.input_file, 'rb') + input = input_file.read() + input_file.close() + + # Apply constraints to the mutated input + if len(input) > DATA_SIZE_MAX: + print("Test input is too long (> {} bytes)".format(DATA_SIZE_MAX)) + return + + # Write the mutated command into the data buffer + uc.mem_map(DATA_ADDRESS, DATA_SIZE_MAX) + uc.mem_write(DATA_ADDRESS, input) + + #------------------------------------------------------------ + # Emulate the code, allowing it to process the mutated input + + print("Executing until a crash or execution reaches 0x{0:016x}".format(end_address)) + try: + result = uc.emu_start(uc.reg_read(UC_X86_REG_RIP), end_address, timeout=0, count=0) + except UcError as e: + print("Execution failed with error: {}".format(e)) + force_crash(e) + + print("Done.") + +if __name__ == "__main__": + main() diff --git a/unicorn_mode/samples/compcov_x64/sample_inputs/sample1.bin b/unicorn_mode/samples/compcov_x64/sample_inputs/sample1.bin new file mode 100644 index 00000000..445c7245 --- /dev/null +++ b/unicorn_mode/samples/compcov_x64/sample_inputs/sample1.bin @@ -0,0 +1 @@ +00000000000000000000000000000000 \ No newline at end of file -- cgit 1.4.1 From 733c8e4c349562fd02d0238be486ecbdf0640fd0 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 28 Aug 2019 18:42:21 +0200 Subject: better neverzero with adc + neverzero for compcov --- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 36 +++++++++++++++------- qemu_mode/patches/afl-qemu-translate-inl.h | 3 +- unicorn_mode/patches/afl-unicorn-cpu-inl.h | 3 +- unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h | 36 +++++++++++++++------- 4 files changed, 52 insertions(+), 26 deletions(-) diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index 4716c2ac..f85a86d7 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -45,11 +45,25 @@ extern u8 afl_compcov_level; void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2); +#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) +# define INC_AFL_AREA(loc) \ + asm volatile ( \ + "incb (%0, %1, 1)\n" \ + "adc $0, (%0, %1, 1)\n" \ + : /* no out */ \ + : "r" (afl_area_ptr), "r" (loc) \ + : "memory", "eax" \ + ) +#else +# define INC_AFL_AREA(loc) \ + afl_area_ptr[loc]++ +#endif + static void afl_compcov_log_16(target_ulong cur_loc, target_ulong arg1, target_ulong arg2) { if ((arg1 & 0xff) == (arg2 & 0xff)) { - afl_area_ptr[cur_loc]++; + INC_AFL_AREA(cur_loc); } } @@ -57,11 +71,11 @@ static void afl_compcov_log_32(target_ulong cur_loc, target_ulong arg1, target_ulong arg2) { if ((arg1 & 0xff) == (arg2 & 0xff)) { - afl_area_ptr[cur_loc]++; + INC_AFL_AREA(cur_loc); if ((arg1 & 0xffff) == (arg2 & 0xffff)) { - afl_area_ptr[cur_loc +1]++; + INC_AFL_AREA(cur_loc +1); if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { - afl_area_ptr[cur_loc +2]++; + INC_AFL_AREA(cur_loc +2); } } } @@ -71,19 +85,19 @@ static void afl_compcov_log_64(target_ulong cur_loc, target_ulong arg1, target_ulong arg2) { if ((arg1 & 0xff) == (arg2 & 0xff)) { - afl_area_ptr[cur_loc]++; + INC_AFL_AREA(cur_loc); if ((arg1 & 0xffff) == (arg2 & 0xffff)) { - afl_area_ptr[cur_loc +1]++; + INC_AFL_AREA(cur_loc +1); if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { - afl_area_ptr[cur_loc +2]++; + INC_AFL_AREA(cur_loc +2); if ((arg1 & 0xffffffff) == (arg2 & 0xffffffff)) { - afl_area_ptr[cur_loc +3]++; + INC_AFL_AREA(cur_loc +3); if ((arg1 & 0xffffffffff) == (arg2 & 0xffffffffff)) { - afl_area_ptr[cur_loc +4]++; + INC_AFL_AREA(cur_loc +4); if ((arg1 & 0xffffffffffff) == (arg2 & 0xffffffffffff)) { - afl_area_ptr[cur_loc +5]++; + INC_AFL_AREA(cur_loc +5); if ((arg1 & 0xffffffffffffff) == (arg2 & 0xffffffffffffff)) { - afl_area_ptr[cur_loc +6]++; + INC_AFL_AREA(cur_loc +6); } } } diff --git a/qemu_mode/patches/afl-qemu-translate-inl.h b/qemu_mode/patches/afl-qemu-translate-inl.h index f82d1217..48d05179 100644 --- a/qemu_mode/patches/afl-qemu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-translate-inl.h @@ -51,8 +51,7 @@ void afl_maybe_log(target_ulong cur_loc) { #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) asm volatile ( "incb (%0, %1, 1)\n" - "seto %%al\n" - "addb %%al, (%0, %1, 1)\n" + "adc $0, (%0, %1, 1)\n" : /* no out */ : "r" (afl_area_ptr), "r" (afl_idx) : "memory", "eax" diff --git a/unicorn_mode/patches/afl-unicorn-cpu-inl.h b/unicorn_mode/patches/afl-unicorn-cpu-inl.h index 28400357..187a0ce6 100644 --- a/unicorn_mode/patches/afl-unicorn-cpu-inl.h +++ b/unicorn_mode/patches/afl-unicorn-cpu-inl.h @@ -252,8 +252,7 @@ static inline void afl_maybe_log(struct uc_struct* uc, unsigned long cur_loc) { #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) asm volatile ( "incb (%0, %1, 1)\n" - "seto %%al\n" - "addb %%al, (%0, %1, 1)\n" + "adc $0, (%0, %1, 1)\n" : /* no out */ : "r" (uc->afl_area_ptr), "r" (afl_idx) : "memory", "eax" diff --git a/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h index 9e56484b..e59d7b15 100644 --- a/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h +++ b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h @@ -32,13 +32,27 @@ #include "uc_priv.h" +#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) +# define INC_AFL_AREA(loc) \ + asm volatile ( \ + "incb (%0, %1, 1)\n" \ + "adc $0, (%0, %1, 1)\n" \ + : /* no out */ \ + : "r" (uc->afl_area_ptr), "r" (loc) \ + : "memory", "eax" \ + ) +#else +# define INC_AFL_AREA(loc) \ + uc->afl_area_ptr[loc]++ +#endif + void HELPER(afl_compcov_log_16)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, uint64_t arg2) { struct uc_struct* uc = uc_ptr; if ((arg1 & 0xff) == (arg2 & 0xff)) { - uc->afl_area_ptr[cur_loc]++; + INC_AFL_AREA(cur_loc); } } @@ -48,11 +62,11 @@ void HELPER(afl_compcov_log_32)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, struct uc_struct* uc = uc_ptr; if ((arg1 & 0xff) == (arg2 & 0xff)) { - uc->afl_area_ptr[cur_loc]++; + INC_AFL_AREA(cur_loc); if ((arg1 & 0xffff) == (arg2 & 0xffff)) { - uc->afl_area_ptr[cur_loc +1]++; + INC_AFL_AREA(cur_loc +1); if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { - uc->afl_area_ptr[cur_loc +2]++; + INC_AFL_AREA(cur_loc +2); } } } @@ -64,19 +78,19 @@ void HELPER(afl_compcov_log_64)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, struct uc_struct* uc = uc_ptr; if ((arg1 & 0xff) == (arg2 & 0xff)) { - uc->afl_area_ptr[cur_loc]++; + INC_AFL_AREA(cur_loc); if ((arg1 & 0xffff) == (arg2 & 0xffff)) { - uc->afl_area_ptr[cur_loc +1]++; + INC_AFL_AREA(cur_loc +1); if ((arg1 & 0xffffff) == (arg2 & 0xffffff)) { - uc->afl_area_ptr[cur_loc +2]++; + INC_AFL_AREA(cur_loc +2); if ((arg1 & 0xffffffff) == (arg2 & 0xffffffff)) { - uc->afl_area_ptr[cur_loc +3]++; + INC_AFL_AREA(cur_loc +3); if ((arg1 & 0xffffffffff) == (arg2 & 0xffffffffff)) { - uc->afl_area_ptr[cur_loc +4]++; + INC_AFL_AREA(cur_loc +4); if ((arg1 & 0xffffffffffff) == (arg2 & 0xffffffffffff)) { - uc->afl_area_ptr[cur_loc +5]++; + INC_AFL_AREA(cur_loc +5); if ((arg1 & 0xffffffffffffff) == (arg2 & 0xffffffffffffff)) { - uc->afl_area_ptr[cur_loc +6]++; + INC_AFL_AREA(cur_loc +6); } } } -- cgit 1.4.1 From 892513708bb5f68b15610fe0c74b892d4421c8cd Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 28 Aug 2019 19:07:19 +0200 Subject: solved MAP_SIZE overflow --- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 2 +- unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index f85a86d7..c0caeefc 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -134,7 +134,7 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2, } cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); - cur_loc &= MAP_SIZE - 1; + cur_loc &= MAP_SIZE - 7; if (cur_loc >= afl_inst_rms) return; diff --git a/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h b/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h index 9c7a14dc..7e8f47c9 100644 --- a/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h +++ b/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h @@ -42,7 +42,7 @@ static void afl_gen_compcov(TCGContext *s, uint64_t cur_loc, TCGv_i64 arg1, return; cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); - cur_loc &= MAP_SIZE - 1; + cur_loc &= MAP_SIZE - 7; if (cur_loc >= s->uc->afl_inst_rms) return; -- cgit 1.4.1 From 3f2a317af09982a47340593b224a10b79a81d303 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 29 Aug 2019 03:06:24 +0200 Subject: Fixed SIGSEV due to wrong pointer size --- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 2 +- qemu_mode/patches/afl-qemu-translate-inl.h | 2 +- unicorn_mode/patches/afl-unicorn-cpu-inl.h | 2 +- unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index c0caeefc..e91e9ffa 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -49,7 +49,7 @@ void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc, # define INC_AFL_AREA(loc) \ asm volatile ( \ "incb (%0, %1, 1)\n" \ - "adc $0, (%0, %1, 1)\n" \ + "adcb $0, (%0, %1, 1)\n" \ : /* no out */ \ : "r" (afl_area_ptr), "r" (loc) \ : "memory", "eax" \ diff --git a/qemu_mode/patches/afl-qemu-translate-inl.h b/qemu_mode/patches/afl-qemu-translate-inl.h index 48d05179..a33e17b7 100644 --- a/qemu_mode/patches/afl-qemu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-translate-inl.h @@ -51,7 +51,7 @@ void afl_maybe_log(target_ulong cur_loc) { #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) asm volatile ( "incb (%0, %1, 1)\n" - "adc $0, (%0, %1, 1)\n" + "adcb $0, (%0, %1, 1)\n" : /* no out */ : "r" (afl_area_ptr), "r" (afl_idx) : "memory", "eax" diff --git a/unicorn_mode/patches/afl-unicorn-cpu-inl.h b/unicorn_mode/patches/afl-unicorn-cpu-inl.h index 187a0ce6..ff194696 100644 --- a/unicorn_mode/patches/afl-unicorn-cpu-inl.h +++ b/unicorn_mode/patches/afl-unicorn-cpu-inl.h @@ -252,7 +252,7 @@ static inline void afl_maybe_log(struct uc_struct* uc, unsigned long cur_loc) { #if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) asm volatile ( "incb (%0, %1, 1)\n" - "adc $0, (%0, %1, 1)\n" + "adcb $0, (%0, %1, 1)\n" : /* no out */ : "r" (uc->afl_area_ptr), "r" (afl_idx) : "memory", "eax" diff --git a/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h index e59d7b15..52cc1afb 100644 --- a/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h +++ b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h @@ -36,7 +36,7 @@ # define INC_AFL_AREA(loc) \ asm volatile ( \ "incb (%0, %1, 1)\n" \ - "adc $0, (%0, %1, 1)\n" \ + "adcb $0, (%0, %1, 1)\n" \ : /* no out */ \ : "r" (uc->afl_area_ptr), "r" (loc) \ : "memory", "eax" \ -- cgit 1.4.1 From 132ad08885f95abfdcbafdf1fa33b3f12ac59538 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 29 Aug 2019 15:28:42 +0200 Subject: common header for qemu and unicorn --- qemu_mode/patches/afl-qemu-common.h | 52 ++++++++++++++++++++++ qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 16 +------ qemu_mode/patches/afl-qemu-translate-inl.h | 14 +----- unicorn_mode/patches/afl-unicorn-common.h | 50 +++++++++++++++++++++ unicorn_mode/patches/afl-unicorn-cpu-inl.h | 30 ++----------- unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h | 21 ++------- 6 files changed, 113 insertions(+), 70 deletions(-) create mode 100644 qemu_mode/patches/afl-qemu-common.h create mode 100644 unicorn_mode/patches/afl-unicorn-common.h diff --git a/qemu_mode/patches/afl-qemu-common.h b/qemu_mode/patches/afl-qemu-common.h new file mode 100644 index 00000000..8013800d --- /dev/null +++ b/qemu_mode/patches/afl-qemu-common.h @@ -0,0 +1,52 @@ +/* + american fuzzy lop - high-performance binary-only instrumentation + ----------------------------------------------------------------- + + Written by Andrew Griffiths and + Michal Zalewski + + Idea & design very much by Andrew Griffiths. + + TCG instrumentation and block chaining support by Andrea Biondo + + + QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi + + + Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This code is a shim patched into the separately-distributed source + code of QEMU 3.1.0. It leverages the built-in QEMU tracing functionality + to implement AFL-style instrumentation and to take care of the remaining + parts of the AFL fork server logic. + + The resulting QEMU binary is essentially a standalone instrumentation + tool; for an example of how to leverage it for other purposes, you can + have a look at afl-showmap.c. + + */ + +#include "../../config.h" + +/* NeverZero */ + +#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) +# define INC_AFL_AREA(loc) \ + asm volatile ( \ + "incb (%0, %1, 1)\n" \ + "adcb $0, (%0, %1, 1)\n" \ + : /* no out */ \ + : "r" (afl_area_ptr), "r" (loc) \ + : "memory", "eax" \ + ) +#else +# define INC_AFL_AREA(loc) \ + afl_area_ptr[loc]++ +#endif + diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index e91e9ffa..fc78e652 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -32,7 +32,7 @@ */ -#include "../../config.h" +#include "afl-qemu-common.h" #include "tcg.h" #include "tcg-op.h" @@ -45,20 +45,6 @@ extern u8 afl_compcov_level; void tcg_gen_afl_compcov_log_call(void *func, target_ulong cur_loc, TCGv_i64 arg1, TCGv_i64 arg2); -#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) -# define INC_AFL_AREA(loc) \ - asm volatile ( \ - "incb (%0, %1, 1)\n" \ - "adcb $0, (%0, %1, 1)\n" \ - : /* no out */ \ - : "r" (afl_area_ptr), "r" (loc) \ - : "memory", "eax" \ - ) -#else -# define INC_AFL_AREA(loc) \ - afl_area_ptr[loc]++ -#endif - static void afl_compcov_log_16(target_ulong cur_loc, target_ulong arg1, target_ulong arg2) { diff --git a/qemu_mode/patches/afl-qemu-translate-inl.h b/qemu_mode/patches/afl-qemu-translate-inl.h index a33e17b7..d63c5167 100644 --- a/qemu_mode/patches/afl-qemu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-translate-inl.h @@ -32,7 +32,7 @@ */ -#include "../../config.h" +#include "afl-qemu-common.h" #include "tcg-op.h" /* Declared in afl-qemu-cpu-inl.h */ @@ -48,17 +48,7 @@ void afl_maybe_log(target_ulong cur_loc) { register uintptr_t afl_idx = cur_loc ^ prev_loc; -#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) - asm volatile ( - "incb (%0, %1, 1)\n" - "adcb $0, (%0, %1, 1)\n" - : /* no out */ - : "r" (afl_area_ptr), "r" (afl_idx) - : "memory", "eax" - ); -#else - afl_area_ptr[afl_idx]++; -#endif + INC_AFL_AREA(afl_idx); prev_loc = cur_loc >> 1; diff --git a/unicorn_mode/patches/afl-unicorn-common.h b/unicorn_mode/patches/afl-unicorn-common.h new file mode 100644 index 00000000..9a1b2a6c --- /dev/null +++ b/unicorn_mode/patches/afl-unicorn-common.h @@ -0,0 +1,50 @@ +/* + american fuzzy lop - high-performance binary-only instrumentation + ----------------------------------------------------------------- + + Written by Andrew Griffiths and + Michal Zalewski + + TCG instrumentation and block chaining support by Andrea Biondo + + Adapted for afl-unicorn by Dominik Maier + + Idea & design very much by Andrew Griffiths. + + Copyright 2015, 2016 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + This code is a shim patched into the separately-distributed source + code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality + to implement AFL-style instrumentation and to take care of the remaining + parts of the AFL fork server logic. + + The resulting QEMU binary is essentially a standalone instrumentation + tool; for an example of how to leverage it for other purposes, you can + have a look at afl-showmap.c. + + */ + +#include "../../config.h" + +/* NeverZero */ + +#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) +# define INC_AFL_AREA(loc) \ + asm volatile ( \ + "incb (%0, %1, 1)\n" \ + "adcb $0, (%0, %1, 1)\n" \ + : /* no out */ \ + : "r" (afl_area_ptr), "r" (loc) \ + : "memory", "eax" \ + ) +#else +# define INC_AFL_AREA(loc) \ + afl_area_ptr[loc]++ +#endif + diff --git a/unicorn_mode/patches/afl-unicorn-cpu-inl.h b/unicorn_mode/patches/afl-unicorn-cpu-inl.h index ff194696..90937a17 100644 --- a/unicorn_mode/patches/afl-unicorn-cpu-inl.h +++ b/unicorn_mode/patches/afl-unicorn-cpu-inl.h @@ -33,7 +33,7 @@ #include #include #include -#include "../../config.h" +#include "afl-unicorn-common.h" /*************************** * VARIOUS AUXILIARY STUFF * @@ -218,17 +218,11 @@ static inline void afl_maybe_log(struct uc_struct* uc, unsigned long cur_loc) { static __thread unsigned long prev_loc; - // DEBUG - //printf("IN AFL_MAYBE_LOG 0x%lx\n", cur_loc); + u8* afl_area_ptr = uc->afl_area_ptr; - // MODIFIED FOR UNICORN MODE -> We want to log all addresses, - // so the checks for 'start < addr < end' are removed - if(!uc->afl_area_ptr) + if(!afl_area_ptr) return; - // DEBUG - //printf("afl_area_ptr = %p\n", afl_area_ptr); - /* Looks like QEMU always maps to fixed locations, so ASAN is not a concern. Phew. But instruction addresses may be aligned. Let's mangle the value to get something quasi-uniform. */ @@ -239,27 +233,11 @@ static inline void afl_maybe_log(struct uc_struct* uc, unsigned long cur_loc) { /* Implement probabilistic instrumentation by looking at scrambled block address. This keeps the instrumented locations stable across runs. */ - // DEBUG - //printf("afl_inst_rms = 0x%lx\n", afl_inst_rms); - if (cur_loc >= uc->afl_inst_rms) return; - // DEBUG - //printf("cur_loc = 0x%lx\n", cur_loc); - register uintptr_t afl_idx = cur_loc ^ prev_loc; -#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) - asm volatile ( - "incb (%0, %1, 1)\n" - "adcb $0, (%0, %1, 1)\n" - : /* no out */ - : "r" (uc->afl_area_ptr), "r" (afl_idx) - : "memory", "eax" - ); -#else - uc->afl_area_ptr[afl_idx]++; -#endif + INC_AFL_AREA(afl_idx); prev_loc = cur_loc >> 1; diff --git a/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h index 52cc1afb..0019bbfa 100644 --- a/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h +++ b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h @@ -31,25 +31,12 @@ */ #include "uc_priv.h" - -#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO) -# define INC_AFL_AREA(loc) \ - asm volatile ( \ - "incb (%0, %1, 1)\n" \ - "adcb $0, (%0, %1, 1)\n" \ - : /* no out */ \ - : "r" (uc->afl_area_ptr), "r" (loc) \ - : "memory", "eax" \ - ) -#else -# define INC_AFL_AREA(loc) \ - uc->afl_area_ptr[loc]++ -#endif +#include "afl-unicorn-common.h" void HELPER(afl_compcov_log_16)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, uint64_t arg2) { - struct uc_struct* uc = uc_ptr; + u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr; if ((arg1 & 0xff) == (arg2 & 0xff)) { INC_AFL_AREA(cur_loc); @@ -59,7 +46,7 @@ void HELPER(afl_compcov_log_16)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, void HELPER(afl_compcov_log_32)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, uint64_t arg2) { - struct uc_struct* uc = uc_ptr; + u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr; if ((arg1 & 0xff) == (arg2 & 0xff)) { INC_AFL_AREA(cur_loc); @@ -75,7 +62,7 @@ void HELPER(afl_compcov_log_32)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, void HELPER(afl_compcov_log_64)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1, uint64_t arg2) { - struct uc_struct* uc = uc_ptr; + u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr; if ((arg1 & 0xff) == (arg2 & 0xff)) { INC_AFL_AREA(cur_loc); -- cgit 1.4.1 From 7b36afd5f16894257c92695d200e59eb51d08e1c Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 30 Aug 2019 11:38:33 +0200 Subject: modernize docs and readme for qemu and unicorn --- docs/unicorn_mode.txt | 109 --------------- qemu_mode/README.md | 137 +++++++++++++++++++ qemu_mode/README.qemu | 146 --------------------- qemu_mode/build_qemu_support.sh | 11 +- qemu_mode/libcompcov/libcompcov.so.c | 2 +- qemu_mode/patches/afl-qemu-common.h | 15 +-- qemu_mode/patches/afl-qemu-cpu-inl.h | 15 +-- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 17 ++- qemu_mode/patches/afl-qemu-tcg-inl.h | 15 +-- qemu_mode/patches/afl-qemu-translate-inl.h | 15 +-- unicorn_mode/README.md | 130 +++++++++++++++--- unicorn_mode/build_unicorn_support.sh | 12 +- unicorn_mode/patches/afl-unicorn-common.h | 18 +-- unicorn_mode/patches/afl-unicorn-cpu-inl.h | 18 +-- .../patches/afl-unicorn-cpu-translate-inl.h | 18 +-- unicorn_mode/patches/afl-unicorn-tcg-op-inl.h | 18 +-- unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h | 18 +-- unicorn_mode/samples/compcov_x64/COMPILE.md | 3 +- unicorn_mode/samples/compcov_x64/compcov_target.c | 2 +- unicorn_mode/samples/simple/COMPILE.md | 5 +- 20 files changed, 353 insertions(+), 371 deletions(-) delete mode 100644 docs/unicorn_mode.txt create mode 100644 qemu_mode/README.md delete mode 100644 qemu_mode/README.qemu diff --git a/docs/unicorn_mode.txt b/docs/unicorn_mode.txt deleted file mode 100644 index b691fff8..00000000 --- a/docs/unicorn_mode.txt +++ /dev/null @@ -1,109 +0,0 @@ -========================================================= -Unicorn-based binary-only instrumentation for afl-fuzz -========================================================= - -1) Introduction ---------------- - -The code in ./unicorn_mode allows you to build a standalone feature that -leverages the Unicorn Engine and allows callers to obtain instrumentation -output for black-box, closed-source binary code snippets. This mechanism -can be then used by afl-fuzz to stress-test targets that couldn't be built -with afl-gcc or used in QEMU mode, or with other extensions such as -TriforceAFL. - -There is a significant performance penalty compared to native AFL, -but at least we're able to use AFL on these binaries, right? - -The idea and much of the implementation comes from Nathan Voss . - -2) How to use -------------- - -Requirements: you need an installed python2 environment. - -*** Building AFL's Unicorn Mode *** - -First, make afl as usual. -Once that completes successfully you need to build and add in the Unicorn Mode -features: - - $ cd unicorn_mode - $ ./build_unicorn_support.sh - -NOTE: This script downloads a recent Unicorn Engine commit that has been tested -and is stable-ish from the Unicorn github page. If you are offline, you'll need -to hack up this script a little bit and supply your own copy of Unicorn's latest -stable release. It's not very hard, just check out the beginning of the -build_unicorn_support.sh script and adjust as necessary. - -Building Unicorn will take a little bit (~5-10 minutes). Once it completes -it automatically compiles a sample application and verify that it works. - -*** Fuzzing with Unicorn Mode *** - -To really use unicorn-mode effectively you need to prepare the following: - - * Relevant binary code to be fuzzed - * Knowledge of the memory map and good starting state - * Folder containing sample inputs to start fuzzing with - - Same ideas as any other AFL inputs - - Quality/speed of results will depend greatly on quality of starting - samples - - See AFL's guidance on how to create a sample corpus - * Unicorn-based test harness which: - - Adds memory map regions - - Loads binary code into memory - - Emulates at least one instruction* - - Yeah, this is lame. See 'Gotchas' section below for more info - - Loads and verifies data to fuzz from a command-line specified file - - AFL will provide mutated inputs by changing the file passed to - the test harness - - Presumably the data to be fuzzed is at a fixed buffer address - - If input constraints (size, invalid bytes, etc.) are known they - should be checked after the file is loaded. If a constraint - fails, just exit the test harness. AFL will treat the input as - 'uninteresting' and move on. - - Sets up registers and memory state for beginning of test - - Emulates the interested code from beginning to end - - If a crash is detected, the test harness must 'crash' by - throwing a signal (SIGSEGV, SIGKILL, SIGABORT, etc.) - -Once you have all those things ready to go you just need to run afl-fuzz in -'unicorn-mode' by passing in the '-U' flag: - - $ afl-fuzz -U -m none -i /path/to/inputs -o /path/to/results -- ./test_harness @@ - -The normal afl-fuzz command line format applies to everything here. Refer to -AFL's main documentation for more info about how to use afl-fuzz effectively. - -For a much clearer vision of what all of this looks like, please refer to the -sample provided in the 'unicorn_mode/samples' directory. There is also a blog -post that goes over the basics at: - -https://medium.com/@njvoss299/afl-unicorn-fuzzing-arbitrary-binary-code-563ca28936bf - -The 'helper_scripts' directory also contains several helper scripts that allow you -to dump context from a running process, load it, and hook heap allocations. For details -on how to use this check out the follow-up blog post to the one linked above. - -A example use of AFL-Unicorn mode is discussed in the Paper Unicorefuzz: -https://www.usenix.org/conference/woot19/presentation/maier - -3) Gotchas, feedback, bugs --------------------------- - -To make sure that AFL's fork server starts up correctly the Unicorn test -harness script must emulate at least one instruction before loading the -data that will be fuzzed from the input file. It doesn't matter what the -instruction is, nor if it is valid. This is an artifact of how the fork-server -is started and could likely be fixed with some clever re-arranging of the -patches applied to Unicorn. - -Running the build script builds Unicorn and its python bindings and installs -them on your system. This installation will supersede any existing Unicorn -installation with the patched afl-unicorn version. - -Refer to the unicorn_mode/samples/arm_example/arm_tester.c for an example -of how to do this properly! If you don't get this right, AFL will not -load any mutated inputs and your fuzzing will be useless! diff --git a/qemu_mode/README.md b/qemu_mode/README.md new file mode 100644 index 00000000..610f6860 --- /dev/null +++ b/qemu_mode/README.md @@ -0,0 +1,137 @@ +# High-performance binary-only instrumentation for afl-fuzz + + (See ../docs/README for the general instruction manual.) + +## 1) Introduction + +The code in this directory allows you to build a standalone feature that +leverages the QEMU "user emulation" mode and allows callers to obtain +instrumentation output for black-box, closed-source binaries. This mechanism +can be then used by afl-fuzz to stress-test targets that couldn't be built +with afl-gcc. + +The usual performance cost is 2-5x, which is considerably better than +seen so far in experiments with tools such as DynamoRIO and PIN. + +The idea and much of the initial implementation comes from Andrew Griffiths. +The actual implementation on QEMU 3 (shipped with afl++) is from +Andrea Fioraldi. Special thanks to abiondo that re-enabled TCG chaining. + +## 2) How to use + +The feature is implemented with a patch to QEMU 3.1.0. The simplest way +to build it is to run ./build_qemu_support.sh. The script will download, +configure, and compile the QEMU binary for you. + +QEMU is a big project, so this will take a while, and you may have to +resolve a couple of dependencies (most notably, you will definitely need +libtool and glib2-devel). + +Once the binaries are compiled, you can leverage the QEMU tool by calling +afl-fuzz and all the related utilities with -Q in the command line. + +Note that QEMU requires a generous memory limit to run; somewhere around +200 MB is a good starting point, but considerably more may be needed for +more complex programs. The default -m limit will be automatically bumped up +to 200 MB when specifying -Q to afl-fuzz; be careful when overriding this. + +In principle, if you set CPU_TARGET before calling ./build_qemu_support.sh, +you should get a build capable of running non-native binaries (say, you +can try CPU_TARGET=arm). This is also necessary for running 32-bit binaries +on a 64-bit system (CPU_TARGET=i386). + +Note: if you want the QEMU helper to be installed on your system for all +users, you need to build it before issuing 'make install' in the parent +directory. + +## 3) Options + +There is ./libcompcov/ which implements laf-intel (splitting memcmp, +strncmp, etc. to make these conditions easier solvable by afl-fuzz). +Highly recommended. + +The option that enables QEMU CompareCoverage is AFL_COMPCOV_LEVEL. +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 +is preloaded. Comparison instructions are currently instrumented only +on the x86 and x86_64 targets. + +Another option is the environment variable AFL_ENTRYPOINT which allows +move the forkserver to a different part, e.g. just before the file is +opened (e.g. way after command line parsing and config file loading, etc) +which can be a huge speed improvement. Note that the specified address +must be an address of a basic block. + +## 4) 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 +bsd-user/elfload.c, but I have not looked into this yet. + +The instrumentation follows only the .text section of the first ELF binary +encountered in the linking process. It does not trace shared libraries. In +practice, this means two things: + + - Any libraries you want to analyze *must* be linked statically into the + executed ELF file (this will usually be the case for closed-source + apps). + + - Standard C libraries and other stuff that is wasteful to instrument + should be linked dynamically - otherwise, AFL will have no way to avoid + peeking into them. + +Setting AFL_INST_LIBS=1 can be used to circumvent the .text detection logic +and instrument every basic block encountered. + +## 5) 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 +non-instrumented binary with the same optimization flags that are normally +injected by afl-gcc, and make sure that the bits to be tested are statically +linked into the binary. A common way to do this would be: + +$ CFLAGS="-O3 -funroll-loops" ./configure --disable-shared +$ make clean all + +Comparative measurements of execution speed or instrumentation coverage will be +fairly meaningless if the optimization levels or instrumentation scopes don't +match. + +## 6) Gotchas, feedback, bugs + +If you need to fix up checksums or do other cleanup on mutated test cases, see +experimental/post_library/ for a viable solution. + +Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate +the "shadow VM" trick employed by the sanitizers and will probably just +run out of memory. + +Compared to fully-fledged virtualization, the user emulation mode is *NOT* a +security boundary. The binaries can freely interact with the host OS. If you +somehow need to fuzz an untrusted binary, put everything in a sandbox first. + +QEMU does not necessarily support all CPU or hardware features that your +target program may be utilizing. In particular, it does not appear to have +full support for AVX2 / FMA3. Using binaries for older CPUs, or recompiling them +with -march=core2, can help. + +Beyond that, this is an early-stage mechanism, so fields reports are welcome. +You can send them to . + +## 7) 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 +fraught with peril, because it depends on being able to properly and fully model +program control flow without actually executing each and every code path. + +The best implementation is this one: + + https://github.com/vanhauser-thc/afl-dyninst + +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. diff --git a/qemu_mode/README.qemu b/qemu_mode/README.qemu deleted file mode 100644 index cd8559ad..00000000 --- a/qemu_mode/README.qemu +++ /dev/null @@ -1,146 +0,0 @@ -========================================================= -High-performance binary-only instrumentation for afl-fuzz -========================================================= - - (See ../docs/README for the general instruction manual.) - -1) Introduction ---------------- - -The code in this directory allows you to build a standalone feature that -leverages the QEMU "user emulation" mode and allows callers to obtain -instrumentation output for black-box, closed-source binaries. This mechanism -can be then used by afl-fuzz to stress-test targets that couldn't be built -with afl-gcc. - -The usual performance cost is 2-5x, which is considerably better than -seen so far in experiments with tools such as DynamoRIO and PIN. - -The idea and much of the initial implementation comes from Andrew Griffiths. -The actual implementation on QEMU 3 (shipped with afl++) is from -Andrea Fioraldi. Special thanks to abiondo that re-enabled TCG chaining. - -2) How to use -------------- - -The feature is implemented with a patch to QEMU 3.1.0. The simplest way -to build it is to run ./build_qemu_support.sh. The script will download, -configure, and compile the QEMU binary for you. - -QEMU is a big project, so this will take a while, and you may have to -resolve a couple of dependencies (most notably, you will definitely need -libtool and glib2-devel). - -Once the binaries are compiled, you can leverage the QEMU tool by calling -afl-fuzz and all the related utilities with -Q in the command line. - -Note that QEMU requires a generous memory limit to run; somewhere around -200 MB is a good starting point, but considerably more may be needed for -more complex programs. The default -m limit will be automatically bumped up -to 200 MB when specifying -Q to afl-fuzz; be careful when overriding this. - -In principle, if you set CPU_TARGET before calling ./build_qemu_support.sh, -you should get a build capable of running non-native binaries (say, you -can try CPU_TARGET=arm). This is also necessary for running 32-bit binaries -on a 64-bit system (CPU_TARGET=i386). - -Note: if you want the QEMU helper to be installed on your system for all -users, you need to build it before issuing 'make install' in the parent -directory. - -3) Options ----------- - -There is ./libcompcov/ which implements laf-intel (splitting memcmp, -strncmp, etc. to make these conditions easier solvable by afl-fuzz). -Highly recommended. - -The option that enables QEMU CompareCoverage is QEMU_COMPCOV_LEVEL. -QEMU_COMPCOV_LEVEL=1 is to instrument comparisons with only immediate -values / read-only memory. QEMU_COMPCOV_LEVEL=2 instruments all -comparison instructions and memory comparison functions when libcompcov -is preloaded. Comparison instructions are currently instrumented only -on the x86 and x86_64 targets. - -Another option is the environment variable AFL_ENTRYPOINT which allows -move the forkserver to a different part, e.g. just before the file is -opened (e.g. way after command line parsing and config file loading, etc) -which can be a huge speed improvement. Note that the specified address -must be an address of a basic block. - -4) 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 -bsd-user/elfload.c, but I have not looked into this yet. - -The instrumentation follows only the .text section of the first ELF binary -encountered in the linking process. It does not trace shared libraries. In -practice, this means two things: - - - Any libraries you want to analyze *must* be linked statically into the - executed ELF file (this will usually be the case for closed-source - apps). - - - Standard C libraries and other stuff that is wasteful to instrument - should be linked dynamically - otherwise, AFL will have no way to avoid - peeking into them. - -Setting AFL_INST_LIBS=1 can be used to circumvent the .text detection logic -and instrument every basic block encountered. - -5) 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 -non-instrumented binary with the same optimization flags that are normally -injected by afl-gcc, and make sure that the bits to be tested are statically -linked into the binary. A common way to do this would be: - -$ CFLAGS="-O3 -funroll-loops" ./configure --disable-shared -$ make clean all - -Comparative measurements of execution speed or instrumentation coverage will be -fairly meaningless if the optimization levels or instrumentation scopes don't -match. - -6) Gotchas, feedback, bugs --------------------------- - -If you need to fix up checksums or do other cleanup on mutated test cases, see -experimental/post_library/ for a viable solution. - -Do not mix QEMU mode with ASAN, MSAN, or the likes; QEMU doesn't appreciate -the "shadow VM" trick employed by the sanitizers and will probably just -run out of memory. - -Compared to fully-fledged virtualization, the user emulation mode is *NOT* a -security boundary. The binaries can freely interact with the host OS. If you -somehow need to fuzz an untrusted binary, put everything in a sandbox first. - -QEMU does not necessarily support all CPU or hardware features that your -target program may be utilizing. In particular, it does not appear to have -full support for AVX2 / FMA3. Using binaries for older CPUs, or recompiling them -with -march=core2, can help. - -Beyond that, this is an early-stage mechanism, so fields reports are welcome. -You can send them to . - -7) 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 -fraught with peril, because it depends on being able to properly and fully model -program control flow without actually executing each and every code path. - -The best implementation is this one: - - https://github.com/vanhauser-thc/afl-dyninst - -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. diff --git a/qemu_mode/build_qemu_support.sh b/qemu_mode/build_qemu_support.sh index 78ad5680..35f5b8ca 100755 --- a/qemu_mode/build_qemu_support.sh +++ b/qemu_mode/build_qemu_support.sh @@ -3,10 +3,17 @@ # american fuzzy lop - QEMU build script # -------------------------------------- # -# Written by Andrew Griffiths and -# Michal Zalewski +# Originally written by Andrew Griffiths and +# Michal Zalewski +# +# TCG instrumentation and block chaining support by Andrea Biondo +# +# +# QEMU 3.1.0 port, TCG thread-safety, CompareCoverage and NeverZero +# counters by Andrea Fioraldi # # Copyright 2015, 2016, 2017 Google Inc. All rights reserved. +# Copyright 2019 AFLplusplus Project. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/qemu_mode/libcompcov/libcompcov.so.c b/qemu_mode/libcompcov/libcompcov.so.c index 92e4dbaa..0ccda927 100644 --- a/qemu_mode/libcompcov/libcompcov.so.c +++ b/qemu_mode/libcompcov/libcompcov.so.c @@ -5,7 +5,7 @@ Written and maintained by Andrea Fioraldi - Copyright 2019 Andrea Fioraldi. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/qemu_mode/patches/afl-qemu-common.h b/qemu_mode/patches/afl-qemu-common.h index 8013800d..c475cb58 100644 --- a/qemu_mode/patches/afl-qemu-common.h +++ b/qemu_mode/patches/afl-qemu-common.h @@ -1,19 +1,18 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - high-performance binary-only instrumentation + ------------------------------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski - - Idea & design very much by Andrew Griffiths. + Originally written by Andrew Griffiths and + Michal Zalewski TCG instrumentation and block chaining support by Andrea Biondo - QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi - + QEMU 3.1.0 port, TCG thread-safety, CompareCoverage and NeverZero + counters by Andrea Fioraldi Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 04d9007d..4ad31b60 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -1,19 +1,18 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - high-performance binary-only instrumentation + ------------------------------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski - - Idea & design very much by Andrew Griffiths. + Originally written by Andrew Griffiths and + Michal Zalewski TCG instrumentation and block chaining support by Andrea Biondo - QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi - + QEMU 3.1.0 port, TCG thread-safety, CompareCoverage and NeverZero + counters by Andrea Fioraldi Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index fc78e652..09ecb9d2 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -1,19 +1,18 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - high-performance binary-only instrumentation + ------------------------------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski - - Idea & design very much by Andrew Griffiths. + Originally written by Andrew Griffiths and + Michal Zalewski TCG instrumentation and block chaining support by Andrea Biondo - - QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi - + + QEMU 3.1.0 port, TCG thread-safety, CompareCoverage and NeverZero + counters by Andrea Fioraldi Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/qemu_mode/patches/afl-qemu-tcg-inl.h b/qemu_mode/patches/afl-qemu-tcg-inl.h index ff90d1b9..a9c53b8c 100644 --- a/qemu_mode/patches/afl-qemu-tcg-inl.h +++ b/qemu_mode/patches/afl-qemu-tcg-inl.h @@ -1,19 +1,18 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - high-performance binary-only instrumentation + ------------------------------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski - - Idea & design very much by Andrew Griffiths. + Originally written by Andrew Griffiths and + Michal Zalewski TCG instrumentation and block chaining support by Andrea Biondo - QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi - + QEMU 3.1.0 port, TCG thread-safety, CompareCoverage and NeverZero + counters by Andrea Fioraldi Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/qemu_mode/patches/afl-qemu-translate-inl.h b/qemu_mode/patches/afl-qemu-translate-inl.h index d63c5167..ffe43dba 100644 --- a/qemu_mode/patches/afl-qemu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-translate-inl.h @@ -1,19 +1,18 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - high-performance binary-only instrumentation + ------------------------------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski - - Idea & design very much by Andrew Griffiths. + Originally written by Andrew Griffiths and + Michal Zalewski TCG instrumentation and block chaining support by Andrea Biondo - QEMU 3.1.0 port, TCG thread-safety and CompareCoverage by Andrea Fioraldi - + QEMU 3.1.0 port, TCG thread-safety, CompareCoverage and NeverZero + counters by Andrea Fioraldi Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/unicorn_mode/README.md b/unicorn_mode/README.md index 9ee975ef..ea3e3c9b 100644 --- a/unicorn_mode/README.md +++ b/unicorn_mode/README.md @@ -1,23 +1,119 @@ -``` - __ _ _ - __ _ / _| | _ _ _ __ (_) ___ ___ _ __ _ __ - / _` | |_| |___| | | | '_ \| |/ __/ _ \| '__| '_ \ -| (_| | _| |___| |_| | | | | | (_| (_) | | | | | | - \__,_|_| |_| \__,_|_| |_|_|\___\___/|_| |_| |_| - -``` +# Unicorn-based binary-only instrumentation for afl-fuzz -afl-unicorn lets you fuzz any piece of binary that can be emulated by -[Unicorn Engine](http://www.unicorn-engine.org/). +The idea and much of the original implementation comes from Nathan Voss . -Requirements: Python2 +The port to afl++ if by Dominik Maier . -For the full readme please see docs/unicorn_mode.txt +The CompareCoverage and NeverZero counters features by Andrea Fioraldi . -For an in-depth description of what this is, how to install it, and how to use -it check out this [blog post](https://medium.com/@njvoss299/afl-unicorn-fuzzing-arbitrary-binary-code-563ca28936bf). +## 1) Introduction -For general help with AFL, please refer to the documents in the ./docs/ directory. +The code in ./unicorn_mode allows you to build a standalone feature that +leverages the Unicorn Engine and allows callers to obtain instrumentation +output for black-box, closed-source binary code snippets. This mechanism +can be then used by afl-fuzz to stress-test targets that couldn't be built +with afl-gcc or used in QEMU mode, or with other extensions such as +TriforceAFL. -Created by Nathan Voss, originally funded by -[Battelle](https://www.battelle.org/cyber). +There is a significant performance penalty compared to native AFL, +but at least we're able to use AFL on these binaries, right? + +## 2) How to use + +Requirements: you need an installed python2 environment. + +### Building AFL's Unicorn Mode + +First, make afl++ as usual. +Once that completes successfully you need to build and add in the Unicorn Mode +features: + + $ cd unicorn_mode + $ ./build_unicorn_support.sh + +NOTE: This script downloads a Unicorn Engine commit that has been tested +and is stable-ish from the Unicorn github page. If you are offline, you'll need +to hack up this script a little bit and supply your own copy of Unicorn's latest +stable release. It's not very hard, just check out the beginning of the +build_unicorn_support.sh script and adjust as necessary. + +Building Unicorn will take a little bit (~5-10 minutes). Once it completes +it automatically compiles a sample application and verify that it works. + +### Fuzzing with Unicorn Mode + +To really use unicorn-mode effectively you need to prepare the following: + + * Relevant binary code to be fuzzed + * Knowledge of the memory map and good starting state + * Folder containing sample inputs to start fuzzing with + + Same ideas as any other AFL inputs + + Quality/speed of results will depend greatly on quality of starting + samples + + See AFL's guidance on how to create a sample corpus + * Unicorn-based test harness which: + + Adds memory map regions + + Loads binary code into memory + + Emulates at least one instruction* + + Yeah, this is lame. See 'Gotchas' section below for more info + + Loads and verifies data to fuzz from a command-line specified file + + AFL will provide mutated inputs by changing the file passed to + the test harness + + Presumably the data to be fuzzed is at a fixed buffer address + + If input constraints (size, invalid bytes, etc.) are known they + should be checked after the file is loaded. If a constraint + fails, just exit the test harness. AFL will treat the input as + 'uninteresting' and move on. + + Sets up registers and memory state for beginning of test + + Emulates the interested code from beginning to end + + If a crash is detected, the test harness must 'crash' by + throwing a signal (SIGSEGV, SIGKILL, SIGABORT, etc.) + +Once you have all those things ready to go you just need to run afl-fuzz in +'unicorn-mode' by passing in the '-U' flag: + + $ afl-fuzz -U -m none -i /path/to/inputs -o /path/to/results -- ./test_harness @@ + +The normal afl-fuzz command line format applies to everything here. Refer to +AFL's main documentation for more info about how to use afl-fuzz effectively. + +For a much clearer vision of what all of this looks like, please refer to the +sample provided in the 'unicorn_mode/samples' directory. There is also a blog +post that goes over the basics at: + +https://medium.com/@njvoss299/afl-unicorn-fuzzing-arbitrary-binary-code-563ca28936bf + +The 'helper_scripts' directory also contains several helper scripts that allow you +to dump context from a running process, load it, and hook heap allocations. For details +on how to use this check out the follow-up blog post to the one linked above. + +A example use of AFL-Unicorn mode is discussed in the Paper Unicorefuzz: +https://www.usenix.org/conference/woot19/presentation/maier + +## 3) Options + +As for the QEMU-based instrumentation, the afl-unicorn twist of afl++ +comes with a sub-instruction based instrumentation similar in purpose to laf-intel. + +The options that enables Unicorn CompareCoverage are the same used for QEMU. +AFL_COMPCOV_LEVEL=1 is to instrument comparisons with only immediate +values. QEMU_COMPCOV_LEVEL=2 instruments all +comparison instructions. Comparison instructions are currently instrumented only +on the x86 and x86_64 targets. + +## 4) Gotchas, feedback, bugs + +To make sure that AFL's fork server starts up correctly the Unicorn test +harness script must emulate at least one instruction before loading the +data that will be fuzzed from the input file. It doesn't matter what the +instruction is, nor if it is valid. This is an artifact of how the fork-server +is started and could likely be fixed with some clever re-arranging of the +patches applied to Unicorn. + +Running the build script builds Unicorn and its python bindings and installs +them on your system. This installation will supersede any existing Unicorn +installation with the patched afl-unicorn version. + +Refer to the unicorn_mode/samples/arm_example/arm_tester.c for an example +of how to do this properly! If you don't get this right, AFL will not +load any mutated inputs and your fuzzing will be useless! diff --git a/unicorn_mode/build_unicorn_support.sh b/unicorn_mode/build_unicorn_support.sh index 2c0fe4b1..1575f66c 100755 --- a/unicorn_mode/build_unicorn_support.sh +++ b/unicorn_mode/build_unicorn_support.sh @@ -1,16 +1,20 @@ #!/bin/sh # -# american fuzzy lop - Unicorn-Mode build script -# -------------------------------------- +# american fuzzy lop++ - unicorn mode build script +# ------------------------------------------------ # -# Written by Nathan Voss +# Originally written by Nathan Voss # # Adapted from code by Andrew Griffiths and # Michal Zalewski # -# Adapted for Afl++ by Dominik Maier +# Adapted for AFLplusplus by Dominik Maier +# +# CompareCoverage and NeverZero counters by Andrea Fioraldi +# # # Copyright 2017 Battelle Memorial Institute. All rights reserved. +# Copyright 2019 AFLplusplus Project. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/unicorn_mode/patches/afl-unicorn-common.h b/unicorn_mode/patches/afl-unicorn-common.h index 9a1b2a6c..6798832c 100644 --- a/unicorn_mode/patches/afl-unicorn-common.h +++ b/unicorn_mode/patches/afl-unicorn-common.h @@ -1,17 +1,17 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - unicorn instrumentation + ---------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski + Originally written by Andrew Griffiths and + Michal Zalewski - TCG instrumentation and block chaining support by Andrea Biondo - Adapted for afl-unicorn by Dominik Maier - Idea & design very much by Andrew Griffiths. + CompareCoverage and NeverZero counters by Andrea Fioraldi + - Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ to implement AFL-style instrumentation and to take care of the remaining parts of the AFL fork server logic. - The resulting QEMU binary is essentially a standalone instrumentation + The resulting libunicorn binary is essentially a standalone instrumentation tool; for an example of how to leverage it for other purposes, you can have a look at afl-showmap.c. diff --git a/unicorn_mode/patches/afl-unicorn-cpu-inl.h b/unicorn_mode/patches/afl-unicorn-cpu-inl.h index 90937a17..a713e4ca 100644 --- a/unicorn_mode/patches/afl-unicorn-cpu-inl.h +++ b/unicorn_mode/patches/afl-unicorn-cpu-inl.h @@ -1,17 +1,17 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - unicorn instrumentation + ---------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski + Originally written by Andrew Griffiths and + Michal Zalewski - TCG instrumentation and block chaining support by Andrea Biondo - Adapted for afl-unicorn by Dominik Maier - Idea & design very much by Andrew Griffiths. + CompareCoverage and NeverZero counters by Andrea Fioraldi + - Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ to implement AFL-style instrumentation and to take care of the remaining parts of the AFL fork server logic. - The resulting QEMU binary is essentially a standalone instrumentation + The resulting libunicorn binary is essentially a standalone instrumentation tool; for an example of how to leverage it for other purposes, you can have a look at afl-showmap.c. diff --git a/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h b/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h index 7e8f47c9..69877c6b 100644 --- a/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h +++ b/unicorn_mode/patches/afl-unicorn-cpu-translate-inl.h @@ -1,17 +1,17 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - unicorn instrumentation + ---------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski + Originally written by Andrew Griffiths and + Michal Zalewski - TCG instrumentation and block chaining support by Andrea Biondo - Adapted for afl-unicorn by Dominik Maier - Idea & design very much by Andrew Griffiths. + CompareCoverage and NeverZero counters by Andrea Fioraldi + - Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ to implement AFL-style instrumentation and to take care of the remaining parts of the AFL fork server logic. - The resulting QEMU binary is essentially a standalone instrumentation + The resulting libunicorn binary is essentially a standalone instrumentation tool; for an example of how to leverage it for other purposes, you can have a look at afl-showmap.c. diff --git a/unicorn_mode/patches/afl-unicorn-tcg-op-inl.h b/unicorn_mode/patches/afl-unicorn-tcg-op-inl.h index d5a29cce..fa4974d6 100644 --- a/unicorn_mode/patches/afl-unicorn-tcg-op-inl.h +++ b/unicorn_mode/patches/afl-unicorn-tcg-op-inl.h @@ -1,17 +1,17 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - unicorn instrumentation + ---------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski + Originally written by Andrew Griffiths and + Michal Zalewski - TCG instrumentation and block chaining support by Andrea Biondo - Adapted for afl-unicorn by Dominik Maier - Idea & design very much by Andrew Griffiths. + CompareCoverage and NeverZero counters by Andrea Fioraldi + - Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ to implement AFL-style instrumentation and to take care of the remaining parts of the AFL fork server logic. - The resulting QEMU binary is essentially a standalone instrumentation + The resulting libunicorn binary is essentially a standalone instrumentation tool; for an example of how to leverage it for other purposes, you can have a look at afl-showmap.c. diff --git a/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h index 0019bbfa..1f0667ce 100644 --- a/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h +++ b/unicorn_mode/patches/afl-unicorn-tcg-runtime-inl.h @@ -1,17 +1,17 @@ /* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- + american fuzzy lop++ - unicorn instrumentation + ---------------------------------------------- - Written by Andrew Griffiths and - Michal Zalewski + Originally written by Andrew Griffiths and + Michal Zalewski - TCG instrumentation and block chaining support by Andrea Biondo - Adapted for afl-unicorn by Dominik Maier - Idea & design very much by Andrew Griffiths. + CompareCoverage and NeverZero counters by Andrea Fioraldi + - Copyright 2015, 2016 Google Inc. All rights reserved. + Copyright 2015, 2016, 2017 Google Inc. All rights reserved. + Copyright 2019 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ to implement AFL-style instrumentation and to take care of the remaining parts of the AFL fork server logic. - The resulting QEMU binary is essentially a standalone instrumentation + The resulting libunicorn binary is essentially a standalone instrumentation tool; for an example of how to leverage it for other purposes, you can have a look at afl-showmap.c. diff --git a/unicorn_mode/samples/compcov_x64/COMPILE.md b/unicorn_mode/samples/compcov_x64/COMPILE.md index db488d30..35de7ad8 100644 --- a/unicorn_mode/samples/compcov_x64/COMPILE.md +++ b/unicorn_mode/samples/compcov_x64/COMPILE.md @@ -1,5 +1,4 @@ -Compiling compcov_target.c -========================== +# Compiling compcov_target.c compcov_target.c was compiled without optimization, position-independent, and without standard libraries using the following command line: diff --git a/unicorn_mode/samples/compcov_x64/compcov_target.c b/unicorn_mode/samples/compcov_x64/compcov_target.c index 71b4cb0e..eb1205b1 100644 --- a/unicorn_mode/samples/compcov_x64/compcov_target.c +++ b/unicorn_mode/samples/compcov_x64/compcov_target.c @@ -7,7 +7,7 @@ * (0x00300000), so make sure that your Unicorn emulation of this * puts user data there. * - * Written by Nathan Voss + * Written by Andrea Fioraldi */ // Magic address where mutated data will be placed diff --git a/unicorn_mode/samples/simple/COMPILE.md b/unicorn_mode/samples/simple/COMPILE.md index bd4a66c6..f7bf5b50 100644 --- a/unicorn_mode/samples/simple/COMPILE.md +++ b/unicorn_mode/samples/simple/COMPILE.md @@ -1,5 +1,4 @@ -Compiling simple_target.c -========================== +# Compiling simple_target.c You shouldn't need to compile simple_target.c since a MIPS binary version is pre-built and shipped with afl-unicorn. This file documents how the binary @@ -38,4 +37,4 @@ mips-linux-gnu-gcc -o simple_target.elf simple_target.c -fPIC -O0 -nostdlib Note that the output of this is padded with nulls for 16-byte alignment. This is important when emulating it, as NOPs will be added after the return of main() -as necessary. \ No newline at end of file +as necessary. -- cgit 1.4.1 From eadd378f6c54a7e021985bca041d9642fff41034 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 30 Aug 2019 11:42:30 +0200 Subject: update changelog --- docs/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/ChangeLog b/docs/ChangeLog index 6d56d314..6d4c4792 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -26,6 +26,10 @@ Version ++2.53d (dev): afl never did), plus shows tuple content summary information now - fix building on *BSD (thanks to tobias.kortkamp for the patch) - small docu updates + - NeverZero counters for QEMU + - NeverZero counters for Unicorn + - CompareCoverage Unicorn + - Immediates-only instrumentation for CompareCoverage - ... your patch? :) -- cgit 1.4.1