diff options
author | van Hauser <vh@thc.org> | 2021-11-30 10:57:28 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-30 10:57:28 +0100 |
commit | 5525f8c9ef8bb879dadd0eb942d524827d1b0362 (patch) | |
tree | 4509448aeb6de557ec7d6b54191195c80a7643e7 | |
parent | edbf41f78619162071987a44b46ab7f739bb85c1 (diff) | |
parent | b48999f7c9e66e81899f8f5486c0931968bf3c77 (diff) | |
download | afl++-5525f8c9ef8bb879dadd0eb942d524827d1b0362.tar.gz |
Merge pull request #1187 from WorksButNotTested/frida
Frida
-rw-r--r-- | docs/env_variables.md | 99 | ||||
-rw-r--r-- | frida_mode/README.md | 6 | ||||
-rw-r--r-- | frida_mode/include/util.h | 5 | ||||
-rw-r--r-- | frida_mode/src/entry.c | 2 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument.c | 2 | ||||
-rw-r--r-- | frida_mode/src/persistent/persistent.c | 6 | ||||
-rw-r--r-- | frida_mode/src/seccomp/seccomp_event.c | 10 | ||||
-rw-r--r-- | frida_mode/src/seccomp/seccomp_filter.c | 10 | ||||
-rw-r--r-- | frida_mode/src/stalker.c | 22 | ||||
-rw-r--r-- | frida_mode/src/stats/stats.c | 6 | ||||
-rw-r--r-- | frida_mode/src/util.c | 34 |
11 files changed, 156 insertions, 46 deletions
diff --git a/docs/env_variables.md b/docs/env_variables.md index cce9ff56..c1c70ec5 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -579,7 +579,92 @@ The QEMU wrapper used to instrument binary-only code supports several settings: emulation" variables (e.g., `QEMU_STACK_SIZE`), but there should be no reason to touch them. -## 6) Settings for afl-cmin +## 7) Settings for afl-frida-trace + +The FRIDA wrapper used to instrument binary-only code supports many of the same +options as `afl-qemu-trace`, but also has a number of additional advanced +options. These are listed in brief below (see [here](../frida_mode/README.md) +for more details). These settings are provided for compatibiltiy with QEMU mode, +the preferred way to configure FRIDA mode is through its +[scripting](../frida_mode/Scripting.md) support. + +* `AFL_FRIDA_DEBUG_MAPS` - See `AFL_QEMU_DEBUG_MAPS` +* `AFL_FRIDA_DRIVER_NO_HOOK` - See `AFL_QEMU_DRIVER_NO_HOOK`. When using the +QEMU driver to provide a `main` loop for a user provided +`LLVMFuzzerTestOneInput`, this option configures the driver to read input from +`stdin` rather than using in-memory test cases. +* `AFL_FRIDA_EXCLUDE_RANGES` - See `AFL_QEMU_EXCLUDE_RANGES` +* `AFL_FRIDA_INST_COVERAGE_FILE` - File to write DynamoRio format coverage +information (e.g. to be loaded within IDA lighthouse). +* `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks +and their instrumented counterparts during block compilation. +* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled +code. Code is considered to be JIT if the executable segment is not backed by a +file. +* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage +instrumentation (the default where available). Required to use +`AFL_FRIDA_INST_TRACE`. +* `AFL_FRIDA_INST_NO_BACKPATCH` - Disable backpatching. At the end of executing +each block, control will return to FRIDA to identify the next block to execute. +* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default the child will +report instrumented blocks back to the parent so that it can also instrument +them and they be inherited by the next child on fork, implies +`AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`. +* `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH` - Disable prefetching of stalker +backpatching information. By default the child will report applied backpatches +to the parent so that they can be applied and then be inherited by the next +child on fork. +* `AFL_FRIDA_INST_RANGES` - See `AFL_QEMU_INST_RANGES` +* `AFL_FRIDA_INST_SEED` - Sets the initial seed for the hash function used to +generate block (and hence edge) IDs. Setting this to a constant value may be +useful for debugging purposes, e.g. investigating unstable edges. +* `AFL_FRIDA_INST_TRACE` - Log to stdout the address of executed blocks, +implies `AFL_FRIDA_INST_NO_OPTIMIZE`. +* `AFL_FRIDA_INST_TRACE_UNIQUE` - As per `AFL_FRIDA_INST_TRACE`, but each edge +is logged only once, requires `AFL_FRIDA_INST_NO_OPTIMIZE`. +* `AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE` - File to write DynamoRio format +coverage information for unstable edges (e.g. to be loaded within IDA +lighthouse). +* `AFL_FRIDA_JS_SCRIPT` - Set the script to be loaded by the FRIDA scripting +engine. See [here](Scripting.md) for details. +* `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target +application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) +* `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target +application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) +* `AFL_FRIDA_PERSISTENT_ADDR` - See `AFL_QEMU_PERSISTENT_ADDR` +* `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT` +* `AFL_FRIDA_PERSISTENT_DEBUG` - Insert a Breakpoint into the instrumented code +at `AFL_FRIDA_PERSISTENT_HOOK` and `AFL_FRIDA_PERSISTENT_RET` to allow the user +to detect issues in the persistent loop using a debugger. +* `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK` +* `AFL_FRIDA_PERSISTENT_RET` - See `AFL_QEMU_PERSISTENT_RET` +* `AFL_FRIDA_SECCOMP_FILE` - Write a log of any syscalls made by the target to +the specified file. +* `AFL_FRIDA_STALKER_ADJACENT_BLOCKS` - Configure the number of adjacent blocks + to fetch when generating instrumented code. By fetching blocks in the same + order they appear in the original program, rather than the order of execution + should help reduce locallity and adjacency. This includes allowing us to vector + between adjancent blocks using a NOP slide rather than an immediate branch. +* `AFL_FRIDA_STALKER_IC_ENTRIES` - Configure the number of inline cache entries +stored along-side branch instructions which provide a cache to avoid having to +call back into FRIDA to find the next block. Default is 32. +* `AFL_FRIDA_STATS_FILE` - Write statistics information about the code being +instrumented to the given file name. The statistics are written only for the +child process when new block is instrumented (when the +`AFL_FRIDA_STATS_INTERVAL` has expired). Note that simply because a new path is +found does not mean a new block needs to be compiled. It could simply be that +the existing blocks instrumented have been executed in a different order. +* `AFL_FRIDA_STATS_INTERVAL` - The maximum frequency to output statistics +information. Stats will be written whenever they are updated if the given +interval has elapsed since last time they were written. +* `AFL_FRIDA_TRACEABLE` - Set the child process to be traceable by any process +to aid debugging and overcome the restrictions imposed by YAMA. Supported on +Linux only. Permits a non-root user to use `gcore` or similar to collect a core +dump of the instrumented target. Note that in order to capture the core dump you +must set a sufficient timeout (using `-t`) to avoid `afl-fuzz` killing the +process whilst it is being dumped. + +## 8) Settings for afl-cmin The corpus minimization script offers very little customization: @@ -597,7 +682,7 @@ The corpus minimization script offers very little customization: - `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed. This can help when embedding `afl-cmin` or `afl-showmap` in other scripts. -## 7) Settings for afl-tmin +## 9) Settings for afl-tmin Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be searched for afl-qemu-trace. In addition to this, `TMPDIR` may be used if a @@ -608,12 +693,12 @@ to match when minimizing crashes. This will make minimization less useful, but may prevent the tool from "jumping" from one crashing condition to another in very buggy software. You probably want to combine it with the `-e` flag. -## 8) Settings for afl-analyze +## 10) Settings for afl-analyze You can set `AFL_ANALYZE_HEX` to get file offsets printed as hexadecimal instead of decimal. -## 9) Settings for libdislocator +## 11) Settings for libdislocator The library honors these environment variables: @@ -635,12 +720,12 @@ The library honors these environment variables: - `AFL_LD_VERBOSE` causes the library to output some diagnostic messages that may be useful for pinpointing the cause of any observed issues. -## 10) Settings for libtokencap +## 11) Settings for libtokencap This library accepts `AFL_TOKEN_FILE` to indicate the location to which the discovered tokens should be written. -## 11) Third-party variables set by afl-fuzz & other tools +## 12) Third-party variables set by afl-fuzz & other tools Several variables are not directly interpreted by afl-fuzz, but are set to optimal values if not already present in the environment: @@ -685,4 +770,4 @@ optimal values if not already present in the environment: - By default, `LD_BIND_NOW` is set to speed up fuzzing by forcing the linker to do all the work before the fork server kicks in. You can override this by - setting `LD_BIND_LAZY` beforehand, but it is almost certainly pointless. \ No newline at end of file + setting `LD_BIND_LAZY` beforehand, but it is almost certainly pointless. diff --git a/frida_mode/README.md b/frida_mode/README.md index a75324d5..6c46fe08 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -145,6 +145,10 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent (only on CMP, SUB and CALL instructions) performance is not quite so critical. ## Advanced configuration options +* `AFL_FRIDA_DRIVER_NO_HOOK` - See `AFL_QEMU_DRIVER_NO_HOOK`. When using the +QEMU driver to provide a `main` loop for a user provided +`LLVMFuzzerTestOneInput`, this option configures the driver to read input from +`stdin` rather than using in-memory test cases. * `AFL_FRIDA_INST_COVERAGE_FILE` - File to write DynamoRio format coverage information (e.g. to be loaded within IDA lighthouse). * `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks @@ -194,6 +198,8 @@ is logged only once, requires `AFL_FRIDA_INST_NO_OPTIMIZE`. * `AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE` - File to write DynamoRio format coverage information for unstable edges (e.g. to be loaded within IDA lighthouse). +* `AFL_FRIDA_JS_SCRIPT` - Set the script to be loaded by the FRIDA scripting +engine. See [here](Scripting.md) for details. * `AFL_FRIDA_OUTPUT_STDOUT` - Redirect the standard output of the target application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`) * `AFL_FRIDA_OUTPUT_STDERR` - Redirect the standard error of the target diff --git a/frida_mode/include/util.h b/frida_mode/include/util.h index 77491ea8..4dc05f20 100644 --- a/frida_mode/include/util.h +++ b/frida_mode/include/util.h @@ -8,9 +8,8 @@ #define UNUSED_PARAMETER(x) (void)(x) #define IGNORED_RETURN(x) (void)!(x) -guint64 util_read_address(char *key); - -guint64 util_read_num(char *key); +guint64 util_read_address(char *key, guint64 default_value); +guint64 util_read_num(char *key, guint64 default_value); gboolean util_output_enabled(void); gsize util_rotate(gsize val, gsize shift, gsize size); gsize util_log2(gsize val); diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c index 562e74eb..de645fdb 100644 --- a/frida_mode/src/entry.c +++ b/frida_mode/src/entry.c @@ -62,7 +62,7 @@ void entry_on_fork(void) { void entry_config(void) { - entry_point = util_read_address("AFL_ENTRYPOINT"); + entry_point = util_read_address("AFL_ENTRYPOINT", 0); if (getenv("AFL_FRIDA_TRACEABLE") != NULL) { traceable = TRUE; } } diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index d5823654..414dc84c 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -246,7 +246,7 @@ void instrument_config(void) { instrument_tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); instrument_unique = (getenv("AFL_FRIDA_INST_TRACE_UNIQUE") != NULL); instrument_use_fixed_seed = (getenv("AFL_FRIDA_INST_SEED") != NULL); - instrument_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED"); + instrument_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED", 0); instrument_coverage_unstable_filename = (getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE")); diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c index e62f25d0..817d9925 100644 --- a/frida_mode/src/persistent/persistent.c +++ b/frida_mode/src/persistent/persistent.c @@ -22,9 +22,9 @@ gboolean persistent_debug = FALSE; void persistent_config(void) { hook_name = getenv("AFL_FRIDA_PERSISTENT_HOOK"); - persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR"); - persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT"); - persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET"); + persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR", 0); + persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT", 0); + persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET", 0); if (getenv("AFL_FRIDA_PERSISTENT_DEBUG") != NULL) { persistent_debug = TRUE; } diff --git a/frida_mode/src/seccomp/seccomp_event.c b/frida_mode/src/seccomp/seccomp_event.c index 0907eff8..e6585f1d 100644 --- a/frida_mode/src/seccomp/seccomp_event.c +++ b/frida_mode/src/seccomp/seccomp_event.c @@ -10,13 +10,13 @@ int seccomp_event_create(void) { -#ifdef SYS_eventfd + #ifdef SYS_eventfd int fd = syscall(SYS_eventfd, 0, 0); -#else -# ifdef SYS_eventfd2 + #else + #ifdef SYS_eventfd2 int fd = syscall(SYS_eventfd2, 0, 0); -# endif -#endif + #endif + #endif if (fd < 0) { FFATAL("seccomp_event_create"); } return fd; diff --git a/frida_mode/src/seccomp/seccomp_filter.c b/frida_mode/src/seccomp/seccomp_filter.c index 5aee398f..1d050303 100644 --- a/frida_mode/src/seccomp/seccomp_filter.c +++ b/frida_mode/src/seccomp/seccomp_filter.c @@ -72,13 +72,13 @@ static struct sock_filter filter[] = { /* Allow us to make anonymous maps */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), -#ifdef __NR_mmap + #ifdef __NR_mmap BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mmap, 0, 3), -#else -# ifdef __NR_mmap2 + #else + #ifdef __NR_mmap2 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mmap2, 0, 3), -# endif -#endif + #endif + #endif BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, args[4]))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, -1, 0, 1), diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c index b4dd5a47..caa16b3f 100644 --- a/frida_mode/src/stalker.c +++ b/frida_mode/src/stalker.c @@ -61,9 +61,10 @@ void stalker_config(void) { backpatch_enable = (getenv("AFL_FRIDA_INST_NO_BACKPATCH") == NULL); - stalker_ic_entries = util_read_num("AFL_FRIDA_STALKER_ADJACENT_BLOCKS"); + stalker_ic_entries = util_read_num("AFL_FRIDA_STALKER_IC_ENTRIES", 32); - stalker_adjacent_blocks = util_read_num("AFL_FRIDA_STALKER_IC_ENTRIES"); + stalker_adjacent_blocks = + util_read_num("AFL_FRIDA_STALKER_ADJACENT_BLOCKS", 32); observer = g_object_new(GUM_TYPE_AFL_STALKER_OBSERVER, NULL); @@ -98,33 +99,32 @@ void stalker_init(void) { FOKF("Stalker - adjacent_blocks [%u]", stalker_adjacent_blocks); #if !(defined(__x86_64__) || defined(__i386__)) - if (stalker_ic_entries != 0) { + if (getenv("AFL_FRIDA_STALKER_IC_ENTRIES") != NULL) { FFATAL("AFL_FRIDA_STALKER_IC_ENTRIES not supported"); } - if (stalker_adjacent_blocks != 0) { + if (getenv("AFL_FRIDA_STALKER_ADJACENT_BLOCKS") != NULL) { FFATAL("AFL_FRIDA_STALKER_ADJACENT_BLOCKS not supported"); } #endif - if (stalker_ic_entries == 0) { stalker_ic_entries = 32; } - if (instrument_coverage_filename == NULL) { + if (instrument_coverage_filename != NULL) { - if (stalker_adjacent_blocks == 0) { stalker_adjacent_blocks = 32; } - - } else { - - if (stalker_adjacent_blocks != 0) { + if (getenv("AFL_FRIDA_STALKER_ADJACENT_BLOCKS") != NULL) { FFATAL( "AFL_FRIDA_STALKER_ADJACENT_BLOCKS and AFL_FRIDA_INST_COVERAGE_FILE " "are incompatible"); + } else { + + stalker_adjacent_blocks = 0; + } } diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c index a61834d6..83ecf89a 100644 --- a/frida_mode/src/stats/stats.c +++ b/frida_mode/src/stats/stats.c @@ -323,7 +323,7 @@ static void stats_observer_init(GumStalkerObserver *observer) { void stats_config(void) { stats_filename = getenv("AFL_FRIDA_STATS_FILE"); - stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL"); + stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL", 10); } @@ -332,7 +332,8 @@ void stats_init(void) { FOKF("Stats - file [%s]", stats_filename); FOKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval); - if (stats_interval != 0 && stats_filename == NULL) { + if (getenv("AFL_FRIDA_STATS_INTERVAL") != NULL && + getenv("AFL_FRIDA_STATS_FILE") == NULL) { FFATAL( "AFL_FRIDA_STATS_FILE must be specified if " @@ -340,7 +341,6 @@ void stats_init(void) { } - if (stats_interval == 0) { stats_interval = 10; } stats_interval_us = stats_interval * MICRO_TO_SEC; if (stats_filename == NULL) { return; } diff --git a/frida_mode/src/util.c b/frida_mode/src/util.c index d84b7065..6f52b6cb 100644 --- a/frida_mode/src/util.c +++ b/frida_mode/src/util.c @@ -1,10 +1,11 @@ #include "util.h" -guint64 util_read_address(char *key) { +guint64 util_read_address(char *key, guint64 default_value) { char *value_str = getenv(key); + char *end_ptr; - if (value_str == NULL) { return 0; } + if (value_str == NULL) { return default_value; } if (!g_str_has_prefix(value_str, "0x")) { @@ -25,8 +26,17 @@ guint64 util_read_address(char *key) { } - guint64 value = g_ascii_strtoull(value_str2, NULL, 16); - if (value == 0) { + errno = 0; + + guint64 value = g_ascii_strtoull(value_str2, &end_ptr, 16); + + if (errno != 0) { + + FATAL("Error (%d) during conversion: %s", errno, value_str); + + } + + if (value == 0 && end_ptr == value_str2) { FATAL("Invalid address failed hex conversion: %s=%s\n", key, value_str2); @@ -36,11 +46,12 @@ guint64 util_read_address(char *key) { } -guint64 util_read_num(char *key) { +guint64 util_read_num(char *key, guint64 default_value) { char *value_str = getenv(key); + char *end_ptr; - if (value_str == NULL) { return 0; } + if (value_str == NULL) { return default_value; } for (char *c = value_str; *c != '\0'; c++) { @@ -53,8 +64,17 @@ guint64 util_read_num(char *key) { } + errno = 0; + guint64 value = g_ascii_strtoull(value_str, NULL, 10); - if (value == 0) { + + if (errno != 0) { + + FATAL("Error (%d) during conversion: %s", errno, value_str); + + } + + if (value == 0 && end_ptr == value_str) { FATAL("Invalid address failed numeric conversion: %s=%s\n", key, value_str); |