about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2021-11-30 10:57:28 +0100
committerGitHub <noreply@github.com>2021-11-30 10:57:28 +0100
commit5525f8c9ef8bb879dadd0eb942d524827d1b0362 (patch)
tree4509448aeb6de557ec7d6b54191195c80a7643e7
parentedbf41f78619162071987a44b46ab7f739bb85c1 (diff)
parentb48999f7c9e66e81899f8f5486c0931968bf3c77 (diff)
downloadafl++-5525f8c9ef8bb879dadd0eb942d524827d1b0362.tar.gz
Merge pull request #1187 from WorksButNotTested/frida
Frida
-rw-r--r--docs/env_variables.md99
-rw-r--r--frida_mode/README.md6
-rw-r--r--frida_mode/include/util.h5
-rw-r--r--frida_mode/src/entry.c2
-rw-r--r--frida_mode/src/instrument/instrument.c2
-rw-r--r--frida_mode/src/persistent/persistent.c6
-rw-r--r--frida_mode/src/seccomp/seccomp_event.c10
-rw-r--r--frida_mode/src/seccomp/seccomp_filter.c10
-rw-r--r--frida_mode/src/stalker.c22
-rw-r--r--frida_mode/src/stats/stats.c6
-rw-r--r--frida_mode/src/util.c34
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);