Support for setting a fixed seed for the hash function
MODIFY
frida_mode/README.md
frida_mode/README.md
@@ -162,6 +162,9 @@ instrumentation (the default where available). Required to use
* `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.
+* `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

MODIFY
frida_mode/frida.map
frida_mode/frida.map
js_api_set_instrument_jit;
js_api_set_instrument_libraries;
js_api_set_instrument_no_optimize;
+ js_api_set_instrument_seed;
js_api_set_instrument_trace;
js_api_set_instrument_trace_unique;
js_api_set_persistent_address;

MODIFY
frida_mode/include/instrument.h
frida_mode/include/instrument.h
@@ -12,6 +12,9 @@ extern gboolean instrument_unique;
extern __thread guint64 instrument_previous_pc;
extern guint64 instrument_hash_zero;
+extern gboolean instrument_use_fixed_seed;
+extern guint64 instrument_fixed_seed;
+
extern uint8_t *__afl_area_ptr;
extern uint32_t __afl_map_size;

MODIFY
frida_mode/src/instrument/instrument.c
frida_mode/src/instrument/instrument.c
@@ -27,6 +27,9 @@ gboolean instrument_unique = false;
guint64 instrument_hash_zero = 0;
guint64 instrument_hash_seed = 0;
+gboolean instrument_use_fixed_seed = FALSE;
+guint64 instrument_fixed_seed = 0;
+
static GumStalkerTransformer *transformer = NULL;
__thread guint64 instrument_previous_pc = 0;
@@ -221,6 +224,8 @@ void instrument_config(void) {
instrument_optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL);
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_debug_config();
asan_config();
@@ -235,6 +240,8 @@ void instrument_init(void) {
OKF("Instrumentation - optimize [%c]", instrument_optimize ? 'X' : ' ');
OKF("Instrumentation - tracing [%c]", instrument_tracing ? 'X' : ' ');
OKF("Instrumentation - unique [%c]", instrument_unique ? 'X' : ' ');
+ OKF("Instrumentation - fixed seed [%c] [0x%016" G_GINT64_MODIFIER "x]",
+ instrument_use_fixed_seed ? 'X' : ' ', instrument_fixed_seed);
if (instrument_tracing && instrument_optimize) {
@@ -270,7 +277,8 @@ void instrument_init(void) {
g_assert(edges_notified != MAP_FAILED);
/*
- * Configure the shared memory region to be removed once the process dies.
+ * Configure the shared memory region to be removed once the process
+ * dies.
*/
if (shmctl(shm_id, IPC_RMID, NULL) < 0) {
@@ -283,14 +291,26 @@ void instrument_init(void) {
}
+ if (instrument_use_fixed_seed) {
+
+ /*
+ * This configuration option may be useful for diagnostics or
+ * debugging.
+ */
+ instrument_hash_seed = instrument_fixed_seed;
+
+ } else {
+
/*
* By using a different seed value for the hash, we can make different
* instances have edge collisions in different places when carrying out
- * parallel fuzzing. The seed itself, doesn't have to be random, it just
- * needs to be different for each instance.
+ * parallel fuzzing. The seed itself, doesn't have to be random, it
+ * just needs to be different for each instance.
*/
- instrument_hash_seed =
- g_get_monotonic_time() ^ (((guint64)getpid()) << 32) ^ syscall(SYS_gettid);
+ instrument_hash_seed = g_get_monotonic_time() ^
+ (((guint64)getpid()) << 32) ^ syscall(SYS_gettid);
+
+ }
OKF("Instrumentation - seed [0x%016" G_GINT64_MODIFIER "x]",
instrument_hash_seed);

MODIFY
frida_mode/src/js/api.js
frida_mode/src/js/api.js
@@ -117,6 +117,12 @@ class Afl {
static setInstrumentNoOptimize() {
Afl.jsApiSetInstrumentNoOptimize();
}
+ /*
+ * See `AFL_FRIDA_INST_SEED`
+ */
+ static setInstrumentSeed(seed) {
+ Afl.jsApiSetInstrumentSeed(seed);
+ }
/**
* See `AFL_FRIDA_INST_TRACE_UNIQUE`.
*/
@@ -231,6 +237,7 @@ Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_de
Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []);
Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []);
Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []);
+Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", "void", ["uint64"]);
Afl.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []);
Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []);
Afl.jsApiSetPersistentAddress = Afl.jsApiGetFunction("js_api_set_persistent_address", "void", ["pointer"]);

