about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--frida_mode/README.md2
-rw-r--r--frida_mode/frida.map1
-rw-r--r--frida_mode/include/instrument.h1
-rw-r--r--frida_mode/src/instrument/instrument_coverage.c150
-rw-r--r--frida_mode/src/js/api.js7
-rw-r--r--frida_mode/src/js/js_api.c7
-rw-r--r--frida_mode/test/unstable/unstable.c7
-rw-r--r--frida_mode/ts/lib/afl.ts13
-rw-r--r--include/envs.h1
9 files changed, 159 insertions, 30 deletions
diff --git a/frida_mode/README.md b/frida_mode/README.md
index 29f7968b..bfe0948b 100644
--- a/frida_mode/README.md
+++ b/frida_mode/README.md
@@ -146,6 +146,8 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
   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_ABSOLUTE` - Generate coverage files using absolute
+  virtual addresses rather than relative virtual addresses.
 * `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
diff --git a/frida_mode/frida.map b/frida_mode/frida.map
index 8e956460..73fff686 100644
--- a/frida_mode/frida.map
+++ b/frida_mode/frida.map
@@ -13,6 +13,7 @@
     js_api_set_debug_maps;
     js_api_set_entrypoint;
     js_api_set_instrument_cache_size;
+    js_api_set_instrument_coverage_absolute;
     js_api_set_instrument_coverage_file;
     js_api_set_instrument_debug_file;
     js_api_set_instrument_jit;
diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h
index 4b268e81..8c93d881 100644
--- a/frida_mode/include/instrument.h
+++ b/frida_mode/include/instrument.h
@@ -7,6 +7,7 @@
 
 extern char    *instrument_debug_filename;
 extern char    *instrument_coverage_filename;
+extern bool     instrument_coverage_absolute;
 extern gboolean instrument_tracing;
 extern gboolean instrument_optimize;
 extern gboolean instrument_unique;
diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c
index 07d4d622..25913585 100644
--- a/frida_mode/src/instrument/instrument_coverage.c
+++ b/frida_mode/src/instrument/instrument_coverage.c
@@ -9,6 +9,7 @@
 #include "util.h"
 
 char *instrument_coverage_filename = NULL;
+bool  instrument_coverage_absolute = false;
 
 static int normal_coverage_fd = -1;
 static int normal_coverage_pipes[2] = {-1, -1};
@@ -237,6 +238,18 @@ static void instrument_coverage_mark(void *key, void *value, void *user_data) {
 
 }
 
+static void instrument_coverage_mark_first(void *key, void *value,
+                                           void *user_data) {
+
+  UNUSED_PARAMETER(key);
+  coverage_range_t *      module = (coverage_range_t *)user_data;
+  normal_coverage_data_t *val = (normal_coverage_data_t *)value;
+
+  val->module = module;
+  module->count++;
+
+}
+
 static void coverage_write(int fd, void *data, size_t size) {
 
   ssize_t written;
@@ -404,28 +417,69 @@ static void instrument_coverage_normal_run() {
 
   instrument_coverage_print("Coverage - Preparing\n");
 
-  GArray *coverage_modules = coverage_get_modules();
+  if (instrument_coverage_absolute) {
 
-  guint size = g_hash_table_size(coverage_hash);
-  instrument_coverage_print("Coverage - Total Entries: %u\n", size);
+    guint size = g_hash_table_size(coverage_hash);
+    instrument_coverage_print("Coverage - Total Entries: %u\n", size);
 
-  coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
+    coverage_range_t module = {
 
-  g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx);
-  instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
+        .base_address = GUM_ADDRESS(0),
+        .limit = GUM_ADDRESS(-1),
+        .size = GUM_ADDRESS(-1),
+        .path = "absolute",
+        .offset = 0,
+        .is_executable = true,
+        .count = size,
+        .id = 0,
 
-  guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
-  instrument_coverage_print("Coverage - Marked Modules: %u\n",
-                            coverage_marked_modules);
+    };
 
-  coverage_write_header(normal_coverage_fd, coverage_marked_modules);
-  coverage_write_modules(normal_coverage_fd, coverage_modules);
-  coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", ctx.count);
-  g_hash_table_foreach(coverage_hash, coverage_write_events,
-                       &normal_coverage_fd);
+    instrument_coverage_print("Coverage Module - 0x%016" G_GINT64_MODIFIER
+                              "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n",
+                              module.base_address, module.limit, module.path);
 
-  g_hash_table_unref(coverage_hash);
+    GArray *coverage_modules =
+        g_array_sized_new(false, false, sizeof(coverage_range_t), 1);
+    g_array_append_val(coverage_modules, module);
+
+    g_hash_table_foreach(coverage_hash, instrument_coverage_mark_first,
+                         &module);
+
+    coverage_write_header(normal_coverage_fd, 1);
+    coverage_write_modules(normal_coverage_fd, coverage_modules);
+    coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", size);
+    g_hash_table_foreach(coverage_hash, coverage_write_events,
+                         &normal_coverage_fd);
+
+  } else {
+
+    GArray *coverage_modules = coverage_get_modules();
+
+    guint size = g_hash_table_size(coverage_hash);
+    instrument_coverage_print("Coverage - Total Entries: %u\n", size);
+
+    coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
+
+    /* For each coverage event in the hashtable associate it with a module and
+     * count the number of entries per module */
+    g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx);
+    instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
+
+    /* For each module with coverage events assign it an incrementing number */
+    guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
+    instrument_coverage_print("Coverage - Marked Modules: %u\n",
+                              coverage_marked_modules);
+
+    coverage_write_header(normal_coverage_fd, coverage_marked_modules);
+    coverage_write_modules(normal_coverage_fd, coverage_modules);
+    coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", ctx.count);
+    g_hash_table_foreach(coverage_hash, coverage_write_events,
+                         &normal_coverage_fd);
 
+  }
+
+  g_hash_table_unref(coverage_hash);
   instrument_coverage_print("Coverage - Completed\n");
 
 }
