aboutsummaryrefslogtreecommitdiff
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",
+