aboutsummaryrefslogtreecommitdiff
path: root/frida_mode/src/js
diff options
context:
space:
mode:
Diffstat (limited to 'frida_mode/src/js')
-rw-r--r--frida_mode/src/js/api.js243
-rw-r--r--frida_mode/src/js/js.c122
-rw-r--r--frida_mode/src/js/js_api.c152
3 files changed, 517 insertions, 0 deletions
diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js
new file mode 100644
index 00000000..4cb04704
--- /dev/null
+++ b/frida_mode/src/js/api.js
@@ -0,0 +1,243 @@
+"use strict";
+class Afl {
+ /**
+ * This is equivalent to setting a value in `AFL_FRIDA_EXCLUDE_RANGES`,
+ * it takes as arguments a `NativePointer` and a `number`. It can be
+ * called multiple times to exclude several ranges.
+ */
+ static addExcludedRange(addressess, size) {
+ Afl.jsApiAddExcludeRange(addressess, size);
+ }
+ /**
+ * This is equivalent to setting a value in `AFL_FRIDA_INST_RANGES`,
+ * it takes as arguments a `NativePointer` and a `number`. It can be
+ * called multiple times to include several ranges.
+ */
+ static addIncludedRange(addressess, size) {
+ Afl.jsApiAddIncludeRange(addressess, size);
+ }
+ /**
+ * This must always be called at the end of your script. This lets
+ * FRIDA mode know that your configuration is finished and that
+ * execution has reached the end of your script. Failure to call
+ * this will result in a fatal error.
+ */
+ static done() {
+ Afl.jsApiDone();
+ }
+ /**
+ * This function can be called within your script to cause FRIDA
+ * mode to trigger a fatal error. This is useful if for example you
+ * discover a problem you weren't expecting and want everything to
+ * stop. The user will need to enable `AFL_DEBUG_CHILD=1` to view
+ * this error message.
+ */
+ static error(msg) {
+ const buf = Memory.allocUtf8String(msg);
+ Afl.jsApiError(buf);
+ }
+ /**
+ * Function used to provide access to `__afl_fuzz_ptr`, which contains the length of
+ * fuzzing data when using in-memory test case fuzzing.
+ */
+ static getAflFuzzLen() {
+ return Afl.jsApiGetSymbol("__afl_fuzz_len");
+ }
+ /**
+ * Function used to provide access to `__afl_fuzz_ptr`, which contains the fuzzing
+ * data when using in-memory test case fuzzing.
+ */
+ static getAflFuzzPtr() {
+ return Afl.jsApiGetSymbol("__afl_fuzz_ptr");
+ }
+ /**
+ * Print a message to the STDOUT. This should be preferred to
+ * FRIDA's `console.log` since FRIDA will queue it's log messages.
+ * If `console.log` is used in a callback in particular, then there
+ * may no longer be a thread running to service this queue.
+ */
+ static print(msg) {
+ const STDOUT_FILENO = 2;
+ const log = `${msg}\n`;
+ const buf = Memory.allocUtf8String(log);
+ Afl.jsApiWrite(STDOUT_FILENO, buf, log.length);
+ }
+ /**
+ * See `AFL_FRIDA_DEBUG_MAPS`.
+ */
+ static setDebugMaps() {
+ Afl.jsApiSetDebugMaps();
+ }
+ /**
+ * This has the same effect as setting `AFL_ENTRYPOINT`, but has the
+ * convenience of allowing you to use FRIDAs APIs to determine the
+ * address you would like to configure, rather than having to grep
+ * the output of `readelf` or something similarly ugly. This
+ * function should be called with a `NativePointer` as its
+ * argument.
+ */
+ static setEntryPoint(address) {
+ Afl.jsApiSetEntryPoint(address);
+ }
+ /**
+ * Function used to enable in-memory test cases for fuzzing.
+ */
+ static setInMemoryFuzzing() {
+ Afl.jsApiAflSharedMemFuzzing.writeInt(1);
+ }
+ /**
+ * See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as
+ * an argument.
+ */
+ static setInstrumentDebugFile(file) {
+ const buf = Memory.allocUtf8String(file);
+ Afl.jsApiSetInstrumentDebugFile(buf);
+ }
+ /**
+ * See `AFL_FRIDA_INST_TRACE`.
+ */
+ static setInstrumentEnableTracing() {
+ Afl.jsApiSetInstrumentTrace();
+ }
+ /**
+ * See `AFL_INST_LIBS`.
+ */
+ static setInstrumentLibraries() {
+ Afl.jsApiSetInstrumentLibraries();
+ }
+ /**
+ * See `AFL_FRIDA_INST_NO_OPTIMIZE`
+ */
+ static setInstrumentNoOptimize() {
+ Afl.jsApiSetInstrumentNoOptimize();
+ }
+ /**
+ * See `AFL_FRIDA_INST_TRACE_UNIQUE`.
+ */
+ static setInstrumentTracingUnique() {
+ Afl.jsApiSetInstrumentTraceUnique();
+ }
+ /**
+ * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a
+ * `NativePointer` should be provided as it's argument.
+ */
+ static setPersistentAddress(address) {
+ Afl.jsApiSetPersistentAddress(address);
+ }
+ /**
+ * This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a
+ * `number` should be provided as it's argument.
+ */
+ static setPersistentCount(count) {
+ Afl.jsApiSetPersistentCount(count);
+ }
+ /**
+ * See `AFL_FRIDA_PERSISTENT_DEBUG`.
+ */
+ static setPersistentDebug() {
+ Afl.jsApiSetPersistentDebug();
+ }
+ /**
+ * See `AFL_FRIDA_PERSISTENT_ADDR`. This function takes a NativePointer as an
+ * argument. See above for examples of use.
+ */
+ static setPersistentHook(address) {
+ Afl.jsApiSetPersistentHook(address);
+ }
+ /**
+ * This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a
+ * `NativePointer` should be provided as it's argument.
+ */
+ static setPersistentReturn(address) {
+ Afl.jsApiSetPersistentReturn(address);
+ }
+ /**
+ * See `AFL_FRIDA_INST_NO_PREFETCH`.
+ */
+ static setPrefetchDisable() {
+ Afl.jsApiSetPrefetchDisable();
+ }
+ /*
+ * Set a function to be called for each instruction which is instrumented
+ * by AFL FRIDA mode.
+ */
+ static setStalkerCallback(callback) {
+ Afl.jsApiSetStalkerCallback(callback);
+ }
+ /**
+ * See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as
+ * an argument.
+ */
+ static setStatsFile(file) {
+ const buf = Memory.allocUtf8String(file);
+ Afl.jsApiSetStatsFile(buf);
+ }
+ /**
+ * See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an
+ * argument
+ */
+ static setStatsInterval(interval) {
+ Afl.jsApiSetStatsInterval(interval);
+ }
+ /**
+ * See `AFL_FRIDA_STATS_TRANSITIONS`
+ */
+ static setStatsTransitions() {
+ Afl.jsApiSetStatsTransitions();
+ }
+ /**
+ * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as
+ * an argument.
+ */
+ static setStdErr(file) {
+ const buf = Memory.allocUtf8String(file);
+ Afl.jsApiSetStdErr(buf);
+ }
+ /**
+ * See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as
+ * an argument.
+ */
+ static setStdOut(file) {
+ const buf = Memory.allocUtf8String(file);
+ Afl.jsApiSetStdOut(buf);
+ }
+ static jsApiGetFunction(name, retType, argTypes) {
+ const addr = Afl.module.getExportByName(name);
+ return new NativeFunction(addr, retType, argTypes);
+ }
+ static jsApiGetSymbol(name) {
+ return Afl.module.getExportByName(name);
+ }
+}
+/**
+ * Field containing the `Module` object for `afl-frida-trace.so` (the FRIDA mode
+ * implementation).
+ */
+Afl.module = Process.getModuleByName("afl-frida-trace.so");
+Afl.jsApiAddExcludeRange = Afl.jsApiGetFunction("js_api_add_exclude_range", "void", ["pointer", "size_t"]);
+Afl.jsApiAddIncludeRange = Afl.jsApiGetFunction("js_api_add_include_range", "void", ["pointer", "size_t"]);
+Afl.jsApiAflSharedMemFuzzing = Afl.jsApiGetSymbol("__afl_sharedmem_fuzzing");
+Afl.jsApiDone = Afl.jsApiGetFunction("js_api_done", "void", []);
+Afl.jsApiError = Afl.jsApiGetFunction("js_api_error", "void", ["pointer"]);
+Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []);
+Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
+Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]);
+Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []);
+Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []);
+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"]);
+Afl.jsApiSetPersistentCount = Afl.jsApiGetFunction("js_api_set_persistent_count", "void", ["uint64"]);
+Afl.jsApiSetPersistentDebug = Afl.jsApiGetFunction("js_api_set_persistent_debug", "void", []);
+Afl.jsApiSetPersistentHook = Afl.jsApiGetFunction("js_api_set_persistent_hook", "void", ["pointer"]);
+Afl.jsApiSetPersistentReturn = Afl.jsApiGetFunction("js_api_set_persistent_return", "void", ["pointer"]);
+Afl.jsApiSetPrefetchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_disable", "void", []);
+Afl.jsApiSetStalkerCallback = Afl.jsApiGetFunction("js_api_set_stalker_callback", "void", ["pointer"]);
+Afl.jsApiSetStatsFile = Afl.jsApiGetFunction("js_api_set_stats_file", "void", ["pointer"]);
+Afl.jsApiSetStatsInterval = Afl.jsApiGetFunction("js_api_set_stats_interval", "void", ["uint64"]);
+Afl.jsApiSetStatsTransitions = Afl.jsApiGetFunction("js_api_set_stats_transitions", "void", []);
+Afl.jsApiSetStdErr = Afl.jsApiGetFunction("js_api_set_stderr", "void", ["pointer"]);
+Afl.jsApiSetStdOut = Afl.jsApiGetFunction("js_api_set_stdout", "void", ["pointer"]);
+Afl.jsApiWrite = new NativeFunction(
+/* tslint:disable-next-line:no-null-keyword */
+Module.getExportByName(null, "write"), "int", ["int", "pointer", "int"]);
diff --git a/frida_mode/src/js/js.c b/frida_mode/src/js/js.c
new file mode 100644
index 00000000..ed378d2c
--- /dev/null
+++ b/frida_mode/src/js/js.c
@@ -0,0 +1,122 @@
+#include "frida-gumjs.h"
+
+#include "debug.h"
+
+#include "js.h"
+#include "util.h"
+
+static char * js_script = NULL;
+gboolean js_done = FALSE;
+js_api_stalker_callback_t js_user_callback = NULL;
+
+static gchar * filename = "afl.js";
+static gchar * contents;
+static GumScriptBackend *backend;
+static GCancellable * cancellable = NULL;
+static GError * error = NULL;
+static GumScript * script;
+
+static void js_msg(GumScript *script, const gchar *message, GBytes *data,
+ gpointer user_data) {
+
+ UNUSED_PARAMETER(script);
+ UNUSED_PARAMETER(data);
+ UNUSED_PARAMETER(user_data);
+ OKF("%s", message);
+
+}
+
+void js_config(void) {
+
+ js_script = getenv("AFL_FRIDA_JS_SCRIPT");
+
+}
+
+static gchar *js_get_script() {
+
+ gsize length;
+ if (js_script != NULL) { filename = js_script; }
+
+ filename = g_canonicalize_filename(filename, g_get_current_dir());
+
+ if (!g_file_get_contents(filename, &contents, &length, NULL)) {
+
+ if (js_script == NULL) {
+
+ return NULL;
+
+ } else {
+
+ FATAL("Could not load script file: %s", filename);
+
+ }
+
+ } else {
+
+ OKF("Loaded AFL script: %s, %" G_GSIZE_MODIFIER "d bytes", filename,
+ length);
+
+ gchar *source = g_malloc0(api_js_len + length + 1);
+ memcpy(source, api_js, api_js_len);
+ memcpy(&source[api_js_len], contents, length);
+
+ return source;
+
+ }
+
+}
+
+static void js_print_script(gchar *source) {
+
+ gchar **split = g_strsplit(source, "\n", 0);
+
+ for (size_t i = 0; split[i] != NULL; i++) {
+
+ OKF("%3" G_GSIZE_MODIFIER "d. %s", i + 1, split[i]);
+
+ }
+
+ g_strfreev(split);
+
+}
+
+void js_start(void) {
+
+ GMainContext *context;
+
+ gchar *source = js_get_script();
+ if (source == NULL) { return; }
+ js_print_script(source);
+
+ backend = gum_script_backend_obtain_qjs();
+
+ script = gum_script_backend_create_sync(backend, "example", source,
+ cancellable, &error);
+
+ if (error != NULL) {
+
+ g_printerr("%s\n", error->message);
+ FATAL("Error processing script");
+
+ }
+
+ gum_script_set_message_handler(script, js_msg, NULL, NULL);
+
+ gum_script_load_sync(script, cancellable);
+
+ context = g_main_context_get_thread_default();
+ while (g_main_context_pending(context))
+ g_main_context_iteration(context, FALSE);
+
+ if (!js_done) { FATAL("Script didn't call Afl.done()"); }
+
+}
+
+gboolean js_stalker_callback(const cs_insn *insn, gboolean begin,
+ gboolean excluded, GumStalkerOutput *output) {
+
+ if (js_user_callback == NULL) { return TRUE; }
+ return js_user_callback(insn, begin, excluded, output);
+
+}
+
diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c
new file mode 100644
index 00000000..91dccab2
--- /dev/null
+++ b/frida_mode/src/js/js_api.c
@@ -0,0 +1,152 @@
+#include "debug.h"
+
+#include "entry.h"
+#include "instrument.h"
+#include "js.h"
+#include "output.h"
+#include "persistent.h"
+#include "prefetch.h"
+#include "ranges.h"
+#include "stats.h"
+#include "util.h"
+
+void js_api_done() {
+
+ js_done = TRUE;
+
+}
+
+void js_api_error(char *msg) {
+
+ FATAL("%s", msg);
+
+}
+
+void js_api_set_entrypoint(void *address) {
+
+ entry_point = GPOINTER_TO_SIZE(address);
+
+}
+
+void js_api_set_persistent_address(void *address) {
+
+ persistent_start = GPOINTER_TO_SIZE(address);
+
+}
+
+void js_api_set_persistent_return(void *address) {
+
+ persistent_ret = GPOINTER_TO_SIZE(address);
+
+}
+
+void js_api_set_persistent_count(uint64_t count) {
+
+ persistent_count = count;
+
+}
+
+void js_api_set_persistent_debug() {
+
+ persistent_debug = TRUE;
+
+}
+
+void js_api_set_debug_maps() {
+
+ ranges_debug_maps = TRUE;
+
+}
+
+void js_api_add_include_range(void *address, gsize size) {
+
+ GumMemoryRange range = {.base_address = GUM_ADDRESS(address), .size = size};
+ ranges_add_include(&range);
+
+}
+
+void js_api_add_exclude_range(void *address, gsize size) {
+
+ GumMemoryRange range = {.base_address = GUM_ADDRESS(address), .size = size};
+ ranges_add_exclude(&range);
+
+}
+
+void js_api_set_instrument_libraries() {
+
+ ranges_inst_libs = TRUE;
+
+}
+
+void js_api_set_instrument_debug_file(char *path) {
+
+ instrument_debug_filename = g_strdup(path);
+
+}
+
+void js_api_set_prefetch_disable(void) {
+
+ prefetch_enable = FALSE;
+
+}
+
+void js_api_set_instrument_no_optimize(void) {
+
+ instrument_optimize = FALSE;
+
+}
+
+void js_api_set_instrument_trace(void) {
+
+ instrument_tracing = TRUE;
+
+}
+
+void js_api_set_instrument_trace_unique(void) {
+
+ instrument_unique = TRUE;
+
+}
+
+void js_api_set_stdout(char *file) {
+
+ output_stdout = g_strdup(file);
+
+}
+
+void js_api_set_stderr(char *file) {
+
+ output_stderr = g_strdup(file);
+
+}
+
+void js_api_set_stats_file(char *file) {
+
+ stats_filename = g_strdup(file);
+
+}
+
+void js_api_set_stats_interval(uint64_t interval) {
+
+ stats_interval = interval;
+
+}
+
+void js_api_set_stats_transitions() {
+
+ stats_transitions = TRUE;
+
+}
+
+void js_api_set_persistent_hook(void *address) {
+
+ persistent_hook = address;
+
+}
+
+void js_api_set_stalker_callback(const js_api_stalker_callback_t callback) {
+
+ js_user_callback = callback;
+
+}
+