about summary refs log tree commit diff
path: root/frida_mode/src/js
diff options
context:
space:
mode:
authorWorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com>2021-06-24 18:46:08 +0100
committerGitHub <noreply@github.com>2021-06-24 19:46:08 +0200
commitf348a35ec6cece54796599865c683505a475fe88 (patch)
tree38b46a34787b467a203d7432a8a3886b4123d621 /frida_mode/src/js
parent4057134d3c6ed202d426ebdcc9aa4edf3e122bda (diff)
downloadafl++-f348a35ec6cece54796599865c683505a475fe88.tar.gz
Added JS support (#992)
* Added JS support

* Added some documentation

Co-authored-by: Your Name <you@example.com>
Diffstat (limited to 'frida_mode/src/js')
-rw-r--r--frida_mode/src/js/api.js201
-rw-r--r--frida_mode/src/js/js.c113
-rw-r--r--frida_mode/src/js/js_api.c142
3 files changed, 456 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..983f1efa
--- /dev/null
+++ b/frida_mode/src/js/api.js
@@ -0,0 +1,201 @@
+const write = new NativeFunction(
+    Module.getExportByName(null, 'write'),
+    'int',
+    ['int', 'pointer', 'int']
+);
+
+const afl_frida_trace = Process.findModuleByName('afl-frida-trace.so');
+
+function get_api(name, ret, args) {
+    const addr = afl_frida_trace.findExportByName(name);
+    return new NativeFunction(addr, ret, args);
+}
+
+const js_api_done = get_api(
+    'js_api_done',
+    'void',
+    []);
+
+const js_api_error = get_api(
+    'js_api_error',
+    'void',
+    ['pointer']);
+
+const js_api_set_entrypoint = get_api(
+    'js_api_set_entrypoint',
+    'void',
+    ['pointer']);
+
+const js_api_set_persistent_address = get_api(
+    'js_api_set_persistent_address',
+    'void',
+    ['pointer']);
+
+const js_api_set_persistent_return = get_api(
+    'js_api_set_persistent_return',
+    'void',
+    ['pointer']);
+
+const js_api_set_persistent_count = get_api(
+    'js_api_set_persistent_count',
+    'void',
+    ['uint64']);
+
+const js_api_set_persistent_debug = get_api(
+    'js_api_set_persistent_debug',
+    'void',
+    []);
+
+const js_api_set_debug_maps = get_api(
+    'js_api_set_debug_maps',
+    'void',
+    []);
+
+const js_api_add_include_range = get_api(
+    'js_api_add_include_range',
+    'void',
+    ['pointer', 'size_t']);
+
+const js_api_add_exclude_range = get_api(
+    'js_api_add_exclude_range',
+    'void',
+    ['pointer', 'size_t']);
+
+const js_api_set_instrument_libraries = get_api(
+    'js_api_set_instrument_libraries',
+    'void',
+    []);
+
+const js_api_set_instrument_debug_file = get_api(
+    'js_api_set_instrument_debug_file',
+    'void',
+    ['pointer']);
+
+const js_api_set_prefetch_disable = get_api(
+    'js_api_set_prefetch_disable',
+    'void',
+    []);
+
+const js_api_set_instrument_no_optimize = get_api(
+    'js_api_set_instrument_no_optimize',
+    'void',
+    []);
+
+const js_api_set_instrument_trace = get_api(
+    'js_api_set_instrument_trace',
+    'void',
+    []);
+
+const js_api_set_instrument_trace_unique = get_api(
+    'js_api_set_instrument_trace_unique',
+    'void',
+    []);
+
+const js_api_set_stdout = get_api(
+    'js_api_set_stdout',
+    'void',
+    ['pointer']);
+
+const js_api_set_stderr = get_api(
+    'js_api_set_stderr',
+    'void',
+    ['pointer']);
+
+const js_api_set_stats_file = get_api(
+    'js_api_set_stats_file',
+    'void',
+    ['pointer']);
+
+const js_api_set_stats_interval = get_api(
+    'js_api_set_stats_interval',
+    'void',
+    ['uint64']);
+
+const js_api_set_stats_transitions = get_api(
+    'js_api_set_stats_transitions',
+    'void',
+    []);
+
+const afl = {
+    print: function (msg) {
+        const STDOUT_FILENO = 2;
+        const log = `${msg}\n`;
+        const buf = Memory.allocUtf8String(log);
+        write(STDOUT_FILENO, buf, log.length);
+    },
+    done: function() {
+        js_api_done();
+    },
+    error: function(msg) {
+        const buf = Memory.allocUtf8String(msg);
+        js_api_error(buf);
+    },
+    setEntryPoint: function(addr) {
+        js_api_set_entrypoint(addr);
+    },
+    setPersistentAddress: function(addr) {
+        js_api_set_persistent_address(addr);
+    },
+    setPersistentReturn: function(addr) {
+        js_api_set_persistent_return(addr);
+    },
+    setPersistentCount: function(addr) {
+        js_api_set_persistent_count(addr);
+    },
+    setPersistentDebug: function() {
+        js_api_set_persistent_debug();
+    },
+    setDebugMaps: function() {
+        js_api_set_debug_maps();
+    },
+    addIncludedRange: function(address, size) {
+        js_api_add_include_range(address, size);
+    },
+    addExcludedRange: function(address, size) {
+        js_api_add_exclude_range(address, size);
+    },
+    setInstrumentLibraries: function() {
+        js_api_set_instrument_libraries();
+    },
+    setInstrumentDebugFile: function(file) {
+        const buf = Memory.allocUtf8String(file);
+        js_api_set_instrument_debug_file(buf)
+    },
+    setPrefetchDisable: function() {
+        js_api_set_prefetch_disable();
+    },
+    setInstrumentNoOptimize: function() {
+        js_api_set_instrument_no_optimize();
+    },
+    setInstrumentEnableTracing: function() {
+        js_api_set_instrument_trace();
+    },
+    setInstrumentTracingUnique: function() {
+        js_api_set_instrument_trace_unique();
+    },
+    setStdOut: function(file) {
+        const buf = Memory.allocUtf8String(file);
+        js_api_set_stdout(buf)
+    },
+    setStdErr: function(file) {
+        const buf = Memory.allocUtf8String(file);
+        js_api_set_stderr(buf)
+    },
+    setStatsFile: function(file) {
+        const buf = Memory.allocUtf8String(file);
+        js_api_set_stats_file(buf)
+    },
+    setStatsInterval: function(interval) {
+        js_api_set_stats_interval(interval);
+    },
+    setStatsTransitions: function() {
+        js_api_set_stats_transitions();
+    }
+
+};
+
+Object.defineProperty(global, 'Afl', {value: afl, writeable: false});
+
+////////////////////////////////////////////////////////////////////////////////
+//                          END OF API                                        //
+////////////////////////////////////////////////////////////////////////////////
diff --git a/frida_mode/src/js/js.c b/frida_mode/src/js/js.c
new file mode 100644
index 00000000..79e716ad
--- /dev/null
+++ b/frida_mode/src/js/js.c
@@ -0,0 +1,113 @@
+#include "frida-gumjs.h"
+
+#include "debug.h"
+
+#include "js.h"
+#include "util.h"
+
+static char *js_script = NULL;
+gboolean     js_done = FALSE;
+
+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()"); }
+
+}
+
diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c
new file mode 100644
index 00000000..018c0b9a
--- /dev/null
+++ b/frida_mode/src/js/js_api.c
@@ -0,0 +1,142 @@
+#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;
+
+}
+
+// "AFL_FRIDA_PERSISTENT_HOOK",
+