diff options
-rw-r--r-- | frida_mode/README.md | 2 | ||||
-rw-r--r-- | frida_mode/frida.map | 1 | ||||
-rw-r--r-- | frida_mode/include/instrument.h | 1 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument_coverage.c | 150 | ||||
-rw-r--r-- | frida_mode/src/js/api.js | 7 | ||||
-rw-r--r-- | frida_mode/src/js/js_api.c | 7 | ||||
-rw-r--r-- | frida_mode/test/unstable/unstable.c | 7 | ||||
-rw-r--r-- | frida_mode/ts/lib/afl.ts | 13 | ||||
-rw-r--r-- | include/envs.h | 1 |
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", |