diff options
27 files changed, 1058 insertions, 301 deletions
diff --git a/README.md b/README.md index 91f28118..c0a22e54 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,17 @@ For comparisons use the fuzzbench `aflplusplus` setup, or use `afl-clang-fast` with `AFL_LLVM_CMPLOG=1`. -## Major changes in afl++ 3.00 onwards: +## Major behaviour changes in afl++ 3.00 onwards: With afl++ 3.13-3.20 we introduce frida_mode (-O) to have an alternative for binary-only fuzzing. It is slower than Qemu mode but works on MacOS, Android, iOS etc. +With afl++ 3.14 we introduced the following changes from previous behaviours: + * afl-fuzz: deterministic fuzzing it not a default for -M main anymore + * afl-cmin/afl-showmap -i now descends into subdirectories (afl-cmin.bash + however does not) + With afl++ 3.10 we introduced the following changes from previous behaviours: * The '+' feature of the '-t' option now means to auto-calculate the timeout with the value given being the maximum timeout. The original meaning of @@ -38,7 +43,6 @@ With afl++ 3.10 we introduced the following changes from previous behaviours: With afl++ 3.00 we introduced changes that break some previous afl and afl++ behaviours and defaults: - * There are no llvm_mode and gcc_plugin subdirectories anymore and there is only one compiler: afl-cc. All previous compilers now symlink to this one. All instrumentation source code is now in the `instrumentation/` folder. @@ -572,8 +576,15 @@ to use afl-clang-lto as the compiler. You also have the option to generate a dictionary yourself, see [utils/libtokencap/README.md](utils/libtokencap/README.md). afl-fuzz has a variety of options that help to workaround target quirks like -specific locations for the input file (`-f`), not performing deterministic -fuzzing (`-d`) and many more. Check out `afl-fuzz -h`. +specific locations for the input file (`-f`), performing deterministic +fuzzing (`-D`) and many more. Check out `afl-fuzz -h`. + +We highly recommend that you set a memory limit for running the target with `-m` +which defines the maximum memory in MB. This prevents a potential +out-of-memory problem for your system plus helps you detect missing `malloc()` +failure handling in the target. +Play around with various -m values until you find one that safely works for all +your input seeds (if you have good ones and then double or quadrouple that. By default afl-fuzz never stops fuzzing. To terminate afl++ simply press Control-C or send a signal SIGINT. You can limit the number of executions or approximate runtime @@ -614,23 +625,28 @@ For every secondary fuzzer there should be a variation, e.g.: * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV (see above). Important note: If you run more than one laf-intel/COMPCOV fuzzer and you want them to share their intermediate results, the main - fuzzer (`-M`) must be one of the them! + fuzzer (`-M`) must be one of the them! (Although this is not really + recommended.) All other secondaries should be used like this: - * A third to a half with the MOpt mutator enabled: `-L 0` - * run with a different power schedule, available are: - `fast (default), explore, coe, lin, quad, exploit, mmopt, rare, seek` - which you can set with e.g. `-p seek` + * A quarter to a third with the MOpt mutator enabled: `-L 0` + * run with a different power schedule, recommended are: + `fast (default), explore, coe, lin, quad, exploit and rare` + which you can set with e.g. `-p explore` + * a few instances should use the old queue cycling with `-Z` Also it is recommended to set `export AFL_IMPORT_FIRST=1` to load testcases from other fuzzers in the campaign first. +If you have a large corpus, a corpus from a previous run or are fuzzing in +a CI, then also set `export AFL_CMPLOG_ONLY_NEW=1` and `export AFL_FAST_CAL=1`. + You can also use different fuzzers. If you are using afl spinoffs or afl conforming fuzzers, then just use the same -o directory and give it a unique `-S` name. Examples are: * [Eclipser](https://github.com/SoftSec-KAIST/Eclipser/) - * [Untracer](https://github.com/FoRTE-Research/UnTracer-AFL) + * [symcc](https://github.com/eurecom-s/symcc/) * [AFLsmart](https://github.com/aflsmart/aflsmart) * [FairFuzz](https://github.com/carolemieux/afl-rb) * [Neuzz](https://github.com/Dongdongshe/neuzz) @@ -638,9 +654,11 @@ Examples are: A long list can be found at [https://github.com/Microsvuln/Awesome-AFL](https://github.com/Microsvuln/Awesome-AFL) -However you can also sync afl++ with honggfuzz, libfuzzer with -entropic, etc. +However you can also sync afl++ with honggfuzz, libfuzzer with `-entropic=1`, etc. Just show the main fuzzer (-M) with the `-F` option where the queue/work directory of a different fuzzer is, e.g. `-F /src/target/honggfuzz`. +Using honggfuzz (with `-n 1` or `-n 2`) and libfuzzer in parallel is highly +recommended! #### c) The status of the fuzz campaign @@ -767,25 +785,26 @@ campaigns as these are much shorter runnings. corpus needs to be loaded. * `AFL_CMPLOG_ONLY_NEW` - only perform cmplog on new found paths, not the initial corpus as this very likely has been done for them already. - * Keep the generated corpus, use afl-cmin and reuse it everytime! + * Keep the generated corpus, use afl-cmin and reuse it every time! 2. Additionally randomize the afl++ compilation options, e.g. * 40% for `AFL_LLVM_CMPLOG` * 10% for `AFL_LLVM_LAF_ALL` 3. Also randomize the afl-fuzz runtime options, e.g. - * 60% for `AFL_DISABLE_TRIM` + * 65% for `AFL_DISABLE_TRIM` * 50% use a dictionary generated by `AFL_LLVM_DICT2FILE` - * 50% use MOpt (`-L 0`) + * 40% use MOpt (`-L 0`) * 40% for `AFL_EXPAND_HAVOC_NOW` - * 30% for old queue processing (`-Z`) + * 20% for old queue processing (`-Z`) * for CMPLOG targets, 60% for `-l 2`, 40% for `-l 3` 4. Do *not* run any `-M` modes, just running `-S` modes is better for CI fuzzing. - `-M` enables deterministic fuzzing, old queue handling etc. which is good for - a fuzzing campaign but not good for short CI runs. + `-M` enables old queue handling etc. which is good for a fuzzing campaign but + not good for short CI runs. -How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz](https://github.com/google/oss-fuzz/blob/4bb61df7905c6005000f5766e966e6fe30ab4559/infra/base-images/base-builder/compile_afl#L69). +How this can look like can e.g. be seen at afl++'s setup in Google's [oss-fuzz](https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/compile_afl) +and [clusterfuzz](https://github.com/google/clusterfuzz/blob/master/src/python/bot/fuzzers/afl/launcher.py). ## Fuzzing binary-only targets diff --git a/TODO.md b/TODO.md index 398f3d11..1c616b4a 100644 --- a/TODO.md +++ b/TODO.md @@ -2,13 +2,11 @@ ## Roadmap 3.00+ - - align map to 64 bytes but keep real IDs - Update afl->pending_not_fuzzed for MOpt - put fuzz target in top line of UI - afl-plot to support multiple plot_data - afl_custom_fuzz_splice_optin() - afl_custom_splice() - - intel-pt tracer - better autodetection of shifting runtime timeout values - cmplog: use colorization input for havoc? - parallel builds for source-only targets diff --git a/afl-cmin b/afl-cmin index 9fa63ec6..e71873d3 100755 --- a/afl-cmin +++ b/afl-cmin @@ -296,13 +296,13 @@ BEGIN { exit 1 } - if (0 == system( "test -d "in_dir"/default" )) { - in_dir = in_dir "/default" - } - - if (0 == system( "test -d "in_dir"/queue" )) { - in_dir = in_dir "/queue" - } + #if (0 == system( "test -d "in_dir"/default" )) { + # in_dir = in_dir "/default" + #} + # + #if (0 == system( "test -d "in_dir"/queue" )) { + # in_dir = in_dir "/queue" + #} system("rm -rf "trace_dir" 2>/dev/null"); system("rm "out_dir"/id[:_]* 2>/dev/null") @@ -355,30 +355,35 @@ BEGIN { } else { stat_format = "-f '%z %N'" # *BSD, MacOS } - cmdline = "(cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)" + cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)" #cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r" while (cmdline | getline) { sub(/^[0-9]+ (\.\/)?/,"",$0) - infilesSmallToBig[i++] = $0 + infilesSmallToBigFull[i] = $0 + sub(/.*\//, "", $0) + infilesSmallToBig[i] = $0 + infilesSmallToBigMap[infilesSmallToBig[i]] = infilesSmallToBigFull[i] + infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i] + i++ } in_count = i - first_file = infilesSmallToBig[0] + first_file = infilesSmallToBigFull[0] - # Make sure that we're not dealing with a directory. - - if (0 == system("test -d ""\""in_dir"/"first_file"\"")) { - print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr" - exit 1 - } + #if (0 == system("test -d ""\""in_dir"/"first_file"\"")) { + # print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr" + # exit 1 + #} - if (0 == system("ln \""in_dir"/"first_file"\" "trace_dir"/.link_test")) { + system(">\""in_dir"/.afl-cmin.test\"") + if (0 == system("ln \""in_dir"/.afl-cmin.test\" "trace_dir"/.link_test")) { cp_tool = "ln" } else { cp_tool = "cp" } + system("rm -f \""in_dir"/.afl-cmin.test\"") if (!ENVIRON["AFL_SKIP_BIN_CHECK"]) { # Make sure that we can actually get anything out of afl-showmap before we @@ -511,7 +516,8 @@ BEGIN { # copy file unless already done if (! (fn in file_already_copied)) { - system(cp_tool" \""in_dir"/"fn"\" \""out_dir"/"fn"\"") + realfile = infilesSmallToBigMap[fn] + system(cp_tool" \""in_dir"/"realfile"\" \""out_dir"/"fn"\"") file_already_copied[fn] = "" ++out_count #printf "tuple nr %d (%d cnt=%d) -> %s\n",tcnt,key,key_count[key],fn > trace_dir"/.log" diff --git a/docs/Changelog.md b/docs/Changelog.md index 9f70535a..475240c2 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,6 +16,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. - if the target becomes unavailable check out out/default/error.txt for an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL + - reverse read the queue on resumes (more effective) - afl-cc: - Update to COMPCOV/laf-intel that speeds up the instrumentation process a lot - thanks to Michael Rodler/f0rki for the PR! @@ -24,10 +25,14 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. - support partial linking - We do support llvm versions from 3.8 to 5.0 again - frida_mode: - - fix for cmplog + - several fixes for cmplog - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET - feature parity of aarch64 with intel now (persistent, cmplog, in-memory testcases, asan) + - qemu_mode: + - performance fix when cmplog was used + - afl-cmin and afl-showmap -i do now descend into subdirectories + (like afl-fuzz does) - note that afl-cmin.bash does not! - afl_analyze: - fix timeout handling - add forkserver support for better performance diff --git a/docs/parallel_fuzzing.md b/docs/parallel_fuzzing.md index 8f2afe1b..23872899 100644 --- a/docs/parallel_fuzzing.md +++ b/docs/parallel_fuzzing.md @@ -1,7 +1,11 @@ # Tips for parallel fuzzing - This document talks about synchronizing afl-fuzz jobs on a single machine - or across a fleet of systems. See README.md for the general instruction manual. +This document talks about synchronizing afl-fuzz jobs on a single machine +or across a fleet of systems. See README.md for the general instruction manual. + +Note that this document is rather outdated. please refer to the main document +section on multiple core usage [../README.md#Using multiple cores](../README.md#b-using-multiple-coresthreads) +for up to date strategies! ## 1) Introduction diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index 329d9f7f..2f637412 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -25,8 +25,7 @@ RT_CFLAGS:=-Wno-unused-parameter \ LDFLAGS+=-shared \ -lpthread \ -lresolv \ - -ldl \ - -z noexecstack \ + -ldl ifdef DEBUG CFLAGS+=-Werror \ @@ -60,6 +59,7 @@ else ifdef DEBUG RT_CFLAGS:=$(RT_CFLAGS) -Wno-prio-ctor-dtor endif +LDFLAGS+=-z noexecstack endif ifeq "$(shell uname)" "Linux" diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c index 3df7d13d..0e3fbe53 100644 --- a/frida_mode/src/cmplog/cmplog.c +++ b/frida_mode/src/cmplog/cmplog.c @@ -1,7 +1,9 @@ #include <errno.h> #include <fcntl.h> #include <limits.h> -#include <syscall.h> +#include <sys/mman.h> +#include <sys/syscall.h> +#include <unistd.h> #include "frida-gum.h" @@ -10,18 +12,21 @@ #include "util.h" #define DEFAULT_MMAP_MIN_ADDR (32UL << 10) -#define FD_TMP_MAX_SIZE 65536 +#define MAX_MEMFD_SIZE (64UL << 10) extern struct cmp_map *__afl_cmp_map; +static GArray * cmplog_ranges = NULL; +static GHashTable * hash_yes = NULL; +static GHashTable * hash_no = NULL; -static GArray *cmplog_ranges = NULL; -static int fd_tmp = -1; -static ssize_t fd_tmp_size = 0; +static long page_size = 0; +static long page_offset_mask = 0; +static long page_mask = 0; static gboolean cmplog_range(const GumRangeDetails *details, gpointer user_data) { - UNUSED_PARAMETER(user_data); + GArray * cmplog_ranges = (GArray *)user_data; GumMemoryRange range = *details->range; g_array_append_val(cmplog_ranges, range); return TRUE; @@ -35,54 +40,46 @@ static gint cmplog_sort(gconstpointer a, gconstpointer b) { } -static int cmplog_create_temp(void) { +static void cmplog_get_ranges(void) { - const char *tmpdir = g_get_tmp_dir(); - OKF("CMPLOG Temporary directory: %s", tmpdir); - gchar *fname = g_strdup_printf("%s/frida-cmplog-XXXXXX", tmpdir); - OKF("CMPLOG Temporary file template: %s", fname); - int fd = mkstemp(fname); - OKF("CMPLOG Temporary file: %s", fname); + OKF("CMPLOG - Collecting ranges"); - if (fd < 0) { - - FATAL("Failed to create temp file: %s, errno: %d", fname, errno); + cmplog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100); + gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, cmplog_ranges); + g_array_sort(cmplog_ranges, cmplog_sort); - } +} - if (unlink(fname) < 0) { +void cmplog_init(void) { - FATAL("Failed to unlink temp file: %s (%d), errno: %d", fname, fd, errno); + if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); } - } + cmplog_get_ranges(); - if (ftruncate(fd, 0) < 0) { + for (guint i = 0; i < cmplog_ranges->len; i++) { - FATAL("Failed to ftruncate temp file: %s (%d), errno: %d", fname, fd, - errno); + GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); + OKF("CMPLOG Range - %3u: 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X", + i, range->base_address, range->base_address + range->size); } - g_free(fname); + page_size = sysconf(_SC_PAGE_SIZE); + page_offset_mask = page_size - 1; + page_mask = ~(page_offset_mask); - return fd; - -} + hash_yes = g_hash_table_new(g_direct_hash, g_direct_equal); + if (hash_yes == NULL) { -void cmplog_init(void) { - - if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); } + FATAL("Failed to g_hash_table_new, errno: %d", errno); - cmplog_ranges = g_array_sized_new(false, false, sizeof(GumMemoryRange), 100); - gum_process_enumerate_ranges(GUM_PAGE_READ, cmplog_range, NULL); - g_array_sort(cmplog_ranges, cmplog_sort); + } - for (guint i = 0; i < cmplog_ranges->len; i++) { + hash_no = g_hash_table_new(g_direct_hash, g_direct_equal); + if (hash_no == NULL) { - GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); - OKF("CMPLOG Range - 0x%016" G_GINT64_MODIFIER "X - 0x%016" G_GINT64_MODIFIER - "X", - range->base_address, range->base_address + range->size); + FATAL("Failed to g_hash_table_new, errno: %d", errno); } @@ -102,6 +99,45 @@ static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit, } +gboolean cmplog_test_addr(guint64 addr, size_t size) { + + if (g_hash_table_contains(hash_yes, (gpointer)addr)) { return true; } + if (g_hash_table_contains(hash_no, (gpointer)addr)) { return false; } + + void * page_addr = (void *)(addr & page_mask); + size_t page_offset = addr & page_offset_mask; + + /* If it spans a page, then bail */ + if (page_size - page_offset < size) { return false; } + + /* + * Our address map can change (e.g. stack growth), use msync as a fallback to + * validate our address. + */ + if (msync(page_addr, page_offset + size, MS_ASYNC) < 0) { + + if (!g_hash_table_add(hash_no, (gpointer)addr)) { + + FATAL("Failed - g_hash_table_add"); + + } + + return false; + + } else { + + if (!g_hash_table_add(hash_yes, (gpointer)addr)) { + + FATAL("Failed - g_hash_table_add"); + + } + + return true; + + } + +} + gboolean cmplog_is_readable(guint64 addr, size_t size) { if (cmplog_ranges == NULL) FATAL("CMPLOG not initialized"); @@ -125,45 +161,16 @@ gboolean cmplog_is_readable(guint64 addr, size_t size) { for (guint i = 0; i < cmplog_ranges->len; i++) { GumMemoryRange *range = &g_array_index(cmplog_ranges, GumMemoryRange, i); - GumAddress outer_base = range->base_address; - GumAddress outer_limit = outer_base + range->size; + + GumAddress outer_base = range->base_address; + GumAddress outer_limit = outer_base + range->size; if (cmplog_contains(inner_base, inner_limit, outer_base, outer_limit)) return true; } - /* - * Our address map can change (e.g. stack growth), use write as a fallback to - * validate our address. - */ - ssize_t written = syscall(__NR_write, fd_tmp, (void *)addr, size); - - /* - * If the write succeeds, then the buffer must be valid otherwise it would - * return EFAULT - */ - if (written > 0) { - - fd_tmp_size += written; - if (fd_tmp_size > FD_TMP_MAX_SIZE) { - - /* - * Truncate the file, we don't want our temp file to continue growing! - */ - if (ftruncate(fd_tmp, 0) < 0) { - - FATAL("Failed to truncate fd_tmp (%d), errno: %d", fd_tmp, errno); - - } - - fd_tmp_size = 0; - - } - - if ((size_t)written == size) { return true; } - - } + if (cmplog_test_addr(addr, size)) { return true; } return false; diff --git a/frida_mode/src/cmplog/cmplog_x64.c b/frida_mode/src/cmplog/cmplog_x64.c index 9f56c32a..ba16445d 100644 --- a/frida_mode/src/cmplog/cmplog_x64.c +++ b/frida_mode/src/cmplog/cmplog_x64.c @@ -177,7 +177,7 @@ static void cmplog_handle_cmp_sub(GumCpuContext *context, gsize operand1, register uintptr_t k = (uintptr_t)address; k = (k >> 4) ^ (k << 8); - k &= CMP_MAP_W - 1; + k &= CMP_MAP_W - 7; __afl_cmp_map->headers[k].type = CMP_TYPE_INS; @@ -198,8 +198,6 @@ static void cmplog_cmp_sub_callout(GumCpuContext *context, gpointer user_data) { gsize operand1; gsize operand2; - if (ctx->operand1.size != ctx->operand2.size) FATAL("Operand size mismatch"); - if (!cmplog_get_operand_value(context, &ctx->operand1, &operand1)) { return; } if (!cmplog_get_operand_value(context, &ctx->operand2, &operand2)) { return; } @@ -233,6 +231,15 @@ static void cmplog_instrument_cmp_sub(const cs_insn * instr, case X86_INS_CMP: case X86_INS_SUB: + case X86_INS_SCASB: + case X86_INS_SCASD: + case X86_INS_SCASQ: + case X86_INS_SCASW: + case X86_INS_CMPSB: + case X86_INS_CMPSD: + case X86_INS_CMPSQ: + case X86_INS_CMPSS: + case X86_INS_CMPSW: break; default: return; @@ -247,13 +254,8 @@ static void cmplog_instrument_cmp_sub(const cs_insn * instr, if (operand1->type == X86_OP_INVALID) return; if (operand2->type == X86_OP_INVALID) return; - if ((operand1->type == X86_OP_MEM) && - (operand1->mem.segment != X86_REG_INVALID)) - return; - - if ((operand2->type == X86_OP_MEM) && - (operand2->mem.segment != X86_REG_INVALID)) - return; + /* Both operands are the same size */ + if (operand1->size == 1) { return; } cmplog_instrument_cmp_sub_put_callout(iterator, operand1, operand2); diff --git a/frida_mode/src/ctx/ctx_x64.c b/frida_mode/src/ctx/ctx_x64.c index c5900533..1772a252 100644 --- a/frida_mode/src/ctx/ctx_x64.c +++ b/frida_mode/src/ctx/ctx_x64.c @@ -49,9 +49,18 @@ gsize ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg) { X86_REG_8L(X86_REG_BL, ctx->rbx) X86_REG_8L(X86_REG_CL, ctx->rcx) X86_REG_8L(X86_REG_DL, ctx->rdx) + X86_REG_8L(X86_REG_SPL, ctx->rsp) X86_REG_8L(X86_REG_BPL, ctx->rbp) X86_REG_8L(X86_REG_SIL, ctx->rsi) X86_REG_8L(X86_REG_DIL, ctx->rdi) + X86_REG_8L(X86_REG_R8B, ctx->r8) + X86_REG_8L(X86_REG_R9B, ctx->r9) + X86_REG_8L(X86_REG_R10B, ctx->r10) + X86_REG_8L(X86_REG_R11B, ctx->r11) + X86_REG_8L(X86_REG_R12B, ctx->r12) + X86_REG_8L(X86_REG_R13B, ctx->r13) + X86_REG_8L(X86_REG_R14B, ctx->r14) + X86_REG_8L(X86_REG_R15B, ctx->r15) X86_REG_8H(X86_REG_AH, ctx->rax) X86_REG_8H(X86_REG_BH, ctx->rbx) @@ -62,14 +71,23 @@ gsize ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg) { X86_REG_16(X86_REG_BX, ctx->rbx) X86_REG_16(X86_REG_CX, ctx->rcx) X86_REG_16(X86_REG_DX, ctx->rdx) + X86_REG_16(X86_REG_SP, ctx->rsp) + X86_REG_16(X86_REG_BP, ctx->rbp) X86_REG_16(X86_REG_DI, ctx->rdi) X86_REG_16(X86_REG_SI, ctx->rsi) - X86_REG_16(X86_REG_BP, ctx->rbp) + X86_REG_16(X86_REG_R8W, ctx->r8) + X86_REG_16(X86_REG_R9W, ctx->r9) + X86_REG_16(X86_REG_R10W, ctx->r10) + X86_REG_16(X86_REG_R11W, ctx->r11) + X86_REG_16(X86_REG_R12W, ctx->r12) + X86_REG_16(X86_REG_R13W, ctx->r13) + X86_REG_16(X86_REG_R14W, ctx->r14) + X86_REG_16(X86_REG_R15W, ctx->r15) X86_REG_32(X86_REG_EAX, ctx->rax) + X86_REG_32(X86_REG_EBX, ctx->rbx) X86_REG_32(X86_REG_ECX, ctx->rcx) X86_REG_32(X86_REG_EDX, ctx->rdx) - X86_REG_32(X86_REG_EBX, ctx->rbx) X86_REG_32(X86_REG_ESP, ctx->rsp) X86_REG_32(X86_REG_EBP, ctx->rbp) X86_REG_32(X86_REG_ESI, ctx->rsi) diff --git a/frida_mode/src/ctx/ctx_x86.c b/frida_mode/src/ctx/ctx_x86.c index 45308272..9b50cb52 100644 --- a/frida_mode/src/ctx/ctx_x86.c +++ b/frida_mode/src/ctx/ctx_x86.c @@ -42,6 +42,7 @@ gsize ctx_read_reg(GumIA32CpuContext *ctx, x86_reg reg) { X86_REG_8L(X86_REG_BL, ctx->ebx) X86_REG_8L(X86_REG_CL, ctx->ecx) X86_REG_8L(X86_REG_DL, ctx->edx) + X86_REG_8L(X86_REG_SPL, ctx->esp) X86_REG_8L(X86_REG_BPL, ctx->ebp) X86_REG_8L(X86_REG_SIL, ctx->esi) X86_REG_8L(X86_REG_DIL, ctx->edi) @@ -55,14 +56,15 @@ gsize ctx_read_reg(GumIA32CpuContext *ctx, x86_reg reg) { X86_REG_16(X86_REG_BX, ctx->ebx) X86_REG_16(X86_REG_CX, ctx->ecx) X86_REG_16(X86_REG_DX, ctx->edx) + X86_REG_16(X86_REG_SP, ctx->esp) + X86_REG_16(X86_REG_BP, ctx->ebp) X86_REG_16(X86_REG_DI, ctx->edi) X86_REG_16(X86_REG_SI, ctx->esi) - X86_REG_16(X86_REG_BP, ctx->ebp) X86_REG_32(X86_REG_EAX, ctx->eax) + X86_REG_32(X86_REG_EBX, ctx->ebx) X86_REG_32(X86_REG_ECX, ctx->ecx) X86_REG_32(X86_REG_EDX, ctx->edx) - X86_REG_32(X86_REG_EBX, ctx->ebx) X86_REG_32(X86_REG_ESP, ctx->esp) X86_REG_32(X86_REG_EBP, ctx->ebp) X86_REG_32(X86_REG_ESI, ctx->esi) diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 7ff23755..b17d9f49 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -101,7 +101,8 @@ static void afl_print_cmdline(void) { if (fd < 0) { - FATAL("Failed to open /proc/self/cmdline, errno: (%d)", errno); + WARNF("Failed to open /proc/self/cmdline, errno: (%d)", errno); + return; } @@ -138,7 +139,8 @@ static void afl_print_env(void) { if (fd < 0) { - FATAL("Failed to open /proc/self/cmdline, errno: (%d)", errno); + WARNF("Failed to open /proc/self/cmdline, errno: (%d)", errno); + return; } diff --git a/frida_mode/test/jpeg/GNUmakefile b/frida_mode/test/jpeg/GNUmakefile new file mode 100644 index 00000000..689fce3d --- /dev/null +++ b/frida_mode/test/jpeg/GNUmakefile @@ -0,0 +1,172 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c +AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so + +LIBJPEG_BUILD_DIR:=$(BUILD_DIR)libjpeg/ +HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ +JPEGTEST_BUILD_DIR:=$(BUILD_DIR)jpegtest/ + +LIBJPEG_URL:=https://github.com/libjpeg-turbo/libjpeg-turbo.git +LIBJPEG_DIR:=$(LIBJPEG_BUILD_DIR)libjpeg/ +LIBJPEG_CONFIGURE:=$(LIBJPEG_DIR)configure.ac +LIBJPEG_MAKEFILE:=$(LIBJPEG_DIR)Makefile +LIBJPEG_LIB:=$(LIBJPEG_DIR).libs/libturbojpeg.a + +HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/stable/utils/aflpp_driver/aflpp_qemu_driver.c" + +JPEGTEST_FILE:=$(JPEGTEST_BUILD_DIR)target.cc +JPEGTEST_OBJ:=$(JPEGTEST_BUILD_DIR)target.o +JPEGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmarks/libjpeg-turbo-07-2017/libjpeg_turbo_fuzzer.cc" + +LDFLAGS += -lpthread + +TEST_BIN:=$(BUILD_DIR)test +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +endif + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +TEST_DATA_FILE:=$(TEST_DATA_DIR)default_seed + +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) +endif + +.PHONY: all clean frida hook + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +32: + CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +######### HARNESS ######## +$(HARNESS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(HARNESS_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $< + +######### JPEGTEST ######## + +$(JPEGTEST_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(JPEGTEST_FILE): | $(JPEGTEST_BUILD_DIR) + wget -O $@ $(JPEGTEST_URL) + +$(JPEGTEST_OBJ): $(JPEGTEST_FILE) | $(LIBJPEG_MAKEFILE) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -std=c++11 -I $(LIBJPEG_DIR) -o $@ -c $< + +######### LIBJPEG ######## + +$(LIBJPEG_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(LIBJPEG_CONFIGURE): $(LIBJPEG_BUILD_DIR) + git clone $(LIBJPEG_URL) $(LIBJPEG_DIR) + cd $(LIBJPEG_DIR) && git checkout b0971e47d76fdb81270e93bbf11ff5558073350d + +$(LIBJPEG_MAKEFILE): $(LIBJPEG_CONFIGURE) + cd $(LIBJPEG_DIR) && autoreconf -fiv + cd $(LIBJPEG_DIR) && ./configure + +$(LIBJPEG_LIB): $(LIBJPEG_MAKEFILE) + make -C $(LIBJPEG_DIR) -j $(shell nproc) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(JPEGTEST_OBJ) $(LIBJPEG_LIB) + $(CXX) \ + $(CFLAGS) \ + -o $@ \ + $(HARNESS_OBJ) $(JPEGTEST_OBJ) $(LIBJPEG_LIB) \ + -lz \ + $(LDFLAGS) \ + $(TEST_BIN_LDFLAGS) \ + +########## HOOK ######## + +$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) + $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ + +########## DUMMY ####### + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TEST_DATA_FILE): | $(TEST_DATA_DIR) + echo "hi" > $(TEST_DATA_FILE) + +###### TEST DATA ####### + +hook: $(AFLPP_DRIVER_HOOK_OBJ) + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(TEST_DATA_FILE) + AFL_DEBUG_CHILD=1 \ + AFL_DISABLE_TRIM=1 \ + AFL_FRIDA_PERSISTENT_CNT=1000000 \ + AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ + AFL_NO_AFFINITY=1 \ + X__AFL_NO_UI=1 \ + AFL_PATH=/out \ + AFL_SHUFFLE_QUEUE=1 \ + AFL_SKIP_CPUFREQ=1 \ + AFL_SKIP_CRASHES=1 \ + AFL_TESTCACHE_SIZE=2 \ + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -m none \ + -t 1000+ \ + -d \ + -O \ + -c 0\ + -V 30 \ + -- \ + $(TEST_BIN) 2147483647 + +debug: + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TEST_BIN) $(TEST_DATA_DIR)basn0g01.jpeg diff --git a/frida_mode/test/jpeg/Makefile b/frida_mode/test/jpeg/Makefile new file mode 100644 index 00000000..863438cf --- /dev/null +++ b/frida_mode/test/jpeg/Makefile @@ -0,0 +1,19 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida + +debug: + @gmake debug + +hook: + @gmake hook diff --git a/frida_mode/test/jpeg/aflpp_qemu_driver_hook.c b/frida_mode/test/jpeg/aflpp_qemu_driver_hook.c new file mode 100644 index 00000000..059d438d --- /dev/null +++ b/frida_mode/test/jpeg/aflpp_qemu_driver_hook.c @@ -0,0 +1,97 @@ +#include <stdint.h> +#include <string.h> + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + +} + +#elif defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + void **esp = (void **)regs->esp; + void * arg1 = esp[1]; + void **arg2 = &esp[2]; + memcpy(arg1, input_buf, input_buf_len); + *arg2 = (void *)input_buf_len; + +} + +#else + #pragma error "Unsupported architecture" +#endif + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/frida_mode/test/jpeg/get_symbol_addr.py b/frida_mode/test/jpeg/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/jpeg/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/frida_mode/test/proj4/GNUmakefile b/frida_mode/test/proj4/GNUmakefile new file mode 100644 index 00000000..09112cd5 --- /dev/null +++ b/frida_mode/test/proj4/GNUmakefile @@ -0,0 +1,172 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c +AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so + +LIBPROJ4_BUILD_DIR:=$(BUILD_DIR)libproj4/ +HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ +PROJ4TEST_BUILD_DIR:=$(BUILD_DIR)proj4test/ + +LIBPROJ4_URL:=https://github.com/OSGeo/PROJ +LIBPROJ4_DIR:=$(LIBPROJ4_BUILD_DIR)libproj4/ +LIBPROJ4_CONFIGURE:=$(LIBPROJ4_DIR)configure.ac +LIBPROJ4_MAKEFILE:=$(LIBPROJ4_DIR)Makefile +LIBPROJ4_LIB:=$(LIBPROJ4_DIR)src/.libs/libproj.a + +HARNESS_FILE:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(HARNESS_BUILD_DIR)StandaloneFuzzTargetMain.o +HARNESS_URL:="https://raw.githubusercontent.com/AFLplusplus/AFLplusplus/stable/utils/aflpp_driver/aflpp_qemu_driver.c" + +PROJ4TEST_FILE:=$(PROJ4TEST_BUILD_DIR)target.cc +PROJ4TEST_OBJ:=$(PROJ4TEST_BUILD_DIR)target.o +PROJ4TEST_URL:="https://raw.githubusercontent.com/OSGeo/PROJ/d00501750b210a73f9fb107ac97a683d4e3d8e7a/test/fuzzers/standard_fuzzer.cpp" + +LDFLAGS += -lpthread + +TEST_BIN:=$(BUILD_DIR)test +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +endif + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +TEST_DATA_FILE:=$(TEST_DATA_DIR)default_seed + +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ifeq "$(ARCH)" "aarch64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) +endif + +.PHONY: all clean frida hook + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +32: + CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +######### HARNESS ######## +$(HARNESS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(HARNESS_FILE): | $(HARNESS_BUILD_DIR) + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_FILE) + $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $< + +######### PROJ4TEST ######## + +$(PROJ4TEST_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(PROJ4TEST_FILE): | $(PROJ4TEST_BUILD_DIR) + wget -O $@ $(PROJ4TEST_URL) + +$(PROJ4TEST_OBJ): $(PROJ4TEST_FILE) | $(LIBPROJ4_MAKEFILE) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -std=c++11 -I $(LIBPROJ4_DIR)src/ -o $@ -c $< + +######### LIBPROJ4 ######## + +$(LIBPROJ4_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(LIBPROJ4_CONFIGURE): $(LIBPROJ4_BUILD_DIR) + git clone $(LIBPROJ4_URL) $(LIBPROJ4_DIR) + cd $(LIBPROJ4_DIR) && git checkout d00501750b210a73f9fb107ac97a683d4e3d8e7a + +$(LIBPROJ4_MAKEFILE): $(LIBPROJ4_CONFIGURE) + cd $(LIBPROJ4_DIR) && ./autogen.sh + cd $(LIBPROJ4_DIR) && ./configure + +$(LIBPROJ4_LIB): $(LIBPROJ4_MAKEFILE) + make -C $(LIBPROJ4_DIR) -j $(shell nproc) + +######### TEST ######## + +$(TEST_BIN): $(HARNESS_OBJ) $(PROJ4TEST_OBJ) $(LIBPROJ4_LIB) + $(CXX) \ + $(CFLAGS) \ + -o $@ \ + $(HARNESS_OBJ) $(PROJ4TEST_OBJ) $(LIBPROJ4_LIB) \ + -lz \ + $(LDFLAGS) \ + $(TEST_BIN_LDFLAGS) \ + +########## HOOK ######## + +$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) + $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ + +########## DUMMY ####### + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TEST_DATA_FILE): | $(TEST_DATA_DIR) + echo "hi" > $(TEST_DATA_FILE) + +###### TEST DATA ####### + +hook: $(AFLPP_DRIVER_HOOK_OBJ) + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TEST_BIN) $(AFLPP_DRIVER_HOOK_OBJ) $(TEST_DATA_FILE) + AFL_DEBUG_CHILD=1 \ + AFL_DISABLE_TRIM=1 \ + AFL_FRIDA_PERSISTENT_CNT=1000000 \ + AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ + AFL_NO_AFFINITY=1 \ + X__AFL_NO_UI=1 \ + AFL_PATH=/out \ + AFL_SHUFFLE_QUEUE=1 \ + AFL_SKIP_CPUFREQ=1 \ + AFL_SKIP_CRASHES=1 \ + AFL_TESTCACHE_SIZE=2 \ + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -m none \ + -t 1000+ \ + -d \ + -O \ + -c 0\ + -V 30 \ + -- \ + $(TEST_BIN) 2147483647 + +debug: + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TEST_BIN) $(TEST_DATA_DIR)basn0g01.proj4 diff --git a/frida_mode/test/proj4/Makefile b/frida_mode/test/proj4/Makefile new file mode 100644 index 00000000..863438cf --- /dev/null +++ b/frida_mode/test/proj4/Makefile @@ -0,0 +1,19 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida + +debug: + @gmake debug + +hook: + @gmake hook diff --git a/frida_mode/test/proj4/aflpp_qemu_driver_hook.c b/frida_mode/test/proj4/aflpp_qemu_driver_hook.c new file mode 100644 index 00000000..059d438d --- /dev/null +++ b/frida_mode/test/proj4/aflpp_qemu_driver_hook.c @@ -0,0 +1,97 @@ +#include <stdint.h> +#include <string.h> + +#if defined(__x86_64__) + +struct x86_64_regs { + + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, + r15; + + union { + + uint64_t rip; + uint64_t pc; + + }; + + union { + + uint64_t rsp; + uint64_t sp; + + }; + + union { + + uint64_t rflags; + uint64_t flags; + + }; + + uint8_t zmm_regs[32][64]; + +}; + +void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + +} + +#elif defined(__i386__) + +struct x86_regs { + + uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + + union { + + uint32_t eip; + uint32_t pc; + + }; + + union { + + uint32_t esp; + uint32_t sp; + + }; + + union { + + uint32_t eflags; + uint32_t flags; + + }; + + uint8_t xmm_regs[8][16]; + +}; + +void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, + uint8_t *input_buf, uint32_t input_buf_len) { + + void **esp = (void **)regs->esp; + void * arg1 = esp[1]; + void **arg2 = &esp[2]; + memcpy(arg1, input_buf, input_buf_len); + *arg2 = (void *)input_buf_len; + +} + +#else + #pragma error "Unsupported architecture" +#endif + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/frida_mode/test/proj4/get_symbol_addr.py b/frida_mode/test/proj4/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/proj4/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +import argparse +from elftools.elf.elffile import ELFFile + +def process_file(file, symbol, base): + with open(file, 'rb') as f: + elf = ELFFile(f) + symtab = elf.get_section_by_name('.symtab') + mains = symtab.get_symbol_by_name(symbol) + if len(mains) != 1: + print ("Failed to find main") + return 1 + + main_addr = mains[0]['st_value'] + main = base + main_addr + print ("0x%016x" % main) + return 0 + +def hex_value(x): + return int(x, 16) + +def main(): + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('-f', '--file', dest='file', type=str, + help='elf file name', required=True) + parser.add_argument('-s', '--symbol', dest='symbol', type=str, + help='symbol name', required=True) + parser.add_argument('-b', '--base', dest='base', type=hex_value, + help='elf base address', required=True) + + args = parser.parse_args() + return process_file (args.file, args.symbol, args.base) + +if __name__ == "__main__": + ret = main() + exit(ret) diff --git a/include/forkserver.h b/include/forkserver.h index 2baa6f0a..c6f7de00 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -54,6 +54,7 @@ typedef struct afl_forkserver { u32 exec_tmout; /* Configurable exec timeout (ms) */ u32 init_tmout; /* Configurable init timeout (ms) */ u32 map_size; /* map size used by the target */ + u32 real_map_size; /* real map size, unaligned */ u32 snapshot; /* is snapshot feature used */ u64 mem_limit; /* Memory cap for child (MB) */ diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 50117012..d4529e2c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -271,12 +271,6 @@ static void __afl_map_shm(void) { if (__afl_final_loc) { - if (__afl_final_loc % 64) { - - __afl_final_loc = (((__afl_final_loc + 63) >> 6) << 6); - - } - __afl_map_size = __afl_final_loc; if (__afl_final_loc > MAP_SIZE) { @@ -623,6 +617,7 @@ static void __afl_unmap_shm(void) { #endif __afl_cmp_map = NULL; + __afl_cmp_map_backup = NULL; } @@ -1019,7 +1014,7 @@ static void __afl_start_forkserver(void) { if (read(FORKSRV_FD, &was_killed, 4) != 4) { - write_error("read from afl-fuzz"); + //write_error("read from afl-fuzz"); _exit(1); } @@ -1690,7 +1685,7 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr, void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (k >> 4) ^ (k << 8); @@ -1794,7 +1789,7 @@ void __sanitizer_cov_trace_const_cmp16(uint128_t arg1, uint128_t arg2) { void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; for (uint64_t i = 0; i < cases[0]; i++) { @@ -1891,7 +1886,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { fprintf(stderr, "\n"); */ - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2); int l1, l2; if ((l1 = area_is_valid(ptr1, 32)) <= 0 || @@ -1975,7 +1970,7 @@ static u8 *get_llvm_stdstring(u8 *string) { void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) return; @@ -1985,7 +1980,7 @@ void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; @@ -1996,7 +1991,7 @@ void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) return; @@ -2006,7 +2001,7 @@ void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; @@ -2040,7 +2035,7 @@ void __afl_coverage_on() { if (likely(__afl_selective_coverage && __afl_selective_coverage_temp)) { __afl_area_ptr = __afl_area_ptr_backup; - __afl_cmp_map = __afl_cmp_map_backup; + if (__afl_cmp_map_backup) { __afl_cmp_map = __afl_cmp_map_backup; } } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 3d472b36..5e8fb9b5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -90,6 +90,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { /* exec related stuff */ fsrv->child_pid = -1; fsrv->map_size = get_map_size(); + fsrv->real_map_size = fsrv->map_size; fsrv->use_fauxsrv = false; fsrv->last_run_timed_out = false; fsrv->debug = false; @@ -110,6 +111,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { fsrv_to->init_tmout = from->init_tmout; fsrv_to->mem_limit = from->mem_limit; fsrv_to->map_size = from->map_size; + fsrv_to->real_map_size = from->real_map_size; fsrv_to->support_shmem_fuzz = from->support_shmem_fuzz; fsrv_to->out_file = from->out_file; fsrv_to->dev_urandom_fd = from->dev_urandom_fd; @@ -416,8 +418,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, struct rlimit r; - if (!fsrv->cmplog_binary && fsrv->qemu_mode == false && - fsrv->frida_mode == false) { + if (!fsrv->cmplog_binary) { unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv @@ -691,15 +692,15 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } - if (unlikely(tmp_map_size % 64)) { + fsrv->real_map_size = tmp_map_size; + + if (tmp_map_size % 64) { - // should not happen - WARNF("Target reported non-aligned map size of %u", tmp_map_size); tmp_map_size = (((tmp_map_size + 63) >> 6) << 6); } - if (!be_quiet) { ACTF("Target map size: %u", tmp_map_size); } + if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); } if (tmp_map_size > fsrv->map_size) { FATAL( diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index c2e9c80f..c684c4b0 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -33,7 +33,7 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); - if (fsrv->qemu_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); } + if (fsrv->qemu_mode || fsrv->frida_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); } if (!fsrv->qemu_mode && !fsrv->frida_mode && argv[0] != fsrv->cmplog_binary) { diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 872e3a32..5e4f1585 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -710,96 +710,103 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } - for (i = 0; i < (u32)nl_cnt; ++i) { + if (nl_cnt) { - struct stat st; + i = nl_cnt; + do { - u8 dfn[PATH_MAX]; - snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir, - nl[i]->d_name); - u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name); + --i; - u8 passed_det = 0; + struct stat st; + u8 dfn[PATH_MAX]; + snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir, + nl[i]->d_name); + u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name); - if (lstat(fn2, &st) || access(fn2, R_OK)) { + u8 passed_det = 0; - PFATAL("Unable to access '%s'", fn2); + if (lstat(fn2, &st) || access(fn2, R_OK)) { - } + PFATAL("Unable to access '%s'", fn2); - /* obviously we want to skip "descending" into . and .. directories, - however it is a good idea to skip also directories that start with - a dot */ - if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') { + } - free(nl[i]); /* not tracked */ - read_testcases(afl, fn2); - ck_free(fn2); - continue; + /* obviously we want to skip "descending" into . and .. directories, + however it is a good idea to skip also directories that start with + a dot */ + if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') { - } + free(nl[i]); /* not tracked */ + read_testcases(afl, fn2); + ck_free(fn2); + continue; - free(nl[i]); + } - if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { + free(nl[i]); - ck_free(fn2); - continue; + if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { - } + ck_free(fn2); + continue; - if (st.st_size > MAX_FILE) { + } - WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2, - stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), - stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); + if (st.st_size > MAX_FILE) { - } + WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", + fn2, + stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), + stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); + + } - /* Check for metadata that indicates that deterministic fuzzing - is complete for this entry. We don't want to repeat deterministic - fuzzing when resuming aborted scans, because it would be pointless - and probably very time-consuming. */ + /* Check for metadata that indicates that deterministic fuzzing + is complete for this entry. We don't want to repeat deterministic + fuzzing when resuming aborted scans, because it would be pointless + and probably very time-consuming. */ - if (!access(dfn, F_OK)) { passed_det = 1; } + if (!access(dfn, F_OK)) { passed_det = 1; } - add_to_queue(afl, fn2, st.st_size >= MAX_FILE ? MAX_FILE : st.st_size, - passed_det); + add_to_queue(afl, fn2, st.st_size >= MAX_FILE ? MAX_FILE : st.st_size, + passed_det); - if (unlikely(afl->shm.cmplog_mode)) { + if (unlikely(afl->shm.cmplog_mode)) { - if (afl->cmplog_lvl == 1) { + if (afl->cmplog_lvl == 1) { - if (!afl->cmplog_max_filesize || - afl->cmplog_max_filesize < st.st_size) { + if (!afl->cmplog_max_filesize || + afl->cmplog_max_filesize < st.st_size) { - afl->cmplog_max_filesize = st.st_size; + afl->cmplog_max_filesize = st.st_size; - } + } - } else if (afl->cmplog_lvl == 2) { + } else if (afl->cmplog_lvl == 2) { - if (!afl->cmplog_max_filesize || - afl->cmplog_max_filesize > st.st_size) { + if (!afl->cmplog_max_filesize || + afl->cmplog_max_filesize > st.st_size) { - afl->cmplog_max_filesize = st.st_size; + afl->cmplog_max_filesize = st.st_size; + + } } } - } + /* + if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { - /* - if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { + u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, + HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE; + afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1; - u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, - HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE; - afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1; + } - } + */ - */ + } while (i > 0); } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 9648d795..e0930234 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -264,6 +264,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, "peak_rss_mb : %lu\n" "cpu_affinity : %d\n" "edges_found : %u\n" + "total_edges : %u\n" "var_byte_count : %u\n" "havoc_expansion : %u\n" "testcache_size : %llu\n" @@ -303,10 +304,10 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, #else -1, #endif - t_bytes, afl->var_byte_count, afl->expand_havoc, - afl->q_testcase_cache_size, afl->q_testcase_cache_count, - afl->q_testcase_evictions, afl->use_banner, - afl->unicorn_mode ? "unicorn" : "", + t_bytes, afl->fsrv.real_map_size, afl->var_byte_count, + afl->expand_havoc, afl->q_testcase_cache_size, + afl->q_testcase_cache_count, afl->q_testcase_evictions, + afl->use_banner, afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "", afl->non_instrumented_mode ? " non_instrumented " : "", afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", @@ -326,7 +327,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, u32 i = 0; fprintf(f, "virgin_bytes :"); - for (i = 0; i < afl->fsrv.map_size; i++) { + for (i = 0; i < afl->fsrv.real_map_size; i++) { if (afl->virgin_bits[i] != 0xff) { @@ -338,7 +339,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, fprintf(f, "\n"); fprintf(f, "var_bytes :"); - for (i = 0; i < afl->fsrv.map_size; i++) { + for (i = 0; i < afl->fsrv.real_map_size; i++) { if (afl->var_bytes[i]) { fprintf(f, " %u", i); } @@ -520,7 +521,7 @@ void show_stats(afl_state_t *afl) { /* Do some bitmap stats. */ t_bytes = count_non_255_bytes(afl, afl->virgin_bits); - t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.map_size; + t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.real_map_size; if (likely(t_bytes) && unlikely(afl->var_byte_count)) { @@ -781,7 +782,7 @@ void show_stats(afl_state_t *afl) { SAYF(bV bSTOP " now processing : " cRST "%-18s " bSTG bV bSTOP, tmp); sprintf(tmp, "%0.02f%% / %0.02f%%", - ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size, + ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.real_map_size, t_byte_ratio); SAYF(" map density : %s%-19s" bSTG bV "\n", diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index e9a67ac5..5f25f728 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -125,7 +125,7 @@ static void usage(u8 *argv0, int more_help) { "entering the\n" " pacemaker mode (minutes of no new paths). 0 = " "immediately,\n" - " -1 = immediately and together with normal mutation).\n" + " -1 = immediately and together with normal mutation.\n" " See docs/README.MOpt.md\n" " -c program - enable CmpLog by specifying a binary compiled for " "it.\n" @@ -1911,7 +1911,12 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); afl->start_time = get_cur_time(); - if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl); + if (afl->in_place_resume || afl->afl_env.afl_autoresume) { + + load_stats_file(afl); + + } + write_stats_file(afl, 0, 0, 0, 0); maybe_update_plot_file(afl, 0, 0, 0); save_auto(afl); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 96b72dd9..936d3bc4 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -67,6 +67,8 @@ static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */ +static u8 outfile[PATH_MAX]; + static u8 *in_data, /* Input data */ *coverage_map; /* Coverage map */ @@ -88,7 +90,8 @@ static bool quiet_mode, /* Hide non-essential messages? */ have_coverage, /* have coverage? */ no_classify, /* do not classify counts */ debug, /* debug mode */ - print_filenames; /* print the current filename */ + print_filenames, /* print the current filename */ + wait_for_gdb; static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -230,7 +233,11 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"), caa = !!getenv("AFL_CMIN_ALLOW_ANY"); - if (!outfile) { FATAL("Output filename not set (Bug in AFL++?)"); } + if (!outfile || !*outfile) { + + FATAL("Output filename not set (Bug in AFL++?)"); + + } if (cmin_mode && (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) { @@ -692,6 +699,96 @@ static void setup_signal_handlers(void) { } +u32 execute_testcases(u8 *dir) { + + struct dirent **nl; + s32 nl_cnt, subdirs = 1; + u32 i, done = 0; + u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; + + if (!be_quiet) { ACTF("Scanning '%s'...", dir); } + + /* We use scandir() + alphasort() rather than readdir() because otherwise, + the ordering of test cases would vary somewhat randomly and would be + difficult to control. */ + + nl_cnt = scandir(dir, &nl, NULL, alphasort); + + if (nl_cnt < 0) { return 0; } + + for (i = 0; i < (u32)nl_cnt; ++i) { + + struct stat st; + + u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name); + + if (lstat(fn2, &st) || access(fn2, R_OK)) { + + PFATAL("Unable to access '%s'", fn2); + + } + + /* obviously we want to skip "descending" into . and .. directories, + however it is a good idea to skip also directories that start with + a dot */ + if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') { + + free(nl[i]); /* not tracked */ + done += execute_testcases(fn2); + ck_free(fn2); + continue; + + } + + if (!S_ISREG(st.st_mode) || !st.st_size) { + + free(nl[i]); + ck_free(fn2); + continue; + + } + + if (st.st_size > MAX_FILE && !be_quiet) { + + WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2, + stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), + stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); + + } + + if (!collect_coverage) + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, nl[i]->d_name); + + free(nl[i]); + + if (read_file(fn2)) { + + if (wait_for_gdb) { + + fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid); + fprintf(stderr, "exec: kill -CONT %d\n", getpid()); + kill(0, SIGSTOP); + + } + + showmap_run_target_forkserver(fsrv, in_data, in_len); + ck_free(in_data); + ++done; + + if (collect_coverage) + analyze_results(fsrv); + else + tcnt = write_results_to_file(fsrv, outfile); + + } + + } + + free(nl); /* not tracked */ + return done; + +} + /* Show banner. */ static void show_banner(void) { @@ -710,31 +807,31 @@ static void usage(u8 *argv0) { "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" "Required parameters:\n" - " -o file - file to write the trace data to\n\n" + " -o file - file to write the trace data to\n\n" "Execution control settings:\n" - " -t msec - timeout for each run (none)\n" - " -m megs - memory limit for child process (%u MB)\n" - " -O - use binary-only instrumentation (FRIDA mode)\n" - " -Q - use binary-only instrumentation (QEMU mode)\n" - " -U - use Unicorn-based instrumentation (Unicorn mode)\n" - " -W - use qemu-based instrumentation with Wine (Wine mode)\n" - " (Not necessary, here for consistency with other afl-* " + " -t msec - timeout for each run (none)\n" + " -m megs - memory limit for child process (%u MB)\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" + " -Q - use binary-only instrumentation (QEMU mode)\n" + " -U - use Unicorn-based instrumentation (Unicorn mode)\n" + " -W - use qemu-based instrumentation with Wine (Wine mode)\n" + " (Not necessary, here for consistency with other afl-* " "tools)\n\n" "Other settings:\n" - " -i dir - process all files in this directory, must be combined " + " -i dir - process all files below this directory, must be combined " "with -o.\n" - " With -C, -o is a file, without -C it must be a " + " With -C, -o is a file, without -C it must be a " "directory\n" - " and each bitmap will be written there individually.\n" - " -C - collect coverage, writes all edges to -o and gives a " + " and each bitmap will be written there individually.\n" + " -C - collect coverage, writes all edges to -o and gives a " "summary\n" - " Must be combined with -i.\n" - " -q - sink program's output and don't show messages\n" - " -e - show edge coverage only, ignore hit counts\n" - " -r - show real tuple values instead of AFL filter values\n" - " -s - do not classify the map\n" - " -c - allow core dumps\n\n" + " Must be combined with -i.\n" + " -q - sink program's output and don't show messages\n" + " -e - show edge coverage only, ignore hit counts\n" + " -r - show real tuple values instead of AFL filter values\n" + " -s - do not classify the map\n" + " -c - allow core dumps\n\n" "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.md.\n\n" @@ -1136,15 +1233,7 @@ int main(int argc, char **argv_orig, char **envp) { if (in_dir) { - DIR * dir_in, *dir_out = NULL; - struct dirent **file_list; - - // int done = 0; - u8 infile[PATH_MAX], outfile[PATH_MAX]; - u8 wait_for_gdb = 0; -#if !defined(DT_REG) - struct stat statbuf; -#endif + DIR *dir_in, *dir_out = NULL; if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; @@ -1177,7 +1266,7 @@ int main(int argc, char **argv_orig, char **envp) { } else { - if ((coverage_map = (u8 *)malloc(map_size)) == NULL) + if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL) FATAL("coult not grab memory"); edges_only = false; raw_instr_output = true; @@ -1245,65 +1334,12 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - int file_count = scandir(in_dir, &file_list, NULL, alphasort); - if (file_count < 0) { + if (execute_testcases(in_dir) == 0) { - PFATAL("Failed to read from input dir at %s\n", in_dir); + FATAL("could not read input testcases from %s", in_dir); } - for (int i = 0; i < file_count; i++) { - - struct dirent *dir_ent = file_list[i]; - - if (dir_ent->d_name[0] == '.') { - - continue; // skip anything that starts with '.' - - } - -#if defined(DT_REG) /* Posix and Solaris do not know d_type and DT_REG */ - if (dir_ent->d_type != DT_REG) { - - continue; // only regular files - - } - -#endif - - snprintf(infile, sizeof(infile), "%s/%s", in_dir, dir_ent->d_name); - -#if !defined(DT_REG) /* use stat() */ - if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue; -#endif - - if (!collect_coverage) - snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name); - - if (read_file(infile)) { - - if (wait_for_gdb) { - - fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid); - fprintf(stderr, "exec: kill -CONT %d\n", getpid()); - kill(0, SIGSTOP); - - } - - showmap_run_target_forkserver(fsrv, in_data, in_len); - ck_free(in_data); - if (collect_coverage) - analyze_results(fsrv); - else - tcnt = write_results_to_file(fsrv, outfile); - - } - - } - - free(file_list); - file_list = NULL; - if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); } if (dir_out) { closedir(dir_out); } |