@@ -622,8 +676,6 @@ static void instrument_coverage_unstable_run(void) {
 
   instrument_coverage_print("Coverage - Preparing\n");
 
-  GArray *coverage_modules = coverage_get_modules();
-
   instrument_coverage_print("Found edges: %u\n", edges);
 
   GArray *unstable_edge_ids = instrument_coverage_unstable_read_unstable_ids();
@@ -634,20 +686,60 @@ static void instrument_coverage_unstable_run(void) {
   guint size = g_hash_table_size(unstable_blocks);
   instrument_coverage_print("Unstable blocks: %u\n", size);
 
-  coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
+  if (instrument_coverage_absolute) {
+
+    instrument_coverage_print("Coverage - Total Entries: %u\n", size);
+
+    coverage_range_t module = {
+
+        .base_address = GUM_ADDRESS(0),
+        .limit = GUM_ADDRESS(-1),
+        .size = GUM_ADDRESS(-1),
+        .path = "absolute",
+        .offset = 0,
+        .is_executable = true,
+        .count = size,
+        .id = 0,
+
+    };
+
+    instrument_coverage_print("Coverage Module - 0x%016" G_GINT64_MODIFIER
+                              "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n",
+                              module.base_address, module.limit, module.path);
 
-  g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx);
-  instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
+    GArray *coverage_modules =
+        g_array_sized_new(false, false, sizeof(coverage_range_t), 1);
+    g_array_append_val(coverage_modules, module);
 
-  guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
-  instrument_coverage_print("Coverage - Marked Modules: %u\n",
-                            coverage_marked_modules);
+    g_hash_table_foreach(unstable_blocks, instrument_coverage_mark_first,
+                         &module);
 
-  coverage_write_header(unstable_coverage_fd, coverage_marked_modules);
-  coverage_write_modules(unstable_coverage_fd, coverage_modules);
-  coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", ctx.count);
-  g_hash_table_foreach(unstable_blocks, coverage_write_events,
-                       &unstable_coverage_fd);
+    coverage_write_header(unstable_coverage_fd, 1);
+    coverage_write_modules(unstable_coverage_fd, coverage_modules);
+    coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", size);
+    g_hash_table_foreach(unstable_blocks, coverage_write_events,
+                         &unstable_coverage_fd);
+
+  } else {
+
+    GArray *coverage_modules = coverage_get_modules();
+
+    coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
+
+    g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx);
+    instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count);
+
+    guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
+    instrument_coverage_print("Coverage - Marked Modules: %u\n",
+                              coverage_marked_modules);
+
+    coverage_write_header(unstable_coverage_fd, coverage_marked_modules);
+    coverage_write_modules(unstable_coverage_fd, coverage_modules);
+    coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", ctx.count);
+    g_hash_table_foreach(unstable_blocks, coverage_write_events,
+                         &unstable_coverage_fd);
+
+  }
 
   g_hash_table_unref(unstable_blocks);
   g_array_free(unstable_edge_ids, TRUE);