MODIFY
frida_mode/src/js/js.c
frida_mode/src/js/js.c
@@ -89,10 +89,7 @@ static void load_cb(GObject *source_object, GAsyncResult *result,
UNUSED_PARAMETER(source_object);
UNUSED_PARAMETER(user_data);
gum_script_load_finish(script, result);
- if (error != NULL)
- {
- FATAL("Failed to load script - %s", error->message);
- }
+ if (error != NULL) { FATAL("Failed to load script - %s", error->message); }
}
@@ -102,10 +99,7 @@ static void create_cb(GObject *source_object, GAsyncResult *result,
UNUSED_PARAMETER(source_object);
UNUSED_PARAMETER(user_data);
script = gum_script_backend_create_finish(backend, result, &error);
- if (error != NULL)
- {
- FATAL("Failed to create script: %s", error->message);
- }
+ if (error != NULL) { FATAL("Failed to create script: %s", error->message); }
gum_script_set_message_handler(script, js_msg, NULL, NULL);
@@ -145,3 +139,4 @@ gboolean js_stalker_callback(const cs_insn *insn, gboolean begin,
return js_user_callback(insn, begin, excluded, output);
}
+

MODIFY
frida_mode/src/js/js_api.c
frida_mode/src/js/js_api.c
@@ -127,6 +127,14 @@ __attribute__((visibility("default"))) void js_api_set_instrument_no_optimize(
}
+__attribute__((visibility("default"))) void js_api_set_instrument_seed(
+ guint64 seed) {
+
+ instrument_use_fixed_seed = TRUE;
+ instrument_fixed_seed = seed;
+
+}
+
__attribute__((visibility("default"))) void js_api_set_instrument_trace(void) {
instrument_tracing = TRUE;

MODIFY
frida_mode/ts/lib/afl.ts
frida_mode/ts/lib/afl.ts
@@ -140,6 +140,13 @@ class Afl {
Afl.jsApiSetInstrumentNoOptimize();
}
+ /*
+ * See `AFL_FRIDA_INST_SEED`
+ */
+ public static setInstrumentSeed(seed: NativePointer): void {
+ Afl.jsApiSetInstrumentSeed(seed);
+ }
+
/**
* See `AFL_FRIDA_INST_TRACE_UNIQUE`.
*/
@@ -295,6 +302,11 @@ class Afl {
"void",
[]);
+ private static readonly jsApiSetInstrumentSeed = Afl.jsApiGetFunction(
+ "js_api_set_instrument_seed",
+ "void",
+ ["uint64"]);
+
private static readonly jsApiSetInstrumentTrace = Afl.jsApiGetFunction(
"js_api_set_instrument_trace",
"void",

MODIFY
include/envs.h
include/envs.h
@@ -60,6 +60,7 @@ static char *afl_environment_variables[] = {
"AFL_FRIDA_INST_NO_OPTIMIZE",
"AFL_FRIDA_INST_NO_PREFETCH",
"AFL_FRIDA_INST_RANGES",
+ "AFL_FRIDA_INST_SEED",
"AFL_FRIDA_INST_TRACE",
"AFL_FRIDA_INST_TRACE_UNIQUE",
"AFL_FRIDA_JS_SCRIPT",

Support for setting a fixed seed for the hash function (#1026)

Co-authored-by: Your Name <you@example.com>