#include "frida-gumjs.h"
#include "js.h"
#include "util.h"
gboolean js_done = FALSE;
js_api_stalker_callback_t js_user_callback = NULL;
js_main_hook_t js_main_hook = NULL;
static char *js_script = NULL;
static gchar *filename = "afl.js";
static gchar *contents;
static GumScriptBackend *backend;
static GCancellable *cancellable = NULL;
static GError *error = NULL;
static GumScript *script;
static GumScriptScheduler *scheduler;
static GMainContext *context;
static GMainLoop *main_loop;
static void js_msg(const gchar *message, GBytes *data, gpointer user_data) {
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(user_data);
FOKF("%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 {
FFATAL("Could not load script file: %s", filename);
}
} else {
FOKF(cBLU "Javascript" cRST " - " cGRN "script:" cYEL " [%s]",
filename == NULL ? " " : filename);
FOKF(cBLU "Javascript" cRST " - " cGRN "size: " cYEL "%" G_GSIZE_MODIFIER
"d bytes",
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++) {
FVERBOSE("%3" G_GSIZE_MODIFIER "d. %s", i + 1, split[i]);
}
g_strfreev(split);
}
static void load_cb(GObject *source_object, GAsyncResult *result,
gpointer user_data) {
UNUSED_PARAMETER(source_object);
UNUSED_PARAMETER(user_data);
gum_script_load_finish(script, result);
if (error != NULL) { FFATAL("Failed to load script - %s", error->message); }
}
static void create_cb(GObject *source_object, GAsyncResult *result,
gpointer user_data) {
UNUSED_PARAMETER(source_object);
UNUSED_PARAMETER(user_data);
script = gum_script_backend_create_finish(backend, result, &error);
if (error != NULL) { FFATAL("Failed to create script: %s", error->message); }
gum_script_set_message_handler(script, js_msg, NULL, NULL);
gum_script_load(script, cancellable, load_cb, NULL);
}
void js_start(void) {
gchar *source = js_get_script();
if (source == NULL) { return; }
js_print_script(source);
scheduler = gum_script_backend_get_scheduler();
gum_script_scheduler_disable_background_thread(scheduler);
backend = gum_script_backend_obtain_qjs();
context = gum_script_scheduler_get_js_context(scheduler);
main_loop = g_main_loop_new(context, true);
g_main_context_push_thread_default(context);
gum_script_backend_create(backend, "example", source, NULL, cancellable,
create_cb, &error);
while (g_main_context_pending(context))
g_main_context_iteration(context, FALSE);
if (!js_done) { FFATAL("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);
}