@@ -660,6 +752,8 @@ static void instrument_coverage_unstable_run(void) {
 void instrument_coverage_config(void) {
 
   instrument_coverage_filename = getenv("AFL_FRIDA_INST_COVERAGE_FILE");
+  instrument_coverage_absolute =
+      (getenv("AFL_FRIDA_INST_COVERAGE_ABSOLUTE") != NULL);
 
 }
 
diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js
index 721ef82c..fce7a5d7 100644
--- a/frida_mode/src/js/api.js
+++ b/frida_mode/src/js/api.js
@@ -105,6 +105,12 @@ class Afl {
         Afl.jsApiSetInstrumentCacheSize(size);
     }
     /**
+     * See `AFL_FRIDA_INST_COVERAGE_ABSOLUTE`.
+     */
+    static setInstrumentCoverageAbsolute() {
+        Afl.jsApiSetInstrumentCoverageAbsolute();
+    }
+    /**
      * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
      * as an argument.
      */
@@ -324,6 +330,7 @@ Afl.jsApiSetCacheDisable = Afl.jsApiGetFunction("js_api_set_cache_disable", "voi
 Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []);
 Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
 Afl.jsApiSetInstrumentCacheSize = Afl.jsApiGetFunction("js_api_set_instrument_cache_size", "void", ["size_t"]);
+Afl.jsApiSetInstrumentCoverageAbsolute = Afl.jsApiGetFunction("js_api_set_instrument_coverage_absolute", "void", []);
 Afl.jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_coverage_file", "void", ["pointer"]);
 Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]);
 Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []);
diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c
index 249f9c96..01bba4ff 100644
--- a/frida_mode/src/js/js_api.c
+++ b/frida_mode/src/js/js_api.c
@@ -115,6 +115,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_libraries() {
 
 }
 
+__attribute__((visibility("default"))) void
+js_api_set_instrument_coverage_absolute(void) {
+
+  instrument_coverage_absolute = true;
+
+}
+
 __attribute__((visibility("default"))) void js_api_set_instrument_coverage_file(
     char *path) {
 
diff --git a/frida_mode/test/unstable/unstable.c b/frida_mode/test/unstable/unstable.c
index 915e283f..7d16c26c 100644
--- a/frida_mode/test/unstable/unstable.c
+++ b/frida_mode/test/unstable/unstable.c
@@ -14,6 +14,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/time.h>
 
 #ifdef __APPLE__
   #define TESTINSTR_SECTION
@@ -25,8 +26,10 @@ void LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
 
   if (size < 1) return;
 
-  int r = rand();
-  if ((r % 2) == 0) {
+  struct timeval tv = {0};
+  if (gettimeofday(&tv, NULL) < 0) return;
+
+  if ((tv.tv_usec % 2) == 0) {
     printf ("Hooray all even\n");
   } else {
     printf ("Hmm that's odd\n");
diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts
index 455d4305..7a83c0fb 100644
--- a/frida_mode/ts/lib/afl.ts
+++ b/frida_mode/ts/lib/afl.ts
@@ -126,6 +126,13 @@ class Afl {
   }
 
   /**
+   * See `AFL_FRIDA_INST_COVERAGE_ABSOLUTE`.
+   */
+  public static setInstrumentCoverageAbsolute(): void {
+    Afl.jsApiSetInstrumentCoverageAbsolute();
+  }
+
+  /**
    * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
    * as an argument.
    */
@@ -398,6 +405,12 @@ class Afl {
     "void",
     ["size_t"]);
 
+  private static readonly jsApiSetInstrumentCoverageAbsolute = Afl.jsApiGetFunction(
+    "js_api_set_instrument_coverage_absolute",
+    "void",
+    []
+  );
+
   private static readonly jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction(
     "js_api_set_instrument_coverage_file",
     "void",
diff --git a/include/envs.h b/include/envs.h
index 853edbd9..52f2d09b 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -58,6 +58,7 @@ static char *afl_environment_variables[] = {
     "AFL_FRIDA_DRIVER_NO_HOOK",
     "AFL_FRIDA_EXCLUDE_RANGES",
     "AFL_FRIDA_INST_CACHE_SIZE",
+    "AFL_FRIDA_INST_COVERAGE_ABSOLUTE",
     "AFL_FRIDA_INST_COVERAGE_FILE",
     "AFL_FRIDA_INST_DEBUG_FILE",
     "AFL_FRIDA_INST_INSN",