Changes to add option for absolute coverage data

This commit is contained in:
Your Name
2022-08-04 18:46:29 +01:00
parent 98e8838755
commit 3562de440e
9 changed files with 159 additions and 30 deletions

View File

@ -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 QEMU driver to provide a `main` loop for a user provided
`LLVMFuzzerTestOneInput`, this option configures the driver to read input from `LLVMFuzzerTestOneInput`, this option configures the driver to read input from
`stdin` rather than using in-memory test cases. `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 * `AFL_FRIDA_INST_COVERAGE_FILE` - File to write DynamoRIO format coverage
information (e.g., to be loaded within IDA lighthouse). information (e.g., to be loaded within IDA lighthouse).
* `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks * `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks

View File

@ -13,6 +13,7 @@
js_api_set_debug_maps; js_api_set_debug_maps;
js_api_set_entrypoint; js_api_set_entrypoint;
js_api_set_instrument_cache_size; js_api_set_instrument_cache_size;
js_api_set_instrument_coverage_absolute;
js_api_set_instrument_coverage_file; js_api_set_instrument_coverage_file;
js_api_set_instrument_debug_file; js_api_set_instrument_debug_file;
js_api_set_instrument_jit; js_api_set_instrument_jit;

View File

@ -7,6 +7,7 @@
extern char *instrument_debug_filename; extern char *instrument_debug_filename;
extern char *instrument_coverage_filename; extern char *instrument_coverage_filename;
extern bool instrument_coverage_absolute;
extern gboolean instrument_tracing; extern gboolean instrument_tracing;
extern gboolean instrument_optimize; extern gboolean instrument_optimize;
extern gboolean instrument_unique; extern gboolean instrument_unique;

View File

@ -9,6 +9,7 @@
#include "util.h" #include "util.h"
char *instrument_coverage_filename = NULL; char *instrument_coverage_filename = NULL;
bool instrument_coverage_absolute = false;
static int normal_coverage_fd = -1; static int normal_coverage_fd = -1;
static int normal_coverage_pipes[2] = {-1, -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) { static void coverage_write(int fd, void *data, size_t size) {
ssize_t written; ssize_t written;
@ -404,6 +417,43 @@ static void instrument_coverage_normal_run() {
instrument_coverage_print("Coverage - Preparing\n"); instrument_coverage_print("Coverage - Preparing\n");
if (instrument_coverage_absolute) {
guint size = g_hash_table_size(coverage_hash);
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);
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(); GArray *coverage_modules = coverage_get_modules();
guint size = g_hash_table_size(coverage_hash); guint size = g_hash_table_size(coverage_hash);
@ -411,9 +461,12 @@ static void instrument_coverage_normal_run() {
coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0}; 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); g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx);
instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count); 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); guint coverage_marked_modules = coverage_mark_modules(coverage_modules);
instrument_coverage_print("Coverage - Marked Modules: %u\n", instrument_coverage_print("Coverage - Marked Modules: %u\n",
coverage_marked_modules); coverage_marked_modules);
@ -424,8 +477,9 @@ static void instrument_coverage_normal_run() {
g_hash_table_foreach(coverage_hash, coverage_write_events, g_hash_table_foreach(coverage_hash, coverage_write_events,
&normal_coverage_fd); &normal_coverage_fd);
g_hash_table_unref(coverage_hash); }
g_hash_table_unref(coverage_hash);
instrument_coverage_print("Coverage - Completed\n"); instrument_coverage_print("Coverage - Completed\n");
} }
@ -622,8 +676,6 @@ static void instrument_coverage_unstable_run(void) {
instrument_coverage_print("Coverage - Preparing\n"); instrument_coverage_print("Coverage - Preparing\n");
GArray *coverage_modules = coverage_get_modules();
instrument_coverage_print("Found edges: %u\n", edges); instrument_coverage_print("Found edges: %u\n", edges);
GArray *unstable_edge_ids = instrument_coverage_unstable_read_unstable_ids(); GArray *unstable_edge_ids = instrument_coverage_unstable_read_unstable_ids();
@ -634,6 +686,44 @@ static void instrument_coverage_unstable_run(void) {
guint size = g_hash_table_size(unstable_blocks); guint size = g_hash_table_size(unstable_blocks);
instrument_coverage_print("Unstable blocks: %u\n", size); instrument_coverage_print("Unstable blocks: %u\n", size);
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);
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(unstable_blocks, instrument_coverage_mark_first,
&module);
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}; coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0};
g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx); g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx);
@ -649,6 +739,8 @@ static void instrument_coverage_unstable_run(void) {
g_hash_table_foreach(unstable_blocks, coverage_write_events, g_hash_table_foreach(unstable_blocks, coverage_write_events,
&unstable_coverage_fd); &unstable_coverage_fd);
}
g_hash_table_unref(unstable_blocks); g_hash_table_unref(unstable_blocks);
g_array_free(unstable_edge_ids, TRUE); g_array_free(unstable_edge_ids, TRUE);
g_hash_table_unref(unstable_coverage_hash); g_hash_table_unref(unstable_coverage_hash);
@ -660,6 +752,8 @@ static void instrument_coverage_unstable_run(void) {
void instrument_coverage_config(void) { void instrument_coverage_config(void) {
instrument_coverage_filename = getenv("AFL_FRIDA_INST_COVERAGE_FILE"); instrument_coverage_filename = getenv("AFL_FRIDA_INST_COVERAGE_FILE");
instrument_coverage_absolute =
(getenv("AFL_FRIDA_INST_COVERAGE_ABSOLUTE") != NULL);
} }

View File

@ -104,6 +104,12 @@ class Afl {
static setInstrumentCacheSize(size) { static setInstrumentCacheSize(size) {
Afl.jsApiSetInstrumentCacheSize(size); 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` * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
* as an argument. * 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.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []);
Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]); Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
Afl.jsApiSetInstrumentCacheSize = Afl.jsApiGetFunction("js_api_set_instrument_cache_size", "void", ["size_t"]); 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.jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_coverage_file", "void", ["pointer"]);
Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_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", []); Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []);

View File

@ -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( __attribute__((visibility("default"))) void js_api_set_instrument_coverage_file(
char *path) { char *path) {

View File

@ -14,6 +14,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h>
#ifdef __APPLE__ #ifdef __APPLE__
#define TESTINSTR_SECTION #define TESTINSTR_SECTION
@ -25,8 +26,10 @@ void LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size < 1) return; if (size < 1) return;
int r = rand(); struct timeval tv = {0};
if ((r % 2) == 0) { if (gettimeofday(&tv, NULL) < 0) return;
if ((tv.tv_usec % 2) == 0) {
printf ("Hooray all even\n"); printf ("Hooray all even\n");
} else { } else {
printf ("Hmm that's odd\n"); printf ("Hmm that's odd\n");

View File

@ -125,6 +125,13 @@ class Afl {
Afl.jsApiSetInstrumentCacheSize(size); Afl.jsApiSetInstrumentCacheSize(size);
} }
/**
* See `AFL_FRIDA_INST_COVERAGE_ABSOLUTE`.
*/
public static setInstrumentCoverageAbsolute(): void {
Afl.jsApiSetInstrumentCoverageAbsolute();
}
/** /**
* See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string` * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
* as an argument. * as an argument.
@ -398,6 +405,12 @@ class Afl {
"void", "void",
["size_t"]); ["size_t"]);
private static readonly jsApiSetInstrumentCoverageAbsolute = Afl.jsApiGetFunction(
"js_api_set_instrument_coverage_absolute",
"void",
[]
);
private static readonly jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction( private static readonly jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction(
"js_api_set_instrument_coverage_file", "js_api_set_instrument_coverage_file",
"void", "void",

View File

@ -58,6 +58,7 @@ static char *afl_environment_variables[] = {
"AFL_FRIDA_DRIVER_NO_HOOK", "AFL_FRIDA_DRIVER_NO_HOOK",
"AFL_FRIDA_EXCLUDE_RANGES", "AFL_FRIDA_EXCLUDE_RANGES",
"AFL_FRIDA_INST_CACHE_SIZE", "AFL_FRIDA_INST_CACHE_SIZE",
"AFL_FRIDA_INST_COVERAGE_ABSOLUTE",
"AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_COVERAGE_FILE",
"AFL_FRIDA_INST_DEBUG_FILE", "AFL_FRIDA_INST_DEBUG_FILE",
"AFL_FRIDA_INST_INSN", "AFL_FRIDA_INST_INSN",