From f348a35ec6cece54796599865c683505a475fe88 Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Thu, 24 Jun 2021 18:46:08 +0100 Subject: Added JS support (#992) * Added JS support * Added some documentation Co-authored-by: Your Name --- frida_mode/src/js/js_api.c | 142 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 frida_mode/src/js/js_api.c (limited to 'frida_mode/src/js/js_api.c') 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", + -- cgit 1.4.1 From 6a3877dcd35d31eb79bebbc30ffe70ac0342743e Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Fri, 25 Jun 2021 22:14:27 +0100 Subject: Improved FRIDA mode scripting support (#994) Co-authored-by: Your Name --- frida_mode/.gitignore | 2 + frida_mode/GNUmakefile | 17 +- frida_mode/Makefile | 3 + frida_mode/Scripting.md | 828 ++++++++++++++++++--- frida_mode/hook/hook.c | 50 ++ frida_mode/include/js.h | 10 +- frida_mode/src/entry.c | 1 + frida_mode/src/instrument/instrument.c | 11 +- frida_mode/src/js/api.js | 430 ++++++----- frida_mode/src/js/js.c | 13 +- frida_mode/src/js/js_api.c | 12 +- frida_mode/src/persistent/persistent.c | 28 +- frida_mode/src/persistent/persistent_arm64.c | 399 ++++------ frida_mode/src/persistent/persistent_x64.c | 174 ++--- frida_mode/src/persistent/persistent_x86.c | 111 ++- frida_mode/test/jpeg/GNUmakefile | 10 +- frida_mode/test/jpeg/Makefile | 3 - frida_mode/test/jpeg/aflpp_qemu_driver_hook.c | 97 --- frida_mode/test/js/GNUmakefile | 56 +- frida_mode/test/js/Makefile | 13 +- frida_mode/test/js/entry.js | 20 + frida_mode/test/js/patch.js | 34 + frida_mode/test/js/replace.js | 43 ++ frida_mode/test/js/stalker.js | 109 +++ frida_mode/test/js/test.c | 115 +++ frida_mode/test/js/test.js | 20 - frida_mode/test/js/test2.c | 177 +++++ frida_mode/test/js/testinstr.c | 121 --- frida_mode/test/libpcap/GNUmakefile | 10 +- frida_mode/test/libpcap/aflpp_qemu_driver_hook.c | 97 --- frida_mode/test/persistent_ret/GNUmakefile | 11 +- frida_mode/test/persistent_ret/test.js | 62 +- frida_mode/test/persistent_ret/testinstr.c | 11 +- frida_mode/test/png/persistent/hook/GNUmakefile | 30 +- frida_mode/test/png/persistent/hook/Makefile | 3 + .../png/persistent/hook/aflpp_qemu_driver_hook.c | 193 ----- frida_mode/test/png/persistent/hook/cmodule.js | 39 + frida_mode/test/png/persistent/hook/load.js | 27 + frida_mode/test/proj4/GNUmakefile | 10 +- frida_mode/test/proj4/Makefile | 2 - frida_mode/test/proj4/aflpp_qemu_driver_hook.c | 97 --- frida_mode/test/re2/GNUmakefile | 10 +- frida_mode/test/re2/Makefile | 2 - frida_mode/test/re2/aflpp_qemu_driver_hook.c | 97 --- frida_mode/ts/lib/afl.ts | 373 ++++++++++ frida_mode/ts/package-lock.json | 12 + frida_mode/ts/package.json | 32 + frida_mode/ts/tsconfig.json | 14 + frida_mode/ts/tslint.json | 256 +++++++ 49 files changed, 2749 insertions(+), 1546 deletions(-) create mode 100644 frida_mode/hook/hook.c delete mode 100644 frida_mode/test/jpeg/aflpp_qemu_driver_hook.c create mode 100644 frida_mode/test/js/entry.js create mode 100644 frida_mode/test/js/patch.js create mode 100644 frida_mode/test/js/replace.js create mode 100644 frida_mode/test/js/stalker.js create mode 100644 frida_mode/test/js/test.c delete mode 100644 frida_mode/test/js/test.js create mode 100644 frida_mode/test/js/test2.c delete mode 100644 frida_mode/test/js/testinstr.c delete mode 100644 frida_mode/test/libpcap/aflpp_qemu_driver_hook.c delete mode 100644 frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c create mode 100644 frida_mode/test/png/persistent/hook/cmodule.js create mode 100644 frida_mode/test/png/persistent/hook/load.js delete mode 100644 frida_mode/test/proj4/aflpp_qemu_driver_hook.c delete mode 100644 frida_mode/test/re2/aflpp_qemu_driver_hook.c create mode 100644 frida_mode/ts/lib/afl.ts create mode 100644 frida_mode/ts/package-lock.json create mode 100644 frida_mode/ts/package.json create mode 100644 frida_mode/ts/tsconfig.json create mode 100644 frida_mode/ts/tslint.json (limited to 'frida_mode/src/js/js_api.c') diff --git a/frida_mode/.gitignore b/frida_mode/.gitignore index 956b9911..32cca51f 100644 --- a/frida_mode/.gitignore +++ b/frida_mode/.gitignore @@ -3,3 +3,5 @@ frida_test.dat qemu_test.dat frida_out/** qemu_out/** +ts/dist/ +ts/node_modules/ diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index fdacff62..f5a96501 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -94,11 +94,15 @@ FRIDA_GUM_DEVKIT_COMPRESSED_TARBALL:=$(FRIDA_DIR)build/$(GUM_DEVKIT_FILENAME) AFL_COMPILER_RT_SRC:=$(ROOT)instrumentation/afl-compiler-rt.o.c AFL_COMPILER_RT_OBJ:=$(OBJ_DIR)afl-compiler-rt.o -.PHONY: all 32 clean format $(FRIDA_GUM) quickjs +HOOK_DIR:=$(PWD)hook/ +AFLPP_DRIVER_HOOK_SRC=$(HOOK_DIR)hook.c +AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)hook.so + +.PHONY: all 32 clean format hook $(FRIDA_GUM) ############################## ALL ############################################# -all: $(FRIDA_TRACE) +all: $(FRIDA_TRACE) $(AFLPP_DRIVER_HOOK_OBJ) 32: CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all @@ -197,13 +201,20 @@ $(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL cp -v $(FRIDA_TRACE) $(ROOT) +############################# HOOK ############################################# + +$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -I $(FRIDA_BUILD_DIR) $< -o $@ + +hook: $(AFLPP_DRIVER_HOOK_OBJ) + ############################# CLEAN ############################################ clean: rm -rf $(BUILD_DIR) ############################# FORMAT ########################################### format: - cd $(ROOT) && echo $(SOURCES) | xargs -L1 ./.custom-format.py -i + cd $(ROOT) && echo $(SOURCES) $(AFLPP_DRIVER_HOOK_SRC) | xargs -L1 ./.custom-format.py -i cd $(ROOT) && echo $(INCLUDES) | xargs -L1 ./.custom-format.py -i ############################# RUN ############################################# diff --git a/frida_mode/Makefile b/frida_mode/Makefile index 6cd1a64e..1922c7e6 100644 --- a/frida_mode/Makefile +++ b/frida_mode/Makefile @@ -11,3 +11,6 @@ clean: format: @gmake format + +hook: + @gmake hook diff --git a/frida_mode/Scripting.md b/frida_mode/Scripting.md index 8b961e18..4c6fe6b2 100644 --- a/frida_mode/Scripting.md +++ b/frida_mode/Scripting.md @@ -99,142 +99,752 @@ const address = module.base.add(0xdeadface); Afl.setPersistentAddress(address); ``` -# API +# Persisent Hook +A persistent hook can be implemented using a conventional shared object, sample +source code for a hook suitable for the prototype of `LLVMFuzzerTestOneInput` +can be found [here](hook/hook.c). This can be configured using code similar to +the following. + ```js -/* - * 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. - */ -Afl.print(msg); +const path = Afl.module.path; +const dir = path.substring(0, path.lastIndexOf("/")); +const mod = Module.load(`${dir}/frida_mode/build/hook.so`); +const hook = mod.getExportByName('afl_persistent_hook'); +Afl.setPersistentHook(hook); +``` -/* - * 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. - */ +Alternatively, the hook can be provided by using FRIDAs built in support for `CModule`, powered by TinyCC. + +```js +const cm = new CModule(` + + #include + #include + + void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, + uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + + } + `, + { + memcpy: Module.getExportByName(null, 'memcpy') + }); +Afl.setPersistentHook(cm.afl_persistent_hook); +``` + +# Advanced Persistence +Consider the following target code... +```c + +#include +#include +#include +#include +#include + +void LLVMFuzzerTestOneInput(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +int run(char *file) { + + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + do { + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + LLVMFuzzerTestOneInput(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + +void slow() { + + usleep(100000); + +} + +int main(int argc, char **argv) { + + if (argc != 2) { return 1; } + slow(); + return run(argv[1]); + +} +``` + +FRIDA mode supports the replacement of any function, with an implementation +generated by CModule. This allows for a bespoke harness to be written as +follows: + +``` +const slow = DebugSymbol.fromName('slow').address; +Afl.print(`slow: ${slow}`); + +const LLVMFuzzerTestOneInput = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address; +Afl.print(`LLVMFuzzerTestOneInput: ${LLVMFuzzerTestOneInput}`); + +const cm = new CModule(` + + extern unsigned char * __afl_fuzz_ptr; + extern unsigned int * __afl_fuzz_len; + extern void LLVMFuzzerTestOneInput(char *buf, int len); + + void slow(void) { + + LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len); + } + `, + { + LLVMFuzzerTestOneInput: LLVMFuzzerTestOneInput, + __afl_fuzz_ptr: Afl.getAflFuzzPtr(), + __afl_fuzz_len: Afl.getAflFuzzLen() + }); + +Afl.setEntryPoint(cm.slow); +Afl.setPersistentAddress(cm.slow); +Afl.setInMemoryFuzzing(); +Interceptor.replace(slow, cm.slow); +Afl.print("done"); Afl.done(); +``` -/* - * 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. - */ -Afl.error(); +Here, we replace the function `slow` with our own code. This code is then +selected as the entry point as well as the persistent loop address. -/* - * 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. - */ -Afl.setEntryPoint(address); +**WARNING** There are two key limitations in replacing a function in this way: +- The function which is to be replaced must not be `main` this is because this +is the point at which FRIDA mode is initialized and at the point the the JS has +been run, the start of the `main` function has already been instrumented and +cached. +- The replacement function must not call itself. e.g. in this example we +couldn't replace `LLVMFuzzerTestOneInput` and call itself. -/* - * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a - * `NativePointer` should be provided as it's argument. - */ -Afl.setPersistentAddress(address); +# Patching +Consider the [following](test/js/test2.c) test code... +```c /* - * This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a - * `NativePointer` should be provided as it's argument. + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 */ -Afl.setPersistentReturn(address); -/* - * This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a - * `number` should be provided as it's argument. - */ -Afl.setPersistentCount(count); +#include +#include +#include +#include +#include +#include + +const uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + + ... + + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +uint32_t +crc32(const void *buf, size_t size) +{ + const uint8_t *p = buf; + uint32_t crc; + crc = ~0U; + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + return crc ^ ~0U; +} /* - * See `AFL_FRIDA_PERSISTENT_DEBUG`. + * Don't you hate those contrived examples which CRC their data. We can use + * FRIDA to patch this function out and always return success. Otherwise, we + * could change it to actually correct the checksum. */ -Afl.setPersistentDebug(); +int crc32_check (char * buf, int len) { + if (len < sizeof(uint32_t)) { return 0; } + uint32_t expected = *(uint32_t *)&buf[len - sizeof(uint32_t)]; + uint32_t calculated = crc32(buf, len - sizeof(uint32_t)); + return expected == calculated; +} /* - * See `AFL_FRIDA_DEBUG_MAPS`. + * So you've found a really boring bug in an earlier campaign which results in + * a NULL dereference or something like that. That bug can get in the way, + * causing the persistent loop to exit whenever it is triggered, and can also + * cloud your output unnecessarily. Again, we can use FRIDA to patch it out. */ -Afl.setDebugMaps(); +void some_boring_bug(char c) { + switch (c) { + case 'A'...'Z': + case 'a'...'z': + __builtin_trap(); + break; + } +} -/* - * 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. - */ -Afl.addIncludedRange(address, size); +void LLVMFuzzerTestOneInput(char *buf, int len) { + + if (!crc32_check(buf, len)) return; + + some_boring_bug(buf[0]); + + if (buf[0] == '0') { + printf("Looks like a zero to me!\n"); + } + else if (buf[0] == '1') { + printf("Pretty sure that is a one!\n"); + } + else if (buf[0] == '2') { + if (buf[1] == '3') { + if (buf[2] == '4') { + printf("Oh we, weren't expecting that!"); + __builtin_trap(); + } + } + } + else + printf("Neither one or zero? How quaint!\n"); -/* - * 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. - */ -Afl.addExcludedRange(address, size); +} -/* - * See `AFL_INST_LIBS`. - */ -Afl.setInstrumentLibraries(); +int main(int argc, char **argv) { -/* - * See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as - * an argument. - */ -Afl.setInstrumentDebugFile(file); + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; -/* - * See `AFL_FRIDA_INST_NO_PREFETCH`. - */ -Afl.setPrefetchDisable(); + if (argc != 2) { return 1; } -/* - * See `AFL_FRIDA_INST_NO_OPTIMIZE` - */ -Afl.setInstrumentNoOptimize(); + printf("Running: %s\n", argv[1]); -/* - * See `AFL_FRIDA_INST_TRACE`. - */ -Afl.setInstrumentEnableTracing(); + fd = open(argv[1], O_RDONLY); + if (fd < 0) { return 1; } -/* - * See `AFL_FRIDA_INST_TRACE_UNIQUE`. - */ -Afl.setInstrumentTracingUnique() + len = lseek(fd, 0, SEEK_END); + if (len < 0) { return 1; } -/* - * See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as - * an argument. - */ -Afl.setStdOut(file); + if (lseek(fd, 0, SEEK_SET) != 0) { return 1; } -/* - * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as - * an argument. - */ -Afl.setStdErr(file); + buf = malloc(len); + if (buf == NULL) { return 1; } -/* - * See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as - * an argument. - */ -Afl.setStatsFile(file); + n_read = read(fd, buf, len); + if (n_read != len) { return 1; } -/* - * See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an - * argument - */ -Afl.setStatsInterval(interval); + printf("Running: %s: (%zd bytes)\n", argv[1], n_read); + + LLVMFuzzerTestOneInput(buf, len); + printf("Done: %s: (%zd bytes)\n", argv[1], n_read); + + return 0; +} +``` + +There are a couple of obstacles with our target application. Unlike when fuzzing +source code, though, we can't simply edit it and recompile it. The following +script shows how we can use the normal functionality of FRIDA to modify any +troublesome behaviour. + +```js +Afl.print('******************'); +Afl.print('* AFL FRIDA MODE *'); +Afl.print('******************'); +Afl.print(''); + +const main = DebugSymbol.fromName('main').address; +Afl.print(`main: ${main}`); +Afl.setEntryPoint(main); +Afl.setPersistentAddress(main); +Afl.setPersistentCount(10000000); + +const crc32_check = DebugSymbol.fromName('crc32_check').address; +const crc32_replacement = new NativeCallback( + (buf, len) => { + Afl.print(`len: ${len}`); + if (len < 4) { + return 0; + } + + return 1; + }, + 'int', + ['pointer', 'int']); +Interceptor.replace(crc32_check, crc32_replacement); + +const some_boring_bug = DebugSymbol.fromName('some_boring_bug').address +const boring_replacement = new NativeCallback( + (c) => { }, + 'void', + ['char']); +Interceptor.replace(some_boring_bug, boring_replacement); + +Afl.done(); +Afl.print("done"); +``` + +# Advanced Patching +Consider the following code fragment... +```c +extern void some_boring_bug2(char c); + +__asm__ ( + ".text \n" + "some_boring_bug2: \n" + ".global some_boring_bug2 \n" + ".type some_boring_bug2, @function \n" + "mov %edi, %eax \n" + "cmp $0xb4, %al \n" + "jne ok \n" + "ud2 \n" + "ok: \n" + "ret \n"); + +void LLVMFuzzerTestOneInput(char *buf, int len) { + + ... + + some_boring_bug2(buf[0]); + + ... + +} +``` + +Rather than using FRIDAs `Interceptor.replace` or `Interceptor.attach` APIs, it +is possible to apply much more fine grained modification to the target +application by means of using the Stalker APIs. + +The following code locates the function of interest and patches out the UD2 +instruction signifying a crash. + +```js +/* Modify the instructions */ +const some_boring_bug2 = DebugSymbol.fromName('some_boring_bug2').address +const pid = Memory.alloc(4); +pid.writeInt(Process.id); + +const cm = new CModule(` + #include + #include + + typedef int pid_t; + + #define STDERR_FILENO 2 + #define BORING2_LEN 10 + + extern int dprintf(int fd, const char *format, ...); + extern void some_boring_bug2(char c); + extern pid_t getpid(void); + extern pid_t pid; + + gboolean js_stalker_callback(const cs_insn *insn, gboolean begin, + gboolean excluded, GumStalkerOutput *output) + { + pid_t my_pid = getpid(); + GumX86Writer *cw = output->writer.x86; + + if (GUM_ADDRESS(insn->address) < GUM_ADDRESS(some_boring_bug2)) { + + return TRUE; + + } + + if (GUM_ADDRESS(insn->address) >= + GUM_ADDRESS(some_boring_bug2) + BORING2_LEN) { + + return TRUE; + + } + + if (my_pid == pid) { + + if (begin) { + + dprintf(STDERR_FILENO, "\n> 0x%016lX: %s %s\n", insn->address, + insn->mnemonic, insn->op_str); + + } else { + + dprintf(STDERR_FILENO, " 0x%016lX: %s %s\n", insn->address, + insn->mnemonic, insn->op_str); + + } + + } + + if (insn->id == X86_INS_UD2) { + + gum_x86_writer_put_nop(cw); + return FALSE; + + } else { + + return TRUE; + + } + } + `, + { + dprintf: Module.getExportByName(null, 'dprintf'), + getpid: Module.getExportByName(null, 'getpid'), + some_boring_bug2: some_boring_bug2, + pid: pid + }); +Afl.setStalkerCallback(cm.js_stalker_callback) +Afl.setStdErr("/tmp/stderr.txt"); +``` + +Note that you will more likely want to find the +patch address by using: + +```js +const module = Process.getModuleByName('target.exe'); +/* Hardcoded offset within the target image */ +const address = module.base.add(0xdeadface); +``` +OR +``` +const address = DebugSymbol.fromName("my_function").address.add(0xdeadface); +``` +OR +``` +const address = Module.getExportByName(null, "my_function").add(0xdeadface); +``` + +The function `js_stalker_callback` should return `TRUE` if the original +instruction should be emitted in the instrumented code, or `FALSE` otherwise. +In the example above, we can see it is replaced with a `NOP`. + +Lastly, note that the same callback will be called when compiling instrumented +code both in the child of the forkserver (as it is executed) and also in the +parent of the forserver (when prefetching is enabled) so that it can be +inherited by the next forked child. It is **VERY** important that the same +instructions be generated in both the parent and the child, or if prefetching is +disabled that the same instructions are generated every time the block is +compiled. Failure to do so will likely lead to bugs which are incredibly +difficult to diagnose. The code above only prints the instructions when running +in the parent process (the one provided by `Process.id` when the JS script is +executed). + +# API +```js +class Afl { + + /** + * Field containing the `Module` object for `afl-frida-trace.so` (the FRIDA mode + * implementation). + */ + public static module: Module = Process.getModuleByName("afl-frida-trace.so"); + + /** + * 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. + */ + public static addExcludedRange(addressess: NativePointer, size: number): void { + 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. + */ + public static addIncludedRange(addressess: NativePointer, size: number): void { + 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. + */ + public static done(): void { + 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. + */ + public static error(msg: string): void { + 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. + */ + public static getAflFuzzLen(): NativePointer { + + 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. + */ + public static getAflFuzzPtr(): NativePointer { + + 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. + */ + public static print(msg: string): void { + 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`. + */ + public static setDebugMaps(): void { + 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. + */ + public static setEntryPoint(address: NativePointer): void { + Afl.jsApiSetEntryPoint(address); + } + + /** + * Function used to enable in-memory test cases for fuzzing. + */ + public static setInMemoryFuzzing(): void { + Afl.jsApiAflSharedMemFuzzing.writeInt(1); + } + + /** + * See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as + * an argument. + */ + public static setInstrumentDebugFile(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentDebugFile(buf); + } + + /** + * See `AFL_FRIDA_INST_TRACE`. + */ + public static setInstrumentEnableTracing(): void { + Afl.jsApiSetInstrumentTrace(); + } + + /** + * See `AFL_INST_LIBS`. + */ + public static setInstrumentLibraries(): void { + Afl.jsApiSetInstrumentLibraries(); + } + + /** + * See `AFL_FRIDA_INST_NO_OPTIMIZE` + */ + public static setInstrumentNoOptimize(): void { + Afl.jsApiSetInstrumentNoOptimize(); + } + + /** + * See `AFL_FRIDA_INST_TRACE_UNIQUE`. + */ + public static setInstrumentTracingUnique(): void { + Afl.jsApiSetInstrumentTraceUnique(); + } + + /** + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a + * `NativePointer` should be provided as it's argument. + */ + public static setPersistentAddress(address: NativePointer): void { + Afl.jsApiSetPersistentAddress(address); + } + + /** + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a + * `number` should be provided as it's argument. + */ + public static setPersistentCount(count: number): void { + Afl.jsApiSetPersistentCount(count); + } + + /** + * See `AFL_FRIDA_PERSISTENT_DEBUG`. + */ + public static setPersistentDebug(): void { + Afl.jsApiSetPersistentDebug(); + } + + /** + * See `AFL_FRIDA_PERSISTENT_ADDR`. This function takes a NativePointer as an + * argument. See above for examples of use. + */ + public static setPersistentHook(address: NativePointer): void { + Afl.jsApiSetPersistentHook(address); + } + + /** + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a + * `NativePointer` should be provided as it's argument. + */ + public static setPersistentReturn(address: NativePointer): void { + Afl.jsApiSetPersistentReturn(address); + } + + /** + * See `AFL_FRIDA_INST_NO_PREFETCH`. + */ + public static setPrefetchDisable(): void { + Afl.jsApiSetPrefetchDisable(); + } + + /* + * Set a function to be called for each instruction which is instrumented + * by AFL FRIDA mode. + */ + public static setStalkerCallback(callback: NativePointer): void { + Afl.jsApiSetStalkerCallback(callback); + } + + /** + * See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as + * an argument. + */ + public static setStatsFile(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStatsFile(buf); + } + + /** + * See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an + * argument + */ + public static setStatsInterval(interval: number): void { + Afl.jsApiSetStatsInterval(interval); + } + + /** + * See `AFL_FRIDA_STATS_TRANSITIONS` + */ + public static setStatsTransitions(): void { + Afl.jsApiSetStatsTransitions(); + } + + /** + * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as + * an argument. + */ + public static setStdErr(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStdErr(buf); + } + + /** + * See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as + * an argument. + */ + public static setStdOut(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStdOut(buf); + } + +} -/* - * See `AFL_FRIDA_STATS_TRANSITIONS` - */ -Afl.setStatsTransitions() ``` diff --git a/frida_mode/hook/hook.c b/frida_mode/hook/hook.c new file mode 100644 index 00000000..7d08101f --- /dev/null +++ b/frida_mode/hook/hook.c @@ -0,0 +1,50 @@ +#include +#include + +#include "frida-gumjs.h" + +#if defined(__x86_64__) + +void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, + uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + +} + +#elif defined(__i386__) + +void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, + uint32_t input_buf_len) { + + void **esp = (void **)regs->esp; + void * arg1 = esp[0]; + void **arg2 = &esp[1]; + memcpy(arg1, input_buf, input_buf_len); + *arg2 = (void *)input_buf_len; + +} + +#elif defined(__aarch64__) + +void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, + uint32_t input_buf_len) { + + memcpy((void *)regs->x[0], input_buf, input_buf_len); + regs->x[1] = input_buf_len; + +} + +#else + #pragma error "Unsupported architecture" +#endif + +int afl_persistent_hook_init(void) { + + // 1 for shared memory input (faster), 0 for normal input (you have to use + // read(), input_buf will be NULL) + return 1; + +} + diff --git a/frida_mode/include/js.h b/frida_mode/include/js.h index 77237d55..a5ecb712 100644 --- a/frida_mode/include/js.h +++ b/frida_mode/include/js.h @@ -3,10 +3,15 @@ #include "frida-gumjs.h" +typedef gboolean (*js_api_stalker_callback_t)(const cs_insn *insn, + gboolean begin, gboolean excluded, + GumStalkerOutput *output); + extern unsigned char api_js[]; extern unsigned int api_js_len; -extern gboolean js_done; +extern gboolean js_done; +extern js_api_stalker_callback_t js_user_callback; /* Frida Mode */ @@ -14,5 +19,8 @@ void js_config(void); void js_start(void); +gboolean js_stalker_callback(const cs_insn *insn, gboolean begin, + gboolean excluded, GumStalkerOutput *output); + #endif diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c index 186d5098..e95b923b 100644 --- a/frida_mode/src/entry.c +++ b/frida_mode/src/entry.c @@ -13,6 +13,7 @@ guint64 entry_point = 0; static void entry_launch(void) { + OKF("Entry point reached"); __afl_manual_init(); /* Child here */ diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index d6ae505d..2a217d96 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -11,6 +11,7 @@ #include "entry.h" #include "frida_cmplog.h" #include "instrument.h" +#include "js.h" #include "persistent.h" #include "prefetch.h" #include "ranges.h" @@ -165,8 +166,6 @@ static void instrument_basic_block(GumStalkerIterator *iterator, } - begin = FALSE; - } instrument_debug_instruction(instr->address, instr->size); @@ -178,7 +177,13 @@ static void instrument_basic_block(GumStalkerIterator *iterator, } - gum_stalker_iterator_keep(iterator); + if (js_stalker_callback(instr, begin, excluded, output)) { + + gum_stalker_iterator_keep(iterator); + + } + + begin = FALSE; } diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index 983f1efa..4cb04704 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -1,201 +1,243 @@ -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) { +"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); - 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) { + 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); - 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) { + 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); - js_api_set_stdout(buf) - }, - setStdErr: function(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); - js_api_set_stderr(buf) - }, - setStatsFile: function(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); - 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 // -//////////////////////////////////////////////////////////////////////////////// + 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 index 79e716ad..ed378d2c 100644 --- a/frida_mode/src/js/js.c +++ b/frida_mode/src/js/js.c @@ -5,8 +5,9 @@ #include "js.h" #include "util.h" -static char *js_script = NULL; -gboolean js_done = FALSE; +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; @@ -111,3 +112,11 @@ void js_start(void) { } +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 index 018c0b9a..91dccab2 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -138,5 +138,15 @@ void js_api_set_stats_transitions() { } -// "AFL_FRIDA_PERSISTENT_HOOK", +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; + +} diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c index e3e0b0ca..bcc59ea7 100644 --- a/frida_mode/src/persistent/persistent.c +++ b/frida_mode/src/persistent/persistent.c @@ -47,19 +47,6 @@ void persistent_config(void) { } -} - -void persistent_init(void) { - - OKF("Instrumentation - persistent mode [%c] (0x%016" G_GINT64_MODIFIER "X)", - persistent_start == 0 ? ' ' : 'X', persistent_start); - OKF("Instrumentation - persistent count [%c] (%" G_GINT64_MODIFIER "d)", - persistent_start == 0 ? ' ' : 'X', persistent_count); - OKF("Instrumentation - hook [%s]", hook_name); - - OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)", - persistent_ret == 0 ? ' ' : 'X', persistent_ret); - if (hook_name == NULL) { return; } void *hook_obj = dlopen(hook_name, RTLD_NOW); @@ -79,7 +66,20 @@ void persistent_init(void) { if (persistent_hook == NULL) FATAL("Failed to find afl_persistent_hook in %s", hook_name); - __afl_sharedmem_fuzzing = 1; +} + +void persistent_init(void) { + + OKF("Instrumentation - persistent mode [%c] (0x%016" G_GINT64_MODIFIER "X)", + persistent_start == 0 ? ' ' : 'X', persistent_start); + OKF("Instrumentation - persistent count [%c] (%" G_GINT64_MODIFIER "d)", + persistent_start == 0 ? ' ' : 'X', persistent_count); + OKF("Instrumentation - hook [%s]", hook_name); + + OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)", + persistent_ret == 0 ? ' ' : 'X', persistent_ret); + + if (persistent_hook != NULL) { __afl_sharedmem_fuzzing = 1; } } diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c index e618fbac..003f058a 100644 --- a/frida_mode/src/persistent/persistent_arm64.c +++ b/frida_mode/src/persistent/persistent_arm64.c @@ -9,99 +9,15 @@ #include "util.h" #if defined(__aarch64__) +typedef struct { -struct arm64_regs { + GumCpuContext ctx; + uint64_t rflags; - uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10; +} persistent_ctx_t; - union { - - uint64_t x11; - uint32_t fp_32; - - }; - - union { - - uint64_t x12; - uint32_t ip_32; - - }; - - union { - - uint64_t x13; - uint32_t sp_32; - - }; - - union { - - uint64_t x14; - uint32_t lr_32; - - }; - - union { - - uint64_t x15; - uint32_t pc_32; - - }; - - union { - - uint64_t x16; - uint64_t ip0; - - }; - - union { - - uint64_t x17; - uint64_t ip1; - - }; - - uint64_t x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28; - - union { - - uint64_t x29; - uint64_t fp; - - }; - - union { - - uint64_t x30; - uint64_t lr; - - }; - - union { - - uint64_t x31; - uint64_t sp; - - }; - - // the zero register is not saved here ofc - - uint64_t pc; - - uint32_t cpsr; - - uint8_t vfp_zregs[32][16 * 16]; - uint8_t vfp_pregs[17][32]; - uint32_t vfp_xregs[16]; - -}; - -typedef struct arm64_regs arch_api_regs; - -static arch_api_regs saved_regs = {0}; -static gpointer saved_lr = NULL; +static persistent_ctx_t saved_regs = {0}; +static gpointer saved_lr = NULL; gboolean persistent_is_supported(void) { @@ -109,8 +25,8 @@ gboolean persistent_is_supported(void) { } -static void instrument_persitent_save_regs(GumArm64Writer * cw, - struct arm64_regs *regs) { +static void instrument_persitent_save_regs(GumArm64Writer * cw, + persistent_ctx_t *regs) { GumAddress regs_address = GUM_ADDRESS(regs); const guint32 mrs_x1_nzcv = 0xd53b4201; @@ -129,83 +45,87 @@ static void instrument_persitent_save_regs(GumArm64Writer * cw, /* Skip x0 & x1 we'll do that later */ - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3, - ARM64_REG_X0, (16 * 1), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X4, ARM64_REG_X5, - ARM64_REG_X0, (16 * 2), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X6, ARM64_REG_X7, - ARM64_REG_X0, (16 * 3), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X8, ARM64_REG_X9, - ARM64_REG_X0, (16 * 4), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X10, ARM64_REG_X11, - ARM64_REG_X0, (16 * 5), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X12, ARM64_REG_X13, - ARM64_REG_X0, (16 * 6), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X14, ARM64_REG_X15, - ARM64_REG_X0, (16 * 7), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X16, ARM64_REG_X17, - ARM64_REG_X0, (16 * 8), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X18, ARM64_REG_X19, - ARM64_REG_X0, (16 * 9), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X20, ARM64_REG_X21, - ARM64_REG_X0, (16 * 10), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X22, ARM64_REG_X23, - ARM64_REG_X0, (16 * 11), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X24, ARM64_REG_X25, - ARM64_REG_X0, (16 * 12), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X26, ARM64_REG_X27, - ARM64_REG_X0, (16 * 13), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X28, ARM64_REG_X29, - ARM64_REG_X0, (16 * 14), - GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X0, + offsetof(GumCpuContext, x[2]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X4, ARM64_REG_X5, ARM64_REG_X0, + offsetof(GumCpuContext, x[4]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X6, ARM64_REG_X7, ARM64_REG_X0, + offsetof(GumCpuContext, x[6]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X8, ARM64_REG_X9, ARM64_REG_X0, + offsetof(GumCpuContext, x[8]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X10, ARM64_REG_X11, ARM64_REG_X0, + offsetof(GumCpuContext, x[10]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X12, ARM64_REG_X13, ARM64_REG_X0, + offsetof(GumCpuContext, x[12]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X14, ARM64_REG_X15, ARM64_REG_X0, + offsetof(GumCpuContext, x[14]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X16, ARM64_REG_X17, ARM64_REG_X0, + offsetof(GumCpuContext, x[16]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X18, ARM64_REG_X19, ARM64_REG_X0, + offsetof(GumCpuContext, x[18]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X20, ARM64_REG_X21, ARM64_REG_X0, + offsetof(GumCpuContext, x[20]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X22, ARM64_REG_X23, ARM64_REG_X0, + offsetof(GumCpuContext, x[22]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X24, ARM64_REG_X25, ARM64_REG_X0, + offsetof(GumCpuContext, x[24]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X26, ARM64_REG_X27, ARM64_REG_X0, + offsetof(GumCpuContext, x[26]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X28, ARM64_REG_X29, ARM64_REG_X0, + offsetof(GumCpuContext, x[28]), GUM_INDEX_SIGNED_OFFSET); - /* LR & Adjusted SP */ - gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_X2, ARM64_REG_SP, - (GUM_RED_ZONE_SIZE + 32)); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X2, - ARM64_REG_X0, (16 * 15), - GUM_INDEX_SIGNED_OFFSET); + /* LR (x30) */ + gum_arm64_writer_put_str_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X0, + offsetof(GumCpuContext, x[30])); - /* PC & CPSR */ + /* PC & Adjusted SP (31) */ gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X2, GUM_ADDRESS(persistent_start)); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X1, - ARM64_REG_X0, (16 * 16), - GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_X3, ARM64_REG_SP, + (GUM_RED_ZONE_SIZE + 32)); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X0, offsetof(GumCpuContext, pc), + GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q0, ARM64_REG_Q1, - ARM64_REG_X0, (16 * 17), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q2, ARM64_REG_Q3, - ARM64_REG_X0, (16 * 18), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q4, ARM64_REG_Q5, - ARM64_REG_X0, (16 * 19), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_Q6, ARM64_REG_Q7, - ARM64_REG_X0, (16 * 20), - GUM_INDEX_SIGNED_OFFSET); + /* CPSR */ + gum_arm64_writer_put_str_reg_reg_offset(cw, ARM64_REG_X1, ARM64_REG_X0, + offsetof(persistent_ctx_t, rflags)); + + /* Q */ + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_Q0, ARM64_REG_Q1, ARM64_REG_X0, + offsetof(GumCpuContext, q[0]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_Q2, ARM64_REG_Q3, ARM64_REG_X0, + offsetof(GumCpuContext, q[16]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_Q4, ARM64_REG_Q5, ARM64_REG_X0, + offsetof(GumCpuContext, q[32]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_Q6, ARM64_REG_Q7, ARM64_REG_X0, + offsetof(GumCpuContext, q[48]), GUM_INDEX_SIGNED_OFFSET); /* x0 & x1 */ gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_SP, 16, GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_stp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3, - ARM64_REG_X0, (16 * 0), - GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_stp_reg_reg_reg_offset( + cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X0, + offsetof(GumCpuContext, x[0]), GUM_INDEX_SIGNED_OFFSET); /* Pop the saved values */ gum_arm64_writer_put_ldp_reg_reg_reg_offset( @@ -217,8 +137,8 @@ static void instrument_persitent_save_regs(GumArm64Writer * cw, } -static void instrument_persitent_restore_regs(GumArm64Writer * cw, - struct arm64_regs *regs) { +static void instrument_persitent_restore_regs(GumArm64Writer * cw, + persistent_ctx_t *regs) { GumAddress regs_address = GUM_ADDRESS(regs); const guint32 msr_nzcv_x1 = 0xd51b4201; @@ -228,82 +148,81 @@ static void instrument_persitent_restore_regs(GumArm64Writer * cw, /* Skip x0 - x3 we'll do that last */ - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X4, ARM64_REG_X5, - ARM64_REG_X0, (16 * 2), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X6, ARM64_REG_X7, - ARM64_REG_X0, (16 * 3), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X8, ARM64_REG_X9, - ARM64_REG_X0, (16 * 4), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X10, ARM64_REG_X11, - ARM64_REG_X0, (16 * 5), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X12, ARM64_REG_X13, - ARM64_REG_X0, (16 * 6), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X14, ARM64_REG_X15, - ARM64_REG_X0, (16 * 7), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X16, ARM64_REG_X17, - ARM64_REG_X0, (16 * 8), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X18, ARM64_REG_X19, - ARM64_REG_X0, (16 * 9), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X20, ARM64_REG_X21, - ARM64_REG_X0, (16 * 10), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X22, ARM64_REG_X23, - ARM64_REG_X0, (16 * 11), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X24, ARM64_REG_X25, - ARM64_REG_X0, (16 * 12), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X26, ARM64_REG_X27, - ARM64_REG_X0, (16 * 13), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X28, ARM64_REG_X29, - ARM64_REG_X0, (16 * 14), - GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X4, ARM64_REG_X5, ARM64_REG_X0, + offsetof(GumCpuContext, x[4]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X6, ARM64_REG_X7, ARM64_REG_X0, + offsetof(GumCpuContext, x[6]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X8, ARM64_REG_X9, ARM64_REG_X0, + offsetof(GumCpuContext, x[8]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X10, ARM64_REG_X11, ARM64_REG_X0, + offsetof(GumCpuContext, x[10]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X12, ARM64_REG_X13, ARM64_REG_X0, + offsetof(GumCpuContext, x[12]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X14, ARM64_REG_X15, ARM64_REG_X0, + offsetof(GumCpuContext, x[14]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X16, ARM64_REG_X17, ARM64_REG_X0, + offsetof(GumCpuContext, x[16]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X18, ARM64_REG_X19, ARM64_REG_X0, + offsetof(GumCpuContext, x[18]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X20, ARM64_REG_X21, ARM64_REG_X0, + offsetof(GumCpuContext, x[20]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X22, ARM64_REG_X23, ARM64_REG_X0, + offsetof(GumCpuContext, x[22]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X24, ARM64_REG_X25, ARM64_REG_X0, + offsetof(GumCpuContext, x[24]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X26, ARM64_REG_X27, ARM64_REG_X0, + offsetof(GumCpuContext, x[26]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X28, ARM64_REG_X29, ARM64_REG_X0, + offsetof(GumCpuContext, x[28]), GUM_INDEX_SIGNED_OFFSET); - /* LR & Adjusted SP (use x1 as clobber) */ - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X1, - ARM64_REG_X0, (16 * 15), - GUM_INDEX_SIGNED_OFFSET); + /* LR (x30) */ + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X0, + offsetof(GumCpuContext, x[30])); + /* Adjusted SP (31) (use x1 as clobber)*/ + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X1, ARM64_REG_X0, + offsetof(GumCpuContext, sp)); gum_arm64_writer_put_mov_reg_reg(cw, ARM64_REG_SP, ARM64_REG_X1); - /* Don't restore RIP use x1-x3 as clobber */ - - /* PC (x2) & CPSR (x1) */ - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X1, - ARM64_REG_X0, (16 * 16), - GUM_INDEX_SIGNED_OFFSET); + /* CPSR */ + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X1, ARM64_REG_X0, + offsetof(persistent_ctx_t, rflags)); gum_arm64_writer_put_instruction(cw, msr_nzcv_x1); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q0, ARM64_REG_Q1, - ARM64_REG_X0, (16 * 17), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q2, ARM64_REG_Q3, - ARM64_REG_X0, (16 * 18), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q4, ARM64_REG_Q5, - ARM64_REG_X0, (16 * 19), - GUM_INDEX_SIGNED_OFFSET); - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_Q6, ARM64_REG_Q7, - ARM64_REG_X0, (16 * 20), - GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_Q0, ARM64_REG_Q1, ARM64_REG_X0, + offsetof(GumCpuContext, q[0]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_Q2, ARM64_REG_Q3, ARM64_REG_X0, + offsetof(GumCpuContext, q[16]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_Q4, ARM64_REG_Q5, ARM64_REG_X0, + offsetof(GumCpuContext, q[32]), GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_Q6, ARM64_REG_Q7, ARM64_REG_X0, + offsetof(GumCpuContext, q[48]), GUM_INDEX_SIGNED_OFFSET); /* x2 & x3 */ - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X3, - ARM64_REG_X0, (16 * 1), - GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X0, + offsetof(GumCpuContext, x[2]), GUM_INDEX_SIGNED_OFFSET); /* x0 & x1 */ - gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X0, ARM64_REG_X1, - ARM64_REG_X0, (16 * 0), - GUM_INDEX_SIGNED_OFFSET); + gum_arm64_writer_put_ldp_reg_reg_reg_offset( + cw, ARM64_REG_X0, ARM64_REG_X1, ARM64_REG_X0, + offsetof(GumCpuContext, x[0]), GUM_INDEX_SIGNED_OFFSET); } @@ -334,29 +253,29 @@ static void instrument_afl_persistent_loop(GumArm64Writer *cw) { } -static void persistent_prologue_hook(GumArm64Writer * cw, - struct arm64_regs *regs) { +static void persistent_prologue_hook(GumArm64Writer * cw, + persistent_ctx_t *regs) { if (persistent_hook == NULL) return; gum_arm64_writer_put_sub_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP, GUM_RED_ZONE_SIZE); - gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X3, + gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X2, GUM_ADDRESS(&__afl_fuzz_len)); - gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X3, ARM64_REG_X3, 0); - gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X3, ARM64_REG_X3, 0); + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X2, 0); + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X2, 0); - gum_arm64_writer_put_and_reg_reg_imm(cw, ARM64_REG_X3, ARM64_REG_X3, + gum_arm64_writer_put_and_reg_reg_imm(cw, ARM64_REG_X2, ARM64_REG_X2, G_MAXULONG); - gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X2, + gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X1, GUM_ADDRESS(&__afl_fuzz_ptr)); - gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X2, 0); + gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X1, ARM64_REG_X1, 0); gum_arm64_writer_put_call_address_with_arguments( - cw, GUM_ADDRESS(persistent_hook), 4, GUM_ARG_ADDRESS, GUM_ADDRESS(regs), - GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_REGISTER, ARM64_REG_X2, - GUM_ARG_REGISTER, ARM64_REG_X3); + cw, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS, + GUM_ADDRESS(®s->ctx), GUM_ARG_REGISTER, ARM64_REG_X1, GUM_ARG_REGISTER, + ARM64_REG_X2); gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP, GUM_RED_ZONE_SIZE); @@ -406,6 +325,8 @@ void persistent_prologue(GumStalkerOutput *output) { gconstpointer loop = cw->code + 1; + OKF("Persistent loop reached"); + instrument_persitent_save_regs(cw, &saved_regs); /* loop: */ diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c index a91abc1c..b2186db1 100644 --- a/frida_mode/src/persistent/persistent_x64.c +++ b/frida_mode/src/persistent/persistent_x64.c @@ -10,40 +10,15 @@ #if defined(__x86_64__) -struct x86_64_regs { +typedef struct { - uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, - r15; + GumCpuContext ctx; + uint64_t rflags; - union { +} persistent_ctx_t; - uint64_t rip; - uint64_t pc; - - }; - - union { - - uint64_t rsp; - uint64_t sp; - - }; - - union { - - uint64_t rflags; - uint64_t flags; - - }; - - uint8_t zmm_regs[32][64]; - -}; - -typedef struct x86_64_regs arch_api_regs; - -static arch_api_regs saved_regs = {0}; -static gpointer saved_ret = NULL; +static persistent_ctx_t saved_regs = {0}; +static gpointer saved_ret = NULL; gboolean persistent_is_supported(void) { @@ -51,8 +26,8 @@ gboolean persistent_is_supported(void) { } -static void instrument_persitent_save_regs(GumX86Writer * cw, - struct x86_64_regs *regs) { +static void instrument_persitent_save_regs(GumX86Writer * cw, + persistent_ctx_t *regs) { GumAddress regs_address = GUM_ADDRESS(regs); gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, @@ -64,41 +39,41 @@ static void instrument_persitent_save_regs(GumX86Writer * cw, gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 1), - GUM_REG_RBX); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 2), - GUM_REG_RCX); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 3), - GUM_REG_RDX); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 4), - GUM_REG_RDI); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 5), - GUM_REG_RSI); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 6), - GUM_REG_RBP); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 7), - GUM_REG_R8); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 8), - GUM_REG_R9); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 9), - GUM_REG_R10); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 10), - GUM_REG_R11); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 11), - GUM_REG_R12); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 12), - GUM_REG_R13); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 13), - GUM_REG_R14); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 14), - GUM_REG_R15); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, rbx), GUM_REG_RBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, rcx), GUM_REG_RCX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, rdx), GUM_REG_RDX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, rdi), GUM_REG_RDI); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, rsi), GUM_REG_RSI); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, rbp), GUM_REG_RBP); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, r8), GUM_REG_R8); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, r9), GUM_REG_R9); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, r10), GUM_REG_R10); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, r11), GUM_REG_R11); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, r12), GUM_REG_R12); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, r13), GUM_REG_R13); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, r14), GUM_REG_R14); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, r15), GUM_REG_R15); /* Store RIP */ gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RBX, GUM_ADDRESS(persistent_start)); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 15), - GUM_REG_RBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, rip), GUM_REG_RBX); /* Store adjusted RSP */ gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_RBX, GUM_REG_RSP); @@ -106,18 +81,18 @@ static void instrument_persitent_save_regs(GumX86Writer * cw, /* RED_ZONE + Saved flags, RAX, alignment */ gum_x86_writer_put_add_reg_imm(cw, GUM_REG_RBX, GUM_RED_ZONE_SIZE + (0x8 * 2)); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 16), - GUM_REG_RBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, rsp), GUM_REG_RBX); /* Save the flags */ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x8); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 17), - GUM_REG_RBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(persistent_ctx_t, rflags), GUM_REG_RBX); /* Save the RAX */ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP, 0x0); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 0), - GUM_REG_RBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_RAX, offsetof(GumCpuContext, rax), GUM_REG_RBX); /* Pop the saved values */ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 0x10); @@ -127,56 +102,56 @@ static void instrument_persitent_save_regs(GumX86Writer * cw, } -static void instrument_persitent_restore_regs(GumX86Writer * cw, - struct x86_64_regs *regs) { +static void instrument_persitent_restore_regs(GumX86Writer * cw, + persistent_ctx_t *regs) { GumAddress regs_address = GUM_ADDRESS(regs); gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, regs_address); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RAX, - (0x8 * 2)); + offsetof(GumCpuContext, rcx)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RAX, - (0x8 * 3)); + offsetof(GumCpuContext, rdx)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDI, GUM_REG_RAX, - (0x8 * 4)); + offsetof(GumCpuContext, rdi)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RAX, - (0x8 * 5)); + offsetof(GumCpuContext, rsi)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBP, GUM_REG_RAX, - (0x8 * 6)); + offsetof(GumCpuContext, rbp)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R8, GUM_REG_RAX, - (0x8 * 7)); + offsetof(GumCpuContext, r8)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R9, GUM_REG_RAX, - (0x8 * 8)); + offsetof(GumCpuContext, r9)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R10, GUM_REG_RAX, - (0x8 * 9)); + offsetof(GumCpuContext, r10)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R11, GUM_REG_RAX, - (0x8 * 10)); + offsetof(GumCpuContext, r11)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R12, GUM_REG_RAX, - (0x8 * 11)); + offsetof(GumCpuContext, r12)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R13, GUM_REG_RAX, - (0x8 * 12)); + offsetof(GumCpuContext, r13)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R14, GUM_REG_RAX, - (0x8 * 13)); + offsetof(GumCpuContext, r14)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R15, GUM_REG_RAX, - (0x8 * 14)); + offsetof(GumCpuContext, r15)); /* Don't restore RIP */ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSP, GUM_REG_RAX, - (0x8 * 16)); + offsetof(GumCpuContext, rsp)); /* Restore RBX, RAX & Flags */ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, -(GUM_RED_ZONE_SIZE)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, - (0x8 * 1)); + offsetof(GumCpuContext, rbx)); gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, - (0x8 * 0)); + offsetof(GumCpuContext, rax)); gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RAX, - (0x8 * 17)); + offsetof(persistent_ctx_t, rflags)); gum_x86_writer_put_push_reg(cw, GUM_REG_RBX); gum_x86_writer_put_popfx(cw); @@ -217,28 +192,27 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) { } -static void persistent_prologue_hook(GumX86Writer * cw, - struct x86_64_regs *regs) { +static void persistent_prologue_hook(GumX86Writer *cw, persistent_ctx_t *regs) { if (persistent_hook == NULL) return; gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, -(GUM_RED_ZONE_SIZE)); - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RCX, + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDX, GUM_ADDRESS(&__afl_fuzz_len)); - gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0); - gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RCX, GUM_REG_RCX, 0); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0); gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_RDI, 0xffffffff); - gum_x86_writer_put_and_reg_reg(cw, GUM_REG_RCX, GUM_REG_RDI); + gum_x86_writer_put_and_reg_reg(cw, GUM_REG_RDX, GUM_REG_RDI); - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDX, + gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RSI, GUM_ADDRESS(&__afl_fuzz_ptr)); - gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0); + gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSI, GUM_REG_RSI, 0); gum_x86_writer_put_call_address_with_arguments( - cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 4, GUM_ARG_ADDRESS, - GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_REGISTER, - GUM_REG_RDX, GUM_ARG_REGISTER, GUM_REG_RCX); + cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS, + GUM_ADDRESS(®s->ctx), GUM_ARG_REGISTER, GUM_REG_RSI, GUM_ARG_REGISTER, + GUM_REG_RDX); gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, (GUM_RED_ZONE_SIZE)); @@ -296,6 +270,8 @@ void persistent_prologue(GumStalkerOutput *output) { gconstpointer loop = cw->code + 1; + OKF("Persistent loop reached"); + /* Pop the return value */ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 8); diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c index 1d01d8e4..f50bccb0 100644 --- a/frida_mode/src/persistent/persistent_x86.c +++ b/frida_mode/src/persistent/persistent_x86.c @@ -1,45 +1,23 @@ #include "frida-gumjs.h" #include "config.h" +#include "debug.h" #include "instrument.h" #include "persistent.h" #if defined(__i386__) -struct x86_regs { +typedef struct { - uint32_t eax, ebx, ecx, edx, edi, esi, ebp; + GumCpuContext ctx; + uint32_t eflags; - union { +} persistent_ctx_t; - uint32_t eip; - uint32_t pc; +static persistent_ctx_t saved_regs = {0}; - }; - - union { - - uint32_t esp; - uint32_t sp; - - }; - - union { - - uint32_t eflags; - uint32_t flags; - - }; - - uint8_t xmm_regs[8][16]; - -}; - -typedef struct x86_regs arch_api_regs; - -static arch_api_regs saved_regs = {0}; -static gpointer saved_ret = NULL; +static gpointer saved_ret = NULL; gboolean persistent_is_supported(void) { @@ -47,8 +25,8 @@ gboolean persistent_is_supported(void) { } -static void instrument_persitent_save_regs(GumX86Writer * cw, - struct x86_regs *regs) { +static void instrument_persitent_save_regs(GumX86Writer * cw, + persistent_ctx_t *regs) { GumAddress regs_address = GUM_ADDRESS(regs); @@ -58,80 +36,80 @@ static void instrument_persitent_save_regs(GumX86Writer * cw, gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 1), - GUM_REG_EBX); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 2), - GUM_REG_ECX); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 3), - GUM_REG_EDX); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 4), - GUM_REG_EDI); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 5), - GUM_REG_ESI); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 6), - GUM_REG_EBP); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(GumCpuContext, ebx), GUM_REG_EBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(GumCpuContext, ecx), GUM_REG_ECX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(GumCpuContext, edx), GUM_REG_EDX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(GumCpuContext, edi), GUM_REG_EDI); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(GumCpuContext, esi), GUM_REG_ESI); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(GumCpuContext, ebp), GUM_REG_EBP); /* Store RIP */ gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EBX, GUM_ADDRESS(persistent_start)); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 7), - GUM_REG_EBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(GumCpuContext, eip), GUM_REG_EBX); /* Store adjusted RSP */ gum_x86_writer_put_mov_reg_reg(cw, GUM_REG_EBX, GUM_REG_ESP); /* RED_ZONE + Saved flags, RAX */ gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EBX, (0x4 * 2)); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 8), - GUM_REG_EBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(GumCpuContext, esp), GUM_REG_EBX); /* Save the flags */ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x4); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 9), - GUM_REG_EBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(persistent_ctx_t, eflags), GUM_REG_EBX); /* Save the RAX */ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP, 0x0); - gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_EAX, (0x4 * 0), - GUM_REG_EBX); + gum_x86_writer_put_mov_reg_offset_ptr_reg( + cw, GUM_REG_EAX, offsetof(GumCpuContext, eax), GUM_REG_EBX); /* Pop the saved values */ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 0x8); } -static void instrument_persitent_restore_regs(GumX86Writer * cw, - struct x86_regs *regs) { +static void instrument_persitent_restore_regs(GumX86Writer * cw, + persistent_ctx_t *regs) { GumAddress regs_address = GUM_ADDRESS(regs); gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, regs_address); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ECX, GUM_REG_EAX, - (0x4 * 2)); + offsetof(GumCpuContext, ecx)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDX, GUM_REG_EAX, - (0x4 * 3)); + offsetof(GumCpuContext, edx)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EDI, GUM_REG_EAX, - (0x4 * 4)); + offsetof(GumCpuContext, edi)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESI, GUM_REG_EAX, - (0x4 * 5)); + offsetof(GumCpuContext, esi)); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX, - (0x4 * 6)); + offsetof(GumCpuContext, ebp)); /* Don't restore RIP */ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESP, GUM_REG_EAX, - (0x4 * 8)); + offsetof(GumCpuContext, esp)); /* Restore RBX, RAX & Flags */ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX, - (0x4 * 1)); + offsetof(GumCpuContext, ebx)); gum_x86_writer_put_push_reg(cw, GUM_REG_EBX); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX, - (0x4 * 0)); + offsetof(GumCpuContext, eax)); gum_x86_writer_put_push_reg(cw, GUM_REG_EBX); gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX, - (0x4 * 9)); + offsetof(persistent_ctx_t, eflags)); gum_x86_writer_put_push_reg(cw, GUM_REG_EBX); gum_x86_writer_put_popfx(cw); @@ -165,7 +143,7 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) { } -static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) { +static void persistent_prologue_hook(GumX86Writer *cw, persistent_ctx_t *regs) { if (persistent_hook == NULL) return; @@ -180,9 +158,8 @@ static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) { /* Base address is 64-bits (hence two zero arguments) */ gum_x86_writer_put_call_address_with_arguments( - cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 5, GUM_ARG_ADDRESS, - GUM_ADDRESS(regs), GUM_ARG_ADDRESS, GUM_ADDRESS(0), GUM_ARG_ADDRESS, - GUM_ADDRESS(0), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER, + cw, GUM_CALL_CAPI, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS, + GUM_ADDRESS(®s->ctx), GUM_ARG_REGISTER, GUM_REG_EDX, GUM_ARG_REGISTER, GUM_REG_ECX); } @@ -233,6 +210,8 @@ void persistent_prologue(GumStalkerOutput *output) { gconstpointer loop = cw->code + 1; + OKF("Persistent loop reached"); + /* Pop the return value */ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 4); diff --git a/frida_mode/test/jpeg/GNUmakefile b/frida_mode/test/jpeg/GNUmakefile index 689fce3d..e3a8f321 100644 --- a/frida_mode/test/jpeg/GNUmakefile +++ b/frida_mode/test/jpeg/GNUmakefile @@ -2,8 +2,7 @@ PWD:=$(shell pwd)/ ROOT:=$(shell realpath $(PWD)../../..)/ BUILD_DIR:=$(PWD)build/ -AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c -AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so +AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so LIBJPEG_BUILD_DIR:=$(BUILD_DIR)libjpeg/ HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ @@ -118,11 +117,6 @@ $(TEST_BIN): $(HARNESS_OBJ) $(JPEGTEST_OBJ) $(LIBJPEG_LIB) $(LDFLAGS) \ $(TEST_BIN_LDFLAGS) \ -########## HOOK ######## - -$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) - $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ - ########## DUMMY ####### $(TEST_DATA_DIR): | $(BUILD_DIR) @@ -133,8 +127,6 @@ $(TEST_DATA_FILE): | $(TEST_DATA_DIR) ###### TEST DATA ####### -hook: $(AFLPP_DRIVER_HOOK_OBJ) - clean: rm -rf $(BUILD_DIR) diff --git a/frida_mode/test/jpeg/Makefile b/frida_mode/test/jpeg/Makefile index 863438cf..7a237f99 100644 --- a/frida_mode/test/jpeg/Makefile +++ b/frida_mode/test/jpeg/Makefile @@ -14,6 +14,3 @@ frida: debug: @gmake debug - -hook: - @gmake hook diff --git a/frida_mode/test/jpeg/aflpp_qemu_driver_hook.c b/frida_mode/test/jpeg/aflpp_qemu_driver_hook.c deleted file mode 100644 index 059d438d..00000000 --- a/frida_mode/test/jpeg/aflpp_qemu_driver_hook.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include - -#if defined(__x86_64__) - -struct x86_64_regs { - - uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, - r15; - - union { - - uint64_t rip; - uint64_t pc; - - }; - - union { - - uint64_t rsp; - uint64_t sp; - - }; - - union { - - uint64_t rflags; - uint64_t flags; - - }; - - uint8_t zmm_regs[32][64]; - -}; - -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - memcpy((void *)regs->rdi, input_buf, input_buf_len); - regs->rsi = input_buf_len; - -} - -#elif defined(__i386__) - -struct x86_regs { - - uint32_t eax, ebx, ecx, edx, edi, esi, ebp; - - union { - - uint32_t eip; - uint32_t pc; - - }; - - union { - - uint32_t esp; - uint32_t sp; - - }; - - union { - - uint32_t eflags; - uint32_t flags; - - }; - - uint8_t xmm_regs[8][16]; - -}; - -void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - void **esp = (void **)regs->esp; - void * arg1 = esp[1]; - void **arg2 = &esp[2]; - memcpy(arg1, input_buf, input_buf_len); - *arg2 = (void *)input_buf_len; - -} - -#else - #pragma error "Unsupported architecture" -#endif - -int afl_persistent_hook_init(void) { - - // 1 for shared memory input (faster), 0 for normal input (you have to use - // read(), input_buf will be NULL) - return 1; - -} - diff --git a/frida_mode/test/js/GNUmakefile b/frida_mode/test/js/GNUmakefile index 8ea71656..af40c1c4 100644 --- a/frida_mode/test/js/GNUmakefile +++ b/frida_mode/test/js/GNUmakefile @@ -1,18 +1,21 @@ PWD:=$(shell pwd)/ ROOT:=$(shell realpath $(PWD)../../..)/ BUILD_DIR:=$(PWD)build/ -TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ -TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in +TEST_DATA_DIR:=$(BUILD_DIR)in/ +TEST_DATA_FILE:=$(TEST_DATA_DIR)in -TESTINSTBIN:=$(BUILD_DIR)testinstr -TESTINSTSRC:=$(PWD)testinstr.c +TESTINSTBIN:=$(BUILD_DIR)test +TESTINSTSRC:=$(PWD)test.c + +TESTINSTBIN2:=$(BUILD_DIR)test2 +TESTINSTSRC2:=$(PWD)test2.c QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out .PHONY: all 32 clean qemu frida -all: $(TESTINSTBIN) +all: $(TESTINSTBIN) $(TESTINSTBIN2) make -C $(ROOT)frida_mode/ 32: @@ -21,24 +24,57 @@ all: $(TESTINSTBIN) $(BUILD_DIR): mkdir -p $@ -$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) +$(TEST_DATA_DIR): | $(BUILD_DIR) mkdir -p $@ -$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) +$(TEST_DATA_FILE): | $(TEST_DATA_DIR) echo -n "000" > $@ $(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< +$(TESTINSTBIN2): $(TESTINSTSRC2) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + clean: rm -rf $(BUILD_DIR) -frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) - AFL_FRIDA_JS_SCRIPT=test.js \ +frida_js_entry: $(TESTINSTBIN) $(TEST_DATA_FILE) + AFL_FRIDA_JS_SCRIPT=entry.js \ $(ROOT)afl-fuzz \ -D \ -O \ - -i $(TESTINSTR_DATA_DIR) \ + -i $(TEST_DATA_DIR) \ -o $(FRIDA_OUT) \ -- \ $(TESTINSTBIN) @@ + +frida_js_replace: $(TESTINSTBIN) $(TEST_DATA_FILE) + AFL_FRIDA_JS_SCRIPT=replace.js \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + +frida_js_patch: $(TESTINSTBIN2) $(TEST_DATA_FILE) + AFL_FRIDA_JS_SCRIPT=patch.js \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN2) @@ + +frida_js_stalker: $(TESTINSTBIN2) $(TEST_DATA_FILE) + AFL_FRIDA_JS_SCRIPT=stalker.js \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN2) @@ diff --git a/frida_mode/test/js/Makefile b/frida_mode/test/js/Makefile index 7a237f99..8a2b6fb0 100644 --- a/frida_mode/test/js/Makefile +++ b/frida_mode/test/js/Makefile @@ -9,8 +9,17 @@ all: clean: @gmake clean -frida: - @gmake frida +frida_js_entry: + @gmake frida_js_entry + +frida_js_replace: + @gmake frida_js_replace + +frida_js_patch: + @gmake frida_js_patch + +frida_js_stalker: + @gmake frida_js_stalker debug: @gmake debug diff --git a/frida_mode/test/js/entry.js b/frida_mode/test/js/entry.js new file mode 100644 index 00000000..f10ef2d1 --- /dev/null +++ b/frida_mode/test/js/entry.js @@ -0,0 +1,20 @@ +Afl.print('******************'); +Afl.print('* AFL FRIDA MODE *'); +Afl.print('******************'); +Afl.print(''); + +Afl.print(`PID: ${Process.id}`); + +new ModuleMap().values().forEach(m => { + Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`); +}); + +const entry_point = DebugSymbol.fromName('run'); +Afl.print(`entry_point: ${entry_point.address}`); + +Afl.setEntryPoint(entry_point.address); + +// Afl.error('HARD NOPE'); + +Afl.done(); +Afl.print("done"); diff --git a/frida_mode/test/js/patch.js b/frida_mode/test/js/patch.js new file mode 100644 index 00000000..485a434f --- /dev/null +++ b/frida_mode/test/js/patch.js @@ -0,0 +1,34 @@ +Afl.print('******************'); +Afl.print('* AFL FRIDA MODE *'); +Afl.print('******************'); +Afl.print(''); + +const main = DebugSymbol.fromName('main').address; +Afl.print(`main: ${main}`); +Afl.setEntryPoint(main); +Afl.setPersistentAddress(main); +Afl.setPersistentCount(10000000); + +const crc32_check = DebugSymbol.fromName('crc32_check').address; +const crc32_replacement = new NativeCallback( + (buf, len) => { + Afl.print(`len: ${len}`); + if (len < 4) { + return 0; + } + + return 1; + }, + 'int', + ['pointer', 'int']); +Interceptor.replace(crc32_check, crc32_replacement); + +const some_boring_bug = DebugSymbol.fromName('some_boring_bug').address +const boring_replacement = new NativeCallback( + (c) => { }, + 'void', + ['char']); +Interceptor.replace(some_boring_bug, boring_replacement); + +Afl.done(); +Afl.print("done"); diff --git a/frida_mode/test/js/replace.js b/frida_mode/test/js/replace.js new file mode 100644 index 00000000..4e1e7eb7 --- /dev/null +++ b/frida_mode/test/js/replace.js @@ -0,0 +1,43 @@ +Afl.print('******************'); +Afl.print('* AFL FRIDA MODE *'); +Afl.print('******************'); +Afl.print(''); + +Afl.print(`PID: ${Process.id}`); + +const name = Process.enumerateModules()[0].name; +Afl.print(`Name: ${name}`); + +new ModuleMap().values().forEach(m => { + Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`); +}); + +const slow = DebugSymbol.fromName('slow').address; +Afl.print(`slow: ${slow}`); + +const LLVMFuzzerTestOneInput = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address; +Afl.print(`LLVMFuzzerTestOneInput: ${LLVMFuzzerTestOneInput}`); + +const cm = new CModule(` + + extern unsigned char * __afl_fuzz_ptr; + extern unsigned int * __afl_fuzz_len; + extern void LLVMFuzzerTestOneInput(char *buf, int len); + + void slow(void) { + + LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len); + } + `, + { + LLVMFuzzerTestOneInput: LLVMFuzzerTestOneInput, + __afl_fuzz_ptr: Afl.getAflFuzzPtr(), + __afl_fuzz_len: Afl.getAflFuzzLen() + }); + +Afl.setEntryPoint(cm.slow); +Afl.setPersistentAddress(cm.slow); +Afl.setInMemoryFuzzing(); +Interceptor.replace(slow, cm.slow); +Afl.print("done"); +Afl.done(); diff --git a/frida_mode/test/js/stalker.js b/frida_mode/test/js/stalker.js new file mode 100644 index 00000000..33f024f5 --- /dev/null +++ b/frida_mode/test/js/stalker.js @@ -0,0 +1,109 @@ +Afl.print('******************'); +Afl.print('* AFL FRIDA MODE *'); +Afl.print('******************'); +Afl.print(''); + +const main = DebugSymbol.fromName('main').address; +Afl.print(`main: ${main}`); +Afl.setEntryPoint(main); +Afl.setPersistentAddress(main); +Afl.setPersistentCount(10000000); + +/* Replace CRC-32 check */ +const crc32_check = DebugSymbol.fromName('crc32_check').address; +const crc32_replacement = new NativeCallback( + (buf, len) => { + if (len < 4) { + return 0; + } + + return 1; + }, + 'int', + ['pointer', 'int']); +Interceptor.replace(crc32_check, crc32_replacement); + +/* Patch out the first boring bug */ +const some_boring_bug = DebugSymbol.fromName('some_boring_bug').address +const boring_replacement = new NativeCallback( + (c) => { }, + 'void', + ['char']); +Interceptor.replace(some_boring_bug, boring_replacement); + +/* Modify the instructions */ +const some_boring_bug2 = DebugSymbol.fromName('some_boring_bug2').address +const pid = Memory.alloc(4); +pid.writeInt(Process.id); + +const cm = new CModule(` + #include + #include + + typedef int pid_t; + + #define STDERR_FILENO 2 + #define BORING2_LEN 10 + + extern int dprintf(int fd, const char *format, ...); + extern void some_boring_bug2(char c); + extern pid_t getpid(void); + extern pid_t pid; + + gboolean js_stalker_callback(const cs_insn *insn, gboolean begin, + gboolean excluded, GumStalkerOutput *output) + { + pid_t my_pid = getpid(); + GumX86Writer *cw = output->writer.x86; + + if (GUM_ADDRESS(insn->address) < GUM_ADDRESS(some_boring_bug2)) { + + return TRUE; + + } + + if (GUM_ADDRESS(insn->address) >= + GUM_ADDRESS(some_boring_bug2) + BORING2_LEN) { + + return TRUE; + + } + + if (my_pid == pid) { + + if (begin) { + + dprintf(STDERR_FILENO, "\n> 0x%016lX: %s %s\n", insn->address, + insn->mnemonic, insn->op_str); + + } else { + + dprintf(STDERR_FILENO, " 0x%016lX: %s %s\n", insn->address, + insn->mnemonic, insn->op_str); + + } + + } + + if (insn->id == X86_INS_UD2) { + + gum_x86_writer_put_nop(cw); + return FALSE; + + } else { + + return TRUE; + + } + } + `, + { + dprintf: Module.getExportByName(null, 'dprintf'), + getpid: Module.getExportByName(null, 'getpid'), + some_boring_bug2: some_boring_bug2, + pid: pid + }); +Afl.setStalkerCallback(cm.js_stalker_callback) +Afl.setStdErr("/tmp/stderr.txt"); +Afl.done(); +Afl.print("done"); diff --git a/frida_mode/test/js/test.c b/frida_mode/test/js/test.c new file mode 100644 index 00000000..bbda5ccf --- /dev/null +++ b/frida_mode/test/js/test.c @@ -0,0 +1,115 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include + +void LLVMFuzzerTestOneInput(char *buf, int len) { + + if (len < 1) return; + buf[len] = 0; + + // we support three input cases + if (buf[0] == '0') + printf("Looks like a zero to me!\n"); + else if (buf[0] == '1') + printf("Pretty sure that is a one!\n"); + else + printf("Neither one or zero? How quaint!\n"); + +} + +int run(char *file) { + + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + do { + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + LLVMFuzzerTestOneInput(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + +void slow() { + + usleep(100000); + +} + +int main(int argc, char **argv) { + + if (argc != 2) { return 1; } + slow(); + return run(argv[1]); + +} + diff --git a/frida_mode/test/js/test.js b/frida_mode/test/js/test.js deleted file mode 100644 index f10ef2d1..00000000 --- a/frida_mode/test/js/test.js +++ /dev/null @@ -1,20 +0,0 @@ -Afl.print('******************'); -Afl.print('* AFL FRIDA MODE *'); -Afl.print('******************'); -Afl.print(''); - -Afl.print(`PID: ${Process.id}`); - -new ModuleMap().values().forEach(m => { - Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`); -}); - -const entry_point = DebugSymbol.fromName('run'); -Afl.print(`entry_point: ${entry_point.address}`); - -Afl.setEntryPoint(entry_point.address); - -// Afl.error('HARD NOPE'); - -Afl.done(); -Afl.print("done"); diff --git a/frida_mode/test/js/test2.c b/frida_mode/test/js/test2.c new file mode 100644 index 00000000..d16f35fc --- /dev/null +++ b/frida_mode/test/js/test2.c @@ -0,0 +1,177 @@ +/* + american fuzzy lop++ - a trivial program to test the build + -------------------------------------------------------- + Originally written by Michal Zalewski + Copyright 2014 Google Inc. All rights reserved. + Copyright 2019-2020 AFLplusplus Project. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define IGNORED_RETURN(x) (void)!(x) + +const uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +uint32_t +crc32(const void *buf, size_t size) +{ + const uint8_t *p = buf; + uint32_t crc; + crc = ~0U; + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + return crc ^ ~0U; +} + +/* + * Don't you hate those contrived examples which CRC their data. We can use + * FRIDA to patch this function out and always return success. Otherwise, we + * could change it to actually correct the checksum. + */ +int crc32_check (char * buf, int len) { + if (len < sizeof(uint32_t)) { return 0; } + uint32_t expected = *(uint32_t *)&buf[len - sizeof(uint32_t)]; + uint32_t calculated = crc32(buf, len - sizeof(uint32_t)); + return expected == calculated; +} + +/* + * So you've found a really boring bug in an earlier campaign which results in + * a NULL dereference or something like that. That bug can get in the way, + * causing the persistent loop to exit whenever it is triggered, and can also + * cloud your output unnecessarily. Again, we can use FRIDA to patch it out. + */ +void some_boring_bug(char c) { + switch (c) { + case 'A'...'Z': + case 'a'...'z': + __builtin_trap(); + break; + } +} + +extern void some_boring_bug2(char c); + +__asm__ ( + ".text \n" + "some_boring_bug2: \n" + ".global some_boring_bug2 \n" + ".type some_boring_bug2, @function \n" + "mov %edi, %eax \n" + "cmp $0xb4, %al \n" + "jne ok \n" + "ud2 \n" + "ok: \n" + "ret \n"); + +void LLVMFuzzerTestOneInput(char *buf, int len) { + + if (!crc32_check(buf, len)) return; + + some_boring_bug(buf[0]); + some_boring_bug2(buf[0]); + + if (buf[0] == '0') { + printf("Looks like a zero to me!\n"); + } + else if (buf[0] == '1') { + printf("Pretty sure that is a one!\n"); + } + else if (buf[0] == '2') { + printf("Oh we, weren't expecting that!"); + __builtin_trap(); + } + else + printf("Neither one or zero? How quaint!\n"); + +} + +int main(int argc, char **argv) { + + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + printf("Running: %s\n", argv[1]); + + fd = open(argv[1], O_RDONLY); + if (fd < 0) { return 1; } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { return 1; } + + if (lseek(fd, 0, SEEK_SET) != 0) { return 1; } + + buf = malloc(len); + if (buf == NULL) { return 1; } + + n_read = read(fd, buf, len); + if (n_read != len) { return 1; } + + printf("Running: %s: (%zd bytes)\n", argv[1], n_read); + + LLVMFuzzerTestOneInput(buf, len); + printf("Done: %s: (%zd bytes)\n", argv[1], n_read); + + return 0; +} + diff --git a/frida_mode/test/js/testinstr.c b/frida_mode/test/js/testinstr.c deleted file mode 100644 index bd605c52..00000000 --- a/frida_mode/test/js/testinstr.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - american fuzzy lop++ - a trivial program to test the build - -------------------------------------------------------- - Originally written by Michal Zalewski - Copyright 2014 Google Inc. All rights reserved. - Copyright 2019-2020 AFLplusplus Project. All rights reserved. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at: - http://www.apache.org/licenses/LICENSE-2.0 - */ - -#include -#include -#include -#include -#include - -#ifdef __APPLE__ - #define TESTINSTR_SECTION -#else - #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) -#endif - -void testinstr(char *buf, int len) { - - if (len < 1) return; - buf[len] = 0; - - // we support three input cases - if (buf[0] == '0') - printf("Looks like a zero to me!\n"); - else if (buf[0] == '1') - printf("Pretty sure that is a one!\n"); - else - printf("Neither one or zero? How quaint!\n"); - -} - -int run(char *file) { - - int fd = -1; - off_t len; - char * buf = NULL; - size_t n_read; - int result = -1; - - do { - - dprintf(STDERR_FILENO, "Running: %s\n", file); - - fd = open(file, O_RDONLY); - if (fd < 0) { - - perror("open"); - break; - - } - - len = lseek(fd, 0, SEEK_END); - if (len < 0) { - - perror("lseek (SEEK_END)"); - break; - - } - - if (lseek(fd, 0, SEEK_SET) != 0) { - - perror("lseek (SEEK_SET)"); - break; - - } - - buf = malloc(len); - if (buf == NULL) { - - perror("malloc"); - break; - - } - - n_read = read(fd, buf, len); - if (n_read != len) { - - perror("read"); - break; - - } - - dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); - - testinstr(buf, len); - dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); - - result = 0; - - } while (false); - - if (buf != NULL) { free(buf); } - - if (fd != -1) { close(fd); } - - return result; - -} - -void slow() { - - usleep(100000); - -} - -int main(int argc, char **argv) { - - if (argc != 2) { return 1; } - slow(); - return run(argv[1]); - -} - diff --git a/frida_mode/test/libpcap/GNUmakefile b/frida_mode/test/libpcap/GNUmakefile index e30f2049..8a10be07 100644 --- a/frida_mode/test/libpcap/GNUmakefile +++ b/frida_mode/test/libpcap/GNUmakefile @@ -2,8 +2,7 @@ PWD:=$(shell pwd)/ ROOT:=$(shell realpath $(PWD)../../..)/ BUILD_DIR:=$(PWD)build/ -AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c -AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so +AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so LIBPCAP_BUILD_DIR:=$(BUILD_DIR)libpcap/ HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ @@ -137,11 +136,6 @@ $(TEST_BIN): $(HARNESS_OBJ) $(PCAPTEST_OBJ) $(LIBPCAP_LIB) $(LDFLAGS) \ $(TEST_BIN_LDFLAGS) \ -########## HOOK ######## - -$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) - $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ - ########## DUMMY ####### $(AFLPP_DRIVER_DUMMY_INPUT): | $(TCPDUMP_TESTS_DIR) @@ -149,8 +143,6 @@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(TCPDUMP_TESTS_DIR) ###### TEST DATA ####### -hook: $(AFLPP_DRIVER_HOOK_OBJ) - clean: rm -rf $(BUILD_DIR) diff --git a/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c b/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c deleted file mode 100644 index 059d438d..00000000 --- a/frida_mode/test/libpcap/aflpp_qemu_driver_hook.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include - -#if defined(__x86_64__) - -struct x86_64_regs { - - uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, - r15; - - union { - - uint64_t rip; - uint64_t pc; - - }; - - union { - - uint64_t rsp; - uint64_t sp; - - }; - - union { - - uint64_t rflags; - uint64_t flags; - - }; - - uint8_t zmm_regs[32][64]; - -}; - -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - memcpy((void *)regs->rdi, input_buf, input_buf_len); - regs->rsi = input_buf_len; - -} - -#elif defined(__i386__) - -struct x86_regs { - - uint32_t eax, ebx, ecx, edx, edi, esi, ebp; - - union { - - uint32_t eip; - uint32_t pc; - - }; - - union { - - uint32_t esp; - uint32_t sp; - - }; - - union { - - uint32_t eflags; - uint32_t flags; - - }; - - uint8_t xmm_regs[8][16]; - -}; - -void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - void **esp = (void **)regs->esp; - void * arg1 = esp[1]; - void **arg2 = &esp[2]; - memcpy(arg1, input_buf, input_buf_len); - *arg2 = (void *)input_buf_len; - -} - -#else - #pragma error "Unsupported architecture" -#endif - -int afl_persistent_hook_init(void) { - - // 1 for shared memory input (faster), 0 for normal input (you have to use - // read(), input_buf will be NULL) - return 1; - -} - diff --git a/frida_mode/test/persistent_ret/GNUmakefile b/frida_mode/test/persistent_ret/GNUmakefile index 81fdd069..f11269e3 100644 --- a/frida_mode/test/persistent_ret/GNUmakefile +++ b/frida_mode/test/persistent_ret/GNUmakefile @@ -90,7 +90,7 @@ frida_js: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) -i $(TESTINSTR_DATA_DIR) \ -o $(FRIDA_OUT) \ -- \ - $(TESTINSTBIN) @@ + $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) gdb \ @@ -102,6 +102,15 @@ debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) --ex 'set disassembly-flavor intel' \ --args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) +debug_js: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + gdb \ + --ex 'set environment AFL_FRIDA_JS_SCRIPT=test.js' \ + --ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \ + --ex 'set environment AFL_DEBUG_CHILD=1' \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --args $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + run: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \ diff --git a/frida_mode/test/persistent_ret/test.js b/frida_mode/test/persistent_ret/test.js index 43c6ad7c..8adb45b2 100644 --- a/frida_mode/test/persistent_ret/test.js +++ b/frida_mode/test/persistent_ret/test.js @@ -5,34 +5,44 @@ Afl.print(''); Afl.print(`PID: ${Process.id}`); +const name = Process.enumerateModules()[0].name; +Afl.print(`Name: ${name}`); + new ModuleMap().values().forEach(m => { Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`); }); -const persistent_addr = DebugSymbol.fromName('main'); -Afl.print(`persistent_addr: ${persistent_addr.address}`); - -const persistent_ret = DebugSymbol.fromName('slow'); -Afl.print(`persistent_ret: ${persistent_ret.address}`); - -Afl.setPersistentAddress(persistent_addr.address); -Afl.setPersistentReturn(persistent_ret.address); -Afl.setPersistentCount(1000000); - -Afl.setDebugMaps(); - -const mod = Process.findModuleByName("libc-2.31.so") -Afl.addExcludedRange(mod.base, mod.size); -Afl.setInstrumentLibraries(); -Afl.setInstrumentDebugFile("/tmp/instr.log"); -Afl.setPrefetchDisable(); -Afl.setInstrumentNoOptimize(); -Afl.setInstrumentEnableTracing(); -Afl.setInstrumentTracingUnique(); -Afl.setStdOut("/tmp/stdout.txt"); -Afl.setStdErr("/tmp/stderr.txt"); -Afl.setStatsFile("/tmp/stats.txt"); -Afl.setStatsInterval(1); -Afl.setStatsTransitions(); -Afl.done(); +if (name === 'testinstr') { + const persistent_addr = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address; + Afl.print(`persistent_addr: ${persistent_addr}`); + Afl.setEntryPoint(persistent_addr); + Afl.setPersistentAddress(persistent_addr); + Afl.setInstrumentDebugFile("/dev/stdout"); + Afl.setPersistentDebug(); + Afl.setInstrumentNoOptimize(); + Afl.setInstrumentEnableTracing(); + + const LLVMFuzzerTestOneInput = new NativeFunction( + persistent_addr, + 'void', + ['pointer', 'uint64'], + {traps: "all"}); + + const persistentHook = new NativeCallback( + (data, size) => { + const input = Afl.aflFuzzPtr.readPointer(); + const len = Afl.aflFuzzLen.readPointer().readU32(); + const hd = hexdump(input, {length: len, header: false, ansi: true}); + Afl.print(`input: ${hd}`); + LLVMFuzzerTestOneInput(input, len); + }, + 'void', + ['pointer', 'uint64']); + + Afl.aflSharedMemFuzzing.writeInt(1); + Interceptor.replace(persistent_addr, persistentHook); + Interceptor.flush(); +} + Afl.print("done"); +Afl.done(); diff --git a/frida_mode/test/persistent_ret/testinstr.c b/frida_mode/test/persistent_ret/testinstr.c index 6cb88a50..42e3519a 100644 --- a/frida_mode/test/persistent_ret/testinstr.c +++ b/frida_mode/test/persistent_ret/testinstr.c @@ -17,13 +17,14 @@ #include #ifdef __APPLE__ - #define TESTINSTR_SECTION + #define MAIN_SECTION #else - #define TESTINSTR_SECTION __attribute__((section(".testinstr"))) + #define MAIN_SECTION __attribute__((section(".main"))) #endif -void testinstr(char *buf, int len) { +void LLVMFuzzerTestOneInput(char *buf, int len) { + printf (">>> LLVMFuzzerTestOneInput >>>\n"); if (len < 1) return; buf[len] = 0; @@ -43,7 +44,7 @@ void slow() { } -TESTINSTR_SECTION int main(int argc, char **argv) { +MAIN_SECTION int main(int argc, char **argv) { char * file; int fd = -1; @@ -101,7 +102,7 @@ TESTINSTR_SECTION int main(int argc, char **argv) { dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); - testinstr(buf, len); + LLVMFuzzerTestOneInput(buf, len); dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); slow(); diff --git a/frida_mode/test/png/persistent/hook/GNUmakefile b/frida_mode/test/png/persistent/hook/GNUmakefile index b17f3775..0ff9fe86 100644 --- a/frida_mode/test/png/persistent/hook/GNUmakefile +++ b/frida_mode/test/png/persistent/hook/GNUmakefile @@ -2,8 +2,7 @@ PWD:=$(shell pwd)/ ROOT:=$(shell realpath $(PWD)../../../../..)/ BUILD_DIR:=$(PWD)build/ -AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c -AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so +AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so CFLAGS+=-O3 \ -funroll-loops \ @@ -48,7 +47,7 @@ endif .PHONY: all 32 clean format qemu qemu_entry frida frida_entry debug -all: $(AFLPP_DRIVER_HOOK_OBJ) +all: make -C $(ROOT)frida_mode/test/png/persistent/ 32: @@ -68,9 +67,6 @@ $(TEST_DATA_DIR): | $(BUILD_DIR) $(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) truncate -s 1M $@ -$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) - $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ - qemu: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_DRIVER_HOOK_OBJ) \ AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ @@ -124,6 +120,28 @@ frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) -- \ $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) +frida_js_load: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_FRIDA_JS_SCRIPT=load.js \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +frida_js_cmodule: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_FRIDA_JS_SCRIPT=cmodule.js \ + $(ROOT)afl-fuzz \ + -D \ + -V 30 \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) + debug: $(AFLPP_DRIVER_DUMMY_INPUT) echo $(AFL_FRIDA_PERSISTENT_ADDR) gdb \ diff --git a/frida_mode/test/png/persistent/hook/Makefile b/frida_mode/test/png/persistent/hook/Makefile index 983d009e..dca51d85 100644 --- a/frida_mode/test/png/persistent/hook/Makefile +++ b/frida_mode/test/png/persistent/hook/Makefile @@ -24,5 +24,8 @@ frida: frida_entry: @gmake frida_entry +frida_js: + @gmake frida_js + debug: @gmake debug diff --git a/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c b/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c deleted file mode 100644 index 1542c0bf..00000000 --- a/frida_mode/test/png/persistent/hook/aflpp_qemu_driver_hook.c +++ /dev/null @@ -1,193 +0,0 @@ -#include -#include - -#if defined(__x86_64__) - -struct x86_64_regs { - - uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, - r15; - - union { - - uint64_t rip; - uint64_t pc; - - }; - - union { - - uint64_t rsp; - uint64_t sp; - - }; - - union { - - uint64_t rflags; - uint64_t flags; - - }; - - uint8_t zmm_regs[32][64]; - -}; - -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - memcpy((void *)regs->rdi, input_buf, input_buf_len); - regs->rsi = input_buf_len; - -} - -#elif defined(__i386__) - -struct x86_regs { - - uint32_t eax, ebx, ecx, edx, edi, esi, ebp; - - union { - - uint32_t eip; - uint32_t pc; - - }; - - union { - - uint32_t esp; - uint32_t sp; - - }; - - union { - - uint32_t eflags; - uint32_t flags; - - }; - - uint8_t xmm_regs[8][16]; - -}; - -void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - void **esp = (void **)regs->esp; - void * arg1 = esp[1]; - void **arg2 = &esp[2]; - memcpy(arg1, input_buf, input_buf_len); - *arg2 = (void *)input_buf_len; - -} -#elif defined(__aarch64__) - -struct arm64_regs { - - uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10; - - union { - - uint64_t x11; - uint32_t fp_32; - - }; - - union { - - uint64_t x12; - uint32_t ip_32; - - }; - - union { - - uint64_t x13; - uint32_t sp_32; - - }; - - union { - - uint64_t x14; - uint32_t lr_32; - - }; - - union { - - uint64_t x15; - uint32_t pc_32; - - }; - - union { - - uint64_t x16; - uint64_t ip0; - - }; - - union { - - uint64_t x17; - uint64_t ip1; - - }; - - uint64_t x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28; - - union { - - uint64_t x29; - uint64_t fp; - - }; - - union { - - uint64_t x30; - uint64_t lr; - - }; - - union { - - uint64_t x31; - uint64_t sp; - - }; - - // the zero register is not saved here ofc - - uint64_t pc; - - uint32_t cpsr; - - uint8_t vfp_zregs[32][16 * 16]; - uint8_t vfp_pregs[17][32]; - uint32_t vfp_xregs[16]; - -}; - -void afl_persistent_hook(struct arm64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - memcpy((void *)regs->x0, input_buf, input_buf_len); - regs->x1 = input_buf_len; -} - -#else - #pragma error "Unsupported architecture" -#endif - -int afl_persistent_hook_init(void) { - - // 1 for shared memory input (faster), 0 for normal input (you have to use - // read(), input_buf will be NULL) - return 1; - -} - diff --git a/frida_mode/test/png/persistent/hook/cmodule.js b/frida_mode/test/png/persistent/hook/cmodule.js new file mode 100644 index 00000000..ab8bdc66 --- /dev/null +++ b/frida_mode/test/png/persistent/hook/cmodule.js @@ -0,0 +1,39 @@ +Afl.print('******************'); +Afl.print('* AFL FRIDA MODE *'); +Afl.print('******************'); +Afl.print(''); + +Afl.print(`PID: ${Process.id}`); + +const name = Process.enumerateModules()[0].name; +Afl.print(`Name: ${name}`); + +new ModuleMap().values().forEach(m => { + Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`); +}); + +const persistent_addr = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address; +Afl.print(`persistent_addr: ${persistent_addr}`); +Afl.setEntryPoint(persistent_addr); +Afl.setPersistentAddress(persistent_addr); + +const cm = new CModule(` + + #include + #include + + void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, + uint32_t input_buf_len) { + + memcpy((void *)regs->rdi, input_buf, input_buf_len); + regs->rsi = input_buf_len; + + } + `, + { + memcpy: Module.getExportByName(null, 'memcpy') + }); +Afl.setPersistentHook(cm.afl_persistent_hook); + +Afl.print("done"); +Afl.done(); diff --git a/frida_mode/test/png/persistent/hook/load.js b/frida_mode/test/png/persistent/hook/load.js new file mode 100644 index 00000000..ce4374ae --- /dev/null +++ b/frida_mode/test/png/persistent/hook/load.js @@ -0,0 +1,27 @@ +Afl.print('******************'); +Afl.print('* AFL FRIDA MODE *'); +Afl.print('******************'); +Afl.print(''); + +Afl.print(`PID: ${Process.id}`); + +const name = Process.enumerateModules()[0].name; +Afl.print(`Name: ${name}`); + +new ModuleMap().values().forEach(m => { + Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`); +}); + +const persistent_addr = DebugSymbol.fromName('LLVMFuzzerTestOneInput').address; +Afl.print(`persistent_addr: ${persistent_addr}`); +Afl.setEntryPoint(persistent_addr); +Afl.setPersistentAddress(persistent_addr); + +const path = Afl.module.path; +const dir = path.substring(0, path.lastIndexOf("/")); +const mod = Module.load(`${dir}/frida_mode/build/hook.so`); +const hook = mod.getExportByName('afl_persistent_hook'); +Afl.setPersistentHook(hook); + +Afl.print("done"); +Afl.done(); diff --git a/frida_mode/test/proj4/GNUmakefile b/frida_mode/test/proj4/GNUmakefile index 09112cd5..e324a5d0 100644 --- a/frida_mode/test/proj4/GNUmakefile +++ b/frida_mode/test/proj4/GNUmakefile @@ -2,8 +2,7 @@ PWD:=$(shell pwd)/ ROOT:=$(shell realpath $(PWD)../../..)/ BUILD_DIR:=$(PWD)build/ -AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c -AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so +AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so LIBPROJ4_BUILD_DIR:=$(BUILD_DIR)libproj4/ HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ @@ -118,11 +117,6 @@ $(TEST_BIN): $(HARNESS_OBJ) $(PROJ4TEST_OBJ) $(LIBPROJ4_LIB) $(LDFLAGS) \ $(TEST_BIN_LDFLAGS) \ -########## HOOK ######## - -$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) - $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ - ########## DUMMY ####### $(TEST_DATA_DIR): | $(BUILD_DIR) @@ -133,8 +127,6 @@ $(TEST_DATA_FILE): | $(TEST_DATA_DIR) ###### TEST DATA ####### -hook: $(AFLPP_DRIVER_HOOK_OBJ) - clean: rm -rf $(BUILD_DIR) diff --git a/frida_mode/test/proj4/Makefile b/frida_mode/test/proj4/Makefile index 863438cf..f83e2992 100644 --- a/frida_mode/test/proj4/Makefile +++ b/frida_mode/test/proj4/Makefile @@ -15,5 +15,3 @@ frida: debug: @gmake debug -hook: - @gmake hook diff --git a/frida_mode/test/proj4/aflpp_qemu_driver_hook.c b/frida_mode/test/proj4/aflpp_qemu_driver_hook.c deleted file mode 100644 index 059d438d..00000000 --- a/frida_mode/test/proj4/aflpp_qemu_driver_hook.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include - -#if defined(__x86_64__) - -struct x86_64_regs { - - uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, - r15; - - union { - - uint64_t rip; - uint64_t pc; - - }; - - union { - - uint64_t rsp; - uint64_t sp; - - }; - - union { - - uint64_t rflags; - uint64_t flags; - - }; - - uint8_t zmm_regs[32][64]; - -}; - -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - memcpy((void *)regs->rdi, input_buf, input_buf_len); - regs->rsi = input_buf_len; - -} - -#elif defined(__i386__) - -struct x86_regs { - - uint32_t eax, ebx, ecx, edx, edi, esi, ebp; - - union { - - uint32_t eip; - uint32_t pc; - - }; - - union { - - uint32_t esp; - uint32_t sp; - - }; - - union { - - uint32_t eflags; - uint32_t flags; - - }; - - uint8_t xmm_regs[8][16]; - -}; - -void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - void **esp = (void **)regs->esp; - void * arg1 = esp[1]; - void **arg2 = &esp[2]; - memcpy(arg1, input_buf, input_buf_len); - *arg2 = (void *)input_buf_len; - -} - -#else - #pragma error "Unsupported architecture" -#endif - -int afl_persistent_hook_init(void) { - - // 1 for shared memory input (faster), 0 for normal input (you have to use - // read(), input_buf will be NULL) - return 1; - -} - diff --git a/frida_mode/test/re2/GNUmakefile b/frida_mode/test/re2/GNUmakefile index 9f0b31d3..e1c5347d 100644 --- a/frida_mode/test/re2/GNUmakefile +++ b/frida_mode/test/re2/GNUmakefile @@ -2,8 +2,7 @@ PWD:=$(shell pwd)/ ROOT:=$(shell realpath $(PWD)../../..)/ BUILD_DIR:=$(PWD)build/ -AFLPP_DRIVER_HOOK_SRC=$(PWD)aflpp_qemu_driver_hook.c -AFLPP_DRIVER_HOOK_OBJ=$(BUILD_DIR)aflpp_qemu_driver_hook.so +AFLPP_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/hook.so LIBRE2_BUILD_DIR:=$(BUILD_DIR)libre2/ HARNESS_BUILD_DIR:=$(BUILD_DIR)harness/ @@ -116,11 +115,6 @@ $(TEST_BIN): $(HARNESS_OBJ) $(RE2TEST_OBJ) $(LIBRE2_LIB) $(LDFLAGS) \ $(TEST_BIN_LDFLAGS) \ -########## HOOK ######## - -$(AFLPP_DRIVER_HOOK_OBJ): $(AFLPP_DRIVER_HOOK_SRC) | $(BUILD_DIR) - $(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@ - ########## DUMMY ####### $(TEST_DATA_DIR): | $(BUILD_DIR) @@ -131,8 +125,6 @@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(TEST_DATA_DIR) ###### TEST DATA ####### -hook: $(AFLPP_DRIVER_HOOK_OBJ) - clean: rm -rf $(BUILD_DIR) diff --git a/frida_mode/test/re2/Makefile b/frida_mode/test/re2/Makefile index 00b2b287..360cdc44 100644 --- a/frida_mode/test/re2/Makefile +++ b/frida_mode/test/re2/Makefile @@ -18,5 +18,3 @@ frida: debug: @gmake debug -hook: - @gmake hook diff --git a/frida_mode/test/re2/aflpp_qemu_driver_hook.c b/frida_mode/test/re2/aflpp_qemu_driver_hook.c deleted file mode 100644 index 059d438d..00000000 --- a/frida_mode/test/re2/aflpp_qemu_driver_hook.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include - -#if defined(__x86_64__) - -struct x86_64_regs { - - uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, r8, r9, r10, r11, r12, r13, r14, - r15; - - union { - - uint64_t rip; - uint64_t pc; - - }; - - union { - - uint64_t rsp; - uint64_t sp; - - }; - - union { - - uint64_t rflags; - uint64_t flags; - - }; - - uint8_t zmm_regs[32][64]; - -}; - -void afl_persistent_hook(struct x86_64_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - memcpy((void *)regs->rdi, input_buf, input_buf_len); - regs->rsi = input_buf_len; - -} - -#elif defined(__i386__) - -struct x86_regs { - - uint32_t eax, ebx, ecx, edx, edi, esi, ebp; - - union { - - uint32_t eip; - uint32_t pc; - - }; - - union { - - uint32_t esp; - uint32_t sp; - - }; - - union { - - uint32_t eflags; - uint32_t flags; - - }; - - uint8_t xmm_regs[8][16]; - -}; - -void afl_persistent_hook(struct x86_regs *regs, uint64_t guest_base, - uint8_t *input_buf, uint32_t input_buf_len) { - - void **esp = (void **)regs->esp; - void * arg1 = esp[1]; - void **arg2 = &esp[2]; - memcpy(arg1, input_buf, input_buf_len); - *arg2 = (void *)input_buf_len; - -} - -#else - #pragma error "Unsupported architecture" -#endif - -int afl_persistent_hook_init(void) { - - // 1 for shared memory input (faster), 0 for normal input (you have to use - // read(), input_buf will be NULL) - return 1; - -} - diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts new file mode 100644 index 00000000..6da7fabc --- /dev/null +++ b/frida_mode/ts/lib/afl.ts @@ -0,0 +1,373 @@ +class Afl { + + /** + * Field containing the `Module` object for `afl-frida-trace.so` (the FRIDA mode + * implementation). + */ + public static module: Module = Process.getModuleByName("afl-frida-trace.so"); + + /** + * 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. + */ + public static addExcludedRange(addressess: NativePointer, size: number): void { + 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. + */ + public static addIncludedRange(addressess: NativePointer, size: number): void { + 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. + */ + public static done(): void { + 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. + */ + public static error(msg: string): void { + 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. + */ + public static getAflFuzzLen(): NativePointer { + + 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. + */ + public static getAflFuzzPtr(): NativePointer { + + 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. + */ + public static print(msg: string): void { + 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`. + */ + public static setDebugMaps(): void { + 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. + */ + public static setEntryPoint(address: NativePointer): void { + Afl.jsApiSetEntryPoint(address); + } + + /** + * Function used to enable in-memory test cases for fuzzing. + */ + public static setInMemoryFuzzing(): void { + Afl.jsApiAflSharedMemFuzzing.writeInt(1); + } + + /** + * See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as + * an argument. + */ + public static setInstrumentDebugFile(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentDebugFile(buf); + } + + /** + * See `AFL_FRIDA_INST_TRACE`. + */ + public static setInstrumentEnableTracing(): void { + Afl.jsApiSetInstrumentTrace(); + } + + /** + * See `AFL_INST_LIBS`. + */ + public static setInstrumentLibraries(): void { + Afl.jsApiSetInstrumentLibraries(); + } + + /** + * See `AFL_FRIDA_INST_NO_OPTIMIZE` + */ + public static setInstrumentNoOptimize(): void { + Afl.jsApiSetInstrumentNoOptimize(); + } + + /** + * See `AFL_FRIDA_INST_TRACE_UNIQUE`. + */ + public static setInstrumentTracingUnique(): void { + Afl.jsApiSetInstrumentTraceUnique(); + } + + /** + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a + * `NativePointer` should be provided as it's argument. + */ + public static setPersistentAddress(address: NativePointer): void { + Afl.jsApiSetPersistentAddress(address); + } + + /** + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a + * `number` should be provided as it's argument. + */ + public static setPersistentCount(count: number): void { + Afl.jsApiSetPersistentCount(count); + } + + /** + * See `AFL_FRIDA_PERSISTENT_DEBUG`. + */ + public static setPersistentDebug(): void { + Afl.jsApiSetPersistentDebug(); + } + + /** + * See `AFL_FRIDA_PERSISTENT_ADDR`. This function takes a NativePointer as an + * argument. See above for examples of use. + */ + public static setPersistentHook(address: NativePointer): void { + Afl.jsApiSetPersistentHook(address); + } + + /** + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a + * `NativePointer` should be provided as it's argument. + */ + public static setPersistentReturn(address: NativePointer): void { + Afl.jsApiSetPersistentReturn(address); + } + + /** + * See `AFL_FRIDA_INST_NO_PREFETCH`. + */ + public static setPrefetchDisable(): void { + Afl.jsApiSetPrefetchDisable(); + } + + /* + * Set a function to be called for each instruction which is instrumented + * by AFL FRIDA mode. + */ + public static setStalkerCallback(callback: NativePointer): void { + Afl.jsApiSetStalkerCallback(callback); + } + + /** + * See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as + * an argument. + */ + public static setStatsFile(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStatsFile(buf); + } + + /** + * See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an + * argument + */ + public static setStatsInterval(interval: number): void { + Afl.jsApiSetStatsInterval(interval); + } + + /** + * See `AFL_FRIDA_STATS_TRANSITIONS` + */ + public static setStatsTransitions(): void { + Afl.jsApiSetStatsTransitions(); + } + + /** + * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as + * an argument. + */ + public static setStdErr(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStdErr(buf); + } + + /** + * See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as + * an argument. + */ + public static setStdOut(file: string): void { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStdOut(buf); + } + + private static readonly jsApiAddExcludeRange = Afl.jsApiGetFunction( + "js_api_add_exclude_range", + "void", + ["pointer", "size_t"]); + + private static readonly jsApiAddIncludeRange = Afl.jsApiGetFunction( + "js_api_add_include_range", + "void", + ["pointer", "size_t"]); + + private static readonly jsApiAflSharedMemFuzzing = Afl.jsApiGetSymbol("__afl_sharedmem_fuzzing"); + + private static readonly jsApiDone = Afl.jsApiGetFunction( + "js_api_done", + "void", + []); + + private static readonly jsApiError = Afl.jsApiGetFunction( + "js_api_error", + "void", + ["pointer"]); + + private static readonly jsApiSetDebugMaps = Afl.jsApiGetFunction( + "js_api_set_debug_maps", + "void", + []); + + private static readonly jsApiSetEntryPoint = Afl.jsApiGetFunction( + "js_api_set_entrypoint", + "void", + ["pointer"]); + + private static readonly jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction( + "js_api_set_instrument_debug_file", + "void", + ["pointer"]); + + private static readonly jsApiSetInstrumentLibraries = Afl.jsApiGetFunction( + "js_api_set_instrument_libraries", + "void", + []); + + private static readonly jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction( + "js_api_set_instrument_no_optimize", + "void", + []); + + private static readonly jsApiSetInstrumentTrace = Afl.jsApiGetFunction( + "js_api_set_instrument_trace", + "void", + []); + + private static readonly jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction( + "js_api_set_instrument_trace_unique", + "void", + []); + + private static readonly jsApiSetPersistentAddress = Afl.jsApiGetFunction( + "js_api_set_persistent_address", + "void", + ["pointer"]); + + private static readonly jsApiSetPersistentCount = Afl.jsApiGetFunction( + "js_api_set_persistent_count", + "void", + ["uint64"]); + + private static readonly jsApiSetPersistentDebug = Afl.jsApiGetFunction( + "js_api_set_persistent_debug", + "void", + []); + + private static readonly jsApiSetPersistentHook = Afl.jsApiGetFunction( + "js_api_set_persistent_hook", + "void", + ["pointer"]); + + private static readonly jsApiSetPersistentReturn = Afl.jsApiGetFunction( + "js_api_set_persistent_return", + "void", + ["pointer"]); + + private static readonly jsApiSetPrefetchDisable = Afl.jsApiGetFunction( + "js_api_set_prefetch_disable", + "void", + []); + + private static readonly jsApiSetStalkerCallback = Afl.jsApiGetFunction( + "js_api_set_stalker_callback", + "void", + ["pointer"]); + + private static readonly jsApiSetStatsFile = Afl.jsApiGetFunction( + "js_api_set_stats_file", + "void", + ["pointer"]); + + private static readonly jsApiSetStatsInterval = Afl.jsApiGetFunction( + "js_api_set_stats_interval", + "void", + ["uint64"]); + + private static readonly jsApiSetStatsTransitions = Afl.jsApiGetFunction( + "js_api_set_stats_transitions", + "void", + []); + + private static readonly jsApiSetStdErr = Afl.jsApiGetFunction( + "js_api_set_stderr", + "void", + ["pointer"]); + + private static readonly jsApiSetStdOut = Afl.jsApiGetFunction( + "js_api_set_stdout", + "void", + ["pointer"]); + + private static readonly jsApiWrite = new NativeFunction( + /* tslint:disable-next-line:no-null-keyword */ + Module.getExportByName(null, "write"), + "int", + ["int", "pointer", "int"]); + + private static jsApiGetFunction(name: string, retType: NativeType, argTypes: NativeType[]): NativeFunction { + const addr: NativePointer = Afl.module.getExportByName(name); + + return new NativeFunction(addr, retType, argTypes); + } + + private static jsApiGetSymbol(name: string): NativePointer { + + return Afl.module.getExportByName(name); + } + +} diff --git a/frida_mode/ts/package-lock.json b/frida_mode/ts/package-lock.json new file mode 100644 index 00000000..e766c2c2 --- /dev/null +++ b/frida_mode/ts/package-lock.json @@ -0,0 +1,12 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "tsc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tsc/-/tsc-2.0.3.tgz", + "integrity": "sha512-SN+9zBUtrpUcOpaUO7GjkEHgWtf22c7FKbKCA4e858eEM7Qz86rRDpgOU2lBIDf0fLCsEg65ms899UMUIB2+Ow==", + "dev": true + } + } +} diff --git a/frida_mode/ts/package.json b/frida_mode/ts/package.json new file mode 100644 index 00000000..47b693ed --- /dev/null +++ b/frida_mode/ts/package.json @@ -0,0 +1,32 @@ +{ + "name": "@worksbutnottested/aflplusplus-frida", + "version": "1.0.0", + "description": "AFLplusplus Frida Mode", + "main": "./dist/frida.js", + "types": "./dist/frida.d.ts", + "files": [ + "/dist/" + ], + "repository": { + "type": "git", + "url": "git@github.com:worksbutnottested/AFLplusplus.git" + }, + "publishConfig": { + "cache": "~/.npm", + "registry": "https://npm.pkg.github.com/@worksbutnottested" + }, + "scripts": { + "prepare": "npm run build", + "build": "tsc", + "lint": "tslint -p tslint.json" + }, + "devDependencies": { + "@types/node": "^14.14.2", + "typescript": "^4.0.3", + "typescript-tslint-plugin": "^0.5.5", + "tslint": "^6.1.3" + }, + "dependencies": { + "@types/frida-gum": "^16.2.0" + } + } diff --git a/frida_mode/ts/tsconfig.json b/frida_mode/ts/tsconfig.json new file mode 100644 index 00000000..624e4496 --- /dev/null +++ b/frida_mode/ts/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2020", + "lib": ["es2020"], + "strict": true, + "module": "commonjs", + "esModuleInterop": true, + "declaration": true, + "outDir": "./dist" + }, + "include": [ + "lib/**/*" + ] + } diff --git a/frida_mode/ts/tslint.json b/frida_mode/ts/tslint.json new file mode 100644 index 00000000..0e7a77ed --- /dev/null +++ b/frida_mode/ts/tslint.json @@ -0,0 +1,256 @@ +{ + "rules": { + "adjacent-overload-signatures": true, + "ban-types": { + "options": [ + ["Object", "Avoid using the `Object` type. Did you mean `object`?"], + [ + "Function", + "Avoid using the `Function` type. Prefer a specific function type, like `() => void`." + ], + ["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"], + ["Number", "Avoid using the `Number` type. Did you mean `number`?"], + ["String", "Avoid using the `String` type. Did you mean `string`?"], + ["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"] + ] + }, + "ban-ts-ignore": true, + "member-access": { + "options": ["check-accessor", "check-constructor", "check-parameter-property"] + }, + "member-ordering": { + "options": { + "order": "statics-first", + "alphabetize": true + } + }, + "no-any": true, + "no-empty-interface": true, + "no-for-in": true, + "no-import-side-effect": true, + "no-inferrable-types": { "options": ["ignore-params"] }, + "no-internal-module": true, + "no-magic-numbers": true, + "no-namespace": true, + "no-non-null-assertion": true, + "no-reference": true, + "no-restricted-globals": true, + "no-this-assignment": true, + "no-var-requires": true, + "only-arrow-functions": true, + "prefer-for-of": true, + "prefer-readonly": true, + "promise-function-async": true, + "typedef": { + "options": [ + "call-signature", + "parameter", + "property-declaration" + ] + }, + "typedef-whitespace": { + "options": [ + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + }, + { + "call-signature": "onespace", + "index-signature": "onespace", + "parameter": "onespace", + "property-declaration": "onespace", + "variable-declaration": "onespace" + } + ] + }, + "unified-signatures": true, + "await-promise": true, + "ban-comma-operator": true, + "curly": true, + "forin": true, + "function-constructor": true, + "label-position": true, + "no-arg": true, + "no-async-without-await": true, + "no-bitwise": true, + "no-conditional-assignment": true, + "no-console": true, + "no-construct": true, + "no-debugger": true, + "no-duplicate-super": true, + "no-duplicate-switch-case": true, + "no-duplicate-variable": { "options": ["check-parameters"] }, + "no-dynamic-delete": true, + "no-empty": true, + "no-eval": true, + "no-floating-promises": true, + "no-for-in-array": true, + "no-implicit-dependencies": true, + "no-inferred-empty-object-type": true, + "no-invalid-template-strings": true, + "no-misused-new": true, + "no-null-keyword": true, + "no-null-undefined-union": true, + "no-object-literal-type-assertion": true, + "no-promise-as-boolean": true, + "no-return-await": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-string-throw": true, + "no-sparse-arrays": true, + "no-submodule-imports": true, + "no-tautology-expression": true, + "no-unbound-method": true, + "no-unnecessary-class": { "options": ["allow-empty-class", "allow-static-only"] }, + "no-unsafe-any": false, + "no-unsafe-finally": true, + "no-unused-expression": true, + "no-var-keyword": true, + "no-void-expression": true, + "prefer-conditional-expression": true, + "radix": true, + "restrict-plus-operands": true, + "static-this": true, + "strict-boolean-expressions": true, + "strict-string-expressions": true, + "strict-comparisons": true, + "strict-type-predicates": true, + "switch-default": true, + "triple-equals": true, + "unnecessary-constructor": true, + "use-default-type-parameter": true, + "use-isnan": true, + "cyclomatic-complexity": true, + "eofline": true, + "indent": { "options": ["spaces"] }, + "invalid-void": true, + "linebreak-style": { "options": "LF" }, + "max-classes-per-file": { "options": 1 }, + "max-file-line-count": { "options": 1000 }, + "max-line-length": { + "options": { "limit": 120 } + }, + "no-default-export": true, + "no-default-import": true, + "no-duplicate-imports": true, + "no-irregular-whitespace": true, + "no-mergeable-namespace": true, + "no-parameter-reassignment": true, + "no-require-imports": true, + "no-trailing-whitespace": true, + "object-literal-sort-keys": true, + "prefer-const": true, + "trailing-comma": { + "options": { + "esSpecCompliant": true, + "multiline": "always", + "singleline": "never" + } + }, + "align": { + "options": ["parameters", "arguments", "statements", "elements", "members"] + }, + "array-type": { "options": "array-simple" }, + "arrow-parens": true, + "arrow-return-shorthand": { "options": "multiline" }, + "binary-expression-operand-order": true, + "callable-types": true, + "class-name": true, + "comment-format": { "options": ["check-space", "check-uppercase"] }, + "comment-type": { "options": ["singleline", "multiline", "doc", "directive"] }, + "completed-docs": [ + true, + { + "enums": true, + "methods": {"locations": "all", "privacies": ["public", "protected"]}, + "properties": {"locations": "all", "privacies": ["public", "protected"]} + } + ], + "deprecation": true, + "encoding": true, + "file-name-casing": { "options": "camel-case" }, + "import-spacing": true, + "increment-decrement": true, + "interface-name": true, + "interface-over-type-literal": true, + "jsdoc-format": { "options": "check-multiline-start" }, + "match-default-export-name": true, + "new-parens": true, + "newline-before-return": true, + "newline-per-chained-call": true, + "no-angle-bracket-type-assertion": true, + "no-boolean-literal-compare": true, + "no-consecutive-blank-lines": true, + "no-parameter-properties": true, + "no-redundant-jsdoc": true, + "no-reference-import": true, + "no-unnecessary-callback-wrapper": true, + "no-unnecessary-initializer": true, + "no-unnecessary-qualifier": true, + "no-unnecessary-type-assertion": true, + "number-literal-format": true, + "object-literal-key-quotes": { "options": "consistent-as-needed" }, + "object-literal-shorthand": true, + "one-line": { + "options": [ + "check-catch", + "check-else", + "check-finally", + "check-open-brace", + "check-whitespace" + ] + }, + "one-variable-per-declaration": true, + "ordered-imports": { + "options": { + "grouped-imports": true, + "import-sources-order": "case-insensitive", + "named-imports-order": "case-insensitive", + "module-source-path": "full" + } + }, + "prefer-function-over-method": true, + "prefer-method-signature": true, + "prefer-object-spread": true, + "prefer-switch": true, + "prefer-template": true, + "prefer-while": true, + "quotemark": { + "options": ["double", "avoid-escape", "avoid-template"] + }, + "return-undefined": true, + "semicolon": { "options": ["always"] }, + "space-before-function-paren": { + "options": { + "anonymous": "never", + "asyncArrow": "always", + "constructor": "never", + "method": "never", + "named": "never" + } + }, + "space-within-parens": { "options": 0 }, + "switch-final-break": true, + "type-literal-delimiter": true, + "unnecessary-bind": true, + "unnecessary-else": true, + "variable-name": { "options": ["ban-keywords", "check-format", "require-const-for-all-caps"] }, + "whitespace": { + "options": [ + "check-branch", + "check-decl", + "check-operator", + "check-module", + "check-separator", + "check-type", + "check-typecast", + "check-preblock", + "check-type-operator", + "check-rest-spread" + ] + } + } +} -- cgit 1.4.1 From a8529de59247a8bf1e9c1591c0db306ccbcf1d49 Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Fri, 2 Jul 2021 08:44:53 +0100 Subject: Changes to strip unused symbols from afl-frida-trace.so and hance remove v7 and its dependency on C++ (#1001) Co-authored-by: Your Name --- frida_mode/GNUmakefile | 11 ++++++-- frida_mode/frida.map | 33 ++++++++++++++++++++++ frida_mode/hook/hook.c | 14 +++++----- frida_mode/many-linux/Dockerfile | 2 +- frida_mode/many-linux/GNUmakefile | 1 + frida_mode/src/js/js_api.c | 59 +++++++++++++++++++++++---------------- frida_mode/src/main.c | 2 +- 7 files changed, 86 insertions(+), 36 deletions(-) create mode 100644 frida_mode/frida.map (limited to 'frida_mode/src/js/js_api.c') diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index f5a96501..d8206d94 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -19,13 +19,14 @@ CFLAGS+=-fPIC \ -g \ -O3 \ -funroll-loops \ + -ffunction-sections \ RT_CFLAGS:=-Wno-unused-parameter \ -Wno-sign-compare \ -Wno-unused-function \ -Wno-unused-result \ -Wno-int-to-pointer-cast \ - -Wno-pointer-sign \ + -Wno-pointer-sign LDFLAGS+=-shared \ -lpthread \ @@ -64,7 +65,10 @@ else ifdef DEBUG RT_CFLAGS:=$(RT_CFLAGS) -Wno-prio-ctor-dtor endif -LDFLAGS+=-z noexecstack +LDFLAGS+= -z noexecstack \ + -Wl,--gc-sections \ + -Wl,--exclude-libs,ALL +LDSCRIPT:=-Wl,--version-script=$(PWD)frida.map endif ifeq "$(shell uname)" "Linux" @@ -164,7 +168,7 @@ $(AFL_COMPILER_RT_OBJ): $(AFL_COMPILER_RT_SRC) $(JS_SRC): $(JS) | $(BUILD_DIR) cd $(JS_DIR) && xxd -i $(JS_NAME) $@ -$(JS_OBJ): $(JS_SRC) +$(JS_OBJ): $(JS_SRC) GNUmakefile $(CC) \ $(CFLAGS) \ -I $(ROOT)include \ @@ -197,6 +201,7 @@ $(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL $(GUM_DEVIT_LIBRARY) \ $(AFL_COMPILER_RT_OBJ) \ $(LDFLAGS) \ + $(LDSCRIPT) \ -o $@ \ cp -v $(FRIDA_TRACE) $(ROOT) diff --git a/frida_mode/frida.map b/frida_mode/frida.map new file mode 100644 index 00000000..cc072dd7 --- /dev/null +++ b/frida_mode/frida.map @@ -0,0 +1,33 @@ +{ + global: + __afl_fuzz_len; + __afl_fuzz_ptr; + __afl_sharedmem_fuzzing; + afl_frida_start; + js_api_add_exclude_range; + js_api_add_include_range; + js_api_done; + js_api_error; + js_api_set_debug_maps; + js_api_set_entrypoint; + js_api_set_instrument_debug_file; + js_api_set_instrument_libraries; + js_api_set_instrument_no_optimize; + js_api_set_instrument_trace; + js_api_set_instrument_trace_unique; + js_api_set_persistent_address; + js_api_set_persistent_count; + js_api_set_persistent_debug; + js_api_set_persistent_hook; + js_api_set_persistent_return; + js_api_set_prefetch_disable; + js_api_set_stalker_callback; + js_api_set_stats_file; + js_api_set_stats_interval; + js_api_set_stats_transitions; + js_api_set_stderr; + js_api_set_stdout; + + local: + *; +}; diff --git a/frida_mode/hook/hook.c b/frida_mode/hook/hook.c index 7d08101f..97f28db7 100644 --- a/frida_mode/hook/hook.c +++ b/frida_mode/hook/hook.c @@ -5,8 +5,8 @@ #if defined(__x86_64__) -void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, - uint32_t input_buf_len) { +__attribute__((visibility("default"))) void afl_persistent_hook( + GumCpuContext *regs, uint8_t *input_buf, uint32_t input_buf_len) { memcpy((void *)regs->rdi, input_buf, input_buf_len); regs->rsi = input_buf_len; @@ -15,8 +15,8 @@ void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, #elif defined(__i386__) -void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, - uint32_t input_buf_len) { +__attribute__((visibility("default"))) void afl_persistent_hook( + GumCpuContext *regs, uint8_t *input_buf, uint32_t input_buf_len) { void **esp = (void **)regs->esp; void * arg1 = esp[0]; @@ -28,8 +28,8 @@ void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, #elif defined(__aarch64__) -void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, - uint32_t input_buf_len) { +__attribute__((visibility("default"))) void afl_persistent_hook( + GumCpuContext *regs, uint8_t *input_buf, uint32_t input_buf_len) { memcpy((void *)regs->x[0], input_buf, input_buf_len); regs->x[1] = input_buf_len; @@ -40,7 +40,7 @@ void afl_persistent_hook(GumCpuContext *regs, uint8_t *input_buf, #pragma error "Unsupported architecture" #endif -int afl_persistent_hook_init(void) { +__attribute__((visibility("default"))) int afl_persistent_hook_init(void) { // 1 for shared memory input (faster), 0 for normal input (you have to use // read(), input_buf will be NULL) diff --git a/frida_mode/many-linux/Dockerfile b/frida_mode/many-linux/Dockerfile index 08c24eae..1d39c356 100644 --- a/frida_mode/many-linux/Dockerfile +++ b/frida_mode/many-linux/Dockerfile @@ -18,7 +18,7 @@ RUN git checkout dev WORKDIR /AFLplusplus/frida_mode ENV CFLAGS="\ -DADDR_NO_RANDOMIZE=0x0040000 \ - -D_POSIX_C_SOURCE=200809L \ -Wno-implicit-function-declaration \ " +ENV CXX=$CC RUN make diff --git a/frida_mode/many-linux/GNUmakefile b/frida_mode/many-linux/GNUmakefile index 2ac44dc2..2860f20c 100644 --- a/frida_mode/many-linux/GNUmakefile +++ b/frida_mode/many-linux/GNUmakefile @@ -15,6 +15,7 @@ $(BUILD_DIR): clean: rm -rf $(BUILD_DIR) + docker images --filter 'dangling=true' -q --no-trunc | xargs -L1 docker rmi --force shell: docker run -ti --rm many-afl-frida /bin/bash diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 91dccab2..58bf9ba3 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -9,142 +9,153 @@ #include "ranges.h" #include "stats.h" #include "util.h" - -void js_api_done() { +__attribute__((visibility("default"))) void js_api_done() { js_done = TRUE; } -void js_api_error(char *msg) { +__attribute__((visibility("default"))) void js_api_error(char *msg) { FATAL("%s", msg); } -void js_api_set_entrypoint(void *address) { +__attribute__((visibility("default"))) void js_api_set_entrypoint( + void *address) { entry_point = GPOINTER_TO_SIZE(address); } -void js_api_set_persistent_address(void *address) { +__attribute__((visibility("default"))) void js_api_set_persistent_address( + void *address) { persistent_start = GPOINTER_TO_SIZE(address); } -void js_api_set_persistent_return(void *address) { +__attribute__((visibility("default"))) void js_api_set_persistent_return( + void *address) { persistent_ret = GPOINTER_TO_SIZE(address); } -void js_api_set_persistent_count(uint64_t count) { +__attribute__((visibility("default"))) void js_api_set_persistent_count( + uint64_t count) { persistent_count = count; } -void js_api_set_persistent_debug() { +__attribute__((visibility("default"))) void js_api_set_persistent_debug() { persistent_debug = TRUE; } -void js_api_set_debug_maps() { +__attribute__((visibility("default"))) void js_api_set_debug_maps() { ranges_debug_maps = TRUE; } -void js_api_add_include_range(void *address, gsize size) { +__attribute__((visibility("default"))) 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) { +__attribute__((visibility("default"))) 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() { +__attribute__((visibility("default"))) void js_api_set_instrument_libraries() { ranges_inst_libs = TRUE; } -void js_api_set_instrument_debug_file(char *path) { +__attribute__((visibility("default"))) void js_api_set_instrument_debug_file( + char *path) { instrument_debug_filename = g_strdup(path); } -void js_api_set_prefetch_disable(void) { +__attribute__((visibility("default"))) void js_api_set_prefetch_disable(void) { prefetch_enable = FALSE; } -void js_api_set_instrument_no_optimize(void) { +__attribute__((visibility("default"))) void js_api_set_instrument_no_optimize( + void) { instrument_optimize = FALSE; } -void js_api_set_instrument_trace(void) { +__attribute__((visibility("default"))) void js_api_set_instrument_trace(void) { instrument_tracing = TRUE; } -void js_api_set_instrument_trace_unique(void) { +__attribute__((visibility("default"))) void js_api_set_instrument_trace_unique( + void) { instrument_unique = TRUE; } -void js_api_set_stdout(char *file) { +__attribute__((visibility("default"))) void js_api_set_stdout(char *file) { output_stdout = g_strdup(file); } -void js_api_set_stderr(char *file) { +__attribute__((visibility("default"))) void js_api_set_stderr(char *file) { output_stderr = g_strdup(file); } -void js_api_set_stats_file(char *file) { +__attribute__((visibility("default"))) void js_api_set_stats_file(char *file) { stats_filename = g_strdup(file); } -void js_api_set_stats_interval(uint64_t interval) { +__attribute__((visibility("default"))) void js_api_set_stats_interval( + uint64_t interval) { stats_interval = interval; } -void js_api_set_stats_transitions() { +__attribute__((visibility("default"))) void js_api_set_stats_transitions() { stats_transitions = TRUE; } -void js_api_set_persistent_hook(void *address) { +__attribute__((visibility("default"))) void js_api_set_persistent_hook( + void *address) { persistent_hook = address; } -void js_api_set_stalker_callback(const js_api_stalker_callback_t callback) { +__attribute__((visibility("default"))) void js_api_set_stalker_callback( + const js_api_stalker_callback_t callback) { js_user_callback = callback; diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 85b0bbf3..91687046 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -163,7 +163,7 @@ static void afl_print_env(void) { } -void afl_frida_start(void) { +__attribute__((visibility("default"))) void afl_frida_start(void) { afl_print_cmdline(); afl_print_env(); -- cgit 1.4.1 From bf9a15541888ac8836a70b4d01c2c9e7bd940051 Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Tue, 6 Jul 2021 08:09:31 +0100 Subject: Support for excluding JIT code (#1006) Co-authored-by: Your Name --- frida_mode/README.md | 3 ++ frida_mode/frida.map | 1 + frida_mode/include/ranges.h | 1 + frida_mode/src/js/api.js | 7 +++++ frida_mode/src/js/js_api.c | 6 ++++ frida_mode/src/ranges.c | 68 +++++++++++++++++++++++++++++++++++++++------ frida_mode/ts/lib/afl.ts | 12 ++++++++ include/envs.h | 1 + 8 files changed, 90 insertions(+), 9 deletions(-) (limited to 'frida_mode/src/js/js_api.c') diff --git a/frida_mode/README.md b/frida_mode/README.md index c85cf3af..024fc140 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -153,6 +153,9 @@ Generated block 0x7ffff75e98e2 *** ``` +* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled +code. Code is considered to be JIT if the executable segment is not backed by a +file. * `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage instrumentation (the default where available). Required to use `AFL_FRIDA_INST_TRACE`. diff --git a/frida_mode/frida.map b/frida_mode/frida.map index cc072dd7..8fc0b174 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -11,6 +11,7 @@ js_api_set_debug_maps; js_api_set_entrypoint; js_api_set_instrument_debug_file; + js_api_set_instrument_jit; js_api_set_instrument_libraries; js_api_set_instrument_no_optimize; js_api_set_instrument_trace; diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h index a667fb76..2eb9b355 100644 --- a/frida_mode/include/ranges.h +++ b/frida_mode/include/ranges.h @@ -5,6 +5,7 @@ extern gboolean ranges_debug_maps; extern gboolean ranges_inst_libs; +extern gboolean ranges_inst_jit; void ranges_config(void); void ranges_init(void); diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index 4cb04704..1d843024 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -99,6 +99,12 @@ class Afl { static setInstrumentEnableTracing() { Afl.jsApiSetInstrumentTrace(); } + /** + * See `AFL_FRIDA_INST_JIT`. + */ + static setInstrumentJit() { + Afl.jsApiSetInstrumentJit(); + } /** * See `AFL_INST_LIBS`. */ @@ -222,6 +228,7 @@ 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.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.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []); diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 58bf9ba3..36471387 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -77,6 +77,12 @@ __attribute__((visibility("default"))) void js_api_add_exclude_range( } +__attribute__((visibility("default"))) void js_api_set_instrument_jit() { + + ranges_inst_jit = TRUE; + +} + __attribute__((visibility("default"))) void js_api_set_instrument_libraries() { ranges_inst_libs = TRUE; diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index 05e18156..5e78fa60 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -19,9 +19,11 @@ typedef struct { gboolean ranges_debug_maps = FALSE; gboolean ranges_inst_libs = FALSE; +gboolean ranges_inst_jit = FALSE; static GArray *module_ranges = NULL; static GArray *libs_ranges = NULL; +static GArray *jit_ranges = NULL; static GArray *include_ranges = NULL; static GArray *exclude_ranges = NULL; static GArray *ranges = NULL; @@ -174,19 +176,27 @@ static gboolean print_ranges_callback(const GumRangeDetails *details, gpointer user_data) { UNUSED_PARAMETER(user_data); + if (details->file == NULL) { - OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER "X", + OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER + "X %c%c%c", details->range->base_address, - details->range->base_address + details->range->size); + details->range->base_address + details->range->size, + details->protection & GUM_PAGE_READ ? 'R' : '-', + details->protection & GUM_PAGE_WRITE ? 'W' : '-', + details->protection & GUM_PAGE_EXECUTE ? 'X' : '-'); } else { OKF("MAP - 0x%016" G_GINT64_MODIFIER "x - 0x%016" G_GINT64_MODIFIER - "X %s(0x%016" G_GINT64_MODIFIER "x)", + "X %c%c%c %s(0x%016" G_GINT64_MODIFIER "x)", details->range->base_address, details->range->base_address + details->range->size, - details->file->path, details->file->offset); + details->protection & GUM_PAGE_READ ? 'R' : '-', + details->protection & GUM_PAGE_WRITE ? 'W' : '-', + details->protection & GUM_PAGE_EXECUTE ? 'X' : '-', details->file->path, + details->file->offset); } @@ -331,6 +341,39 @@ static GArray *collect_libs_ranges(void) { } +static gboolean collect_jit_ranges_callback(const GumRangeDetails *details, + gpointer user_data) { + + GArray *ranges = (GArray *)user_data; + + /* If the executable code isn't backed by a file, it's probably JIT */ + if (details->file == NULL) { + + GumMemoryRange range = *details->range; + g_array_append_val(ranges, range); + + } + + return TRUE; + +} + +static GArray *collect_jit_ranges(void) { + + GArray *result; + result = g_array_new(false, false, sizeof(GumMemoryRange)); + if (!ranges_inst_jit) { + + gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, collect_jit_ranges_callback, + result); + + } + + print_ranges("JIT", result); + return result; + +} + static gboolean intersect_range(GumMemoryRange *rr, GumMemoryRange *ra, GumMemoryRange *rb) { @@ -510,6 +553,7 @@ void ranges_config(void) { if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { ranges_debug_maps = TRUE; } if (getenv("AFL_INST_LIBS") != NULL) { ranges_inst_libs = TRUE; } + if (getenv("AFL_FRIDA_INST_JIT") != NULL) { ranges_inst_jit = TRUE; } if (ranges_debug_maps) { @@ -530,7 +574,9 @@ void ranges_init(void) { GArray * step2; GArray * step3; GArray * step4; + GArray * step5; + OKF("Ranges - Instrument jit [%c]", ranges_inst_jit ? 'X' : ' '); OKF("Ranges - Instrument libraries [%c]", ranges_inst_libs ? 'X' : ' '); print_ranges("AFL_FRIDA_INST_RANGES", include_ranges); @@ -538,6 +584,7 @@ void ranges_init(void) { module_ranges = collect_module_ranges(); libs_ranges = collect_libs_ranges(); + jit_ranges = collect_jit_ranges(); /* If include ranges is empty, then assume everything is included */ if (include_ranges->len == 0) { @@ -560,17 +607,20 @@ void ranges_init(void) { step3 = subtract_ranges(step2, exclude_ranges); print_ranges("step3", step3); + step4 = subtract_ranges(step3, jit_ranges); + print_ranges("step4", step4); + /* - * After step3, we have the total ranges to be instrumented, we now subtract + * After step4, we have the total ranges to be instrumented, we now subtract * that from the original ranges of the modules to configure stalker. */ + step5 = subtract_ranges(module_ranges, step4); + print_ranges("step5", step5); - step4 = subtract_ranges(module_ranges, step3); - print_ranges("step4", step4); - - ranges = merge_ranges(step4); + ranges = merge_ranges(step5); print_ranges("final", ranges); + g_array_free(step5, TRUE); g_array_free(step4, TRUE); g_array_free(step3, TRUE); g_array_free(step2, TRUE); diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index 93368dac..67e21beb 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/frida_mode/ts/lib/afl.ts @@ -119,6 +119,13 @@ class Afl { Afl.jsApiSetInstrumentTrace(); } + /** + * See `AFL_FRIDA_INST_JIT`. + */ + public static setInstrumentJit(): void { + Afl.jsApiSetInstrumentJit(); + } + /** * See `AFL_INST_LIBS`. */ @@ -273,6 +280,11 @@ class Afl { "void", ["pointer"]); + private static readonly jsApiSetInstrumentJit = Afl.jsApiGetFunction( + "js_api_set_instrument_jit", + "void", + []); + private static readonly jsApiSetInstrumentLibraries = Afl.jsApiGetFunction( "js_api_set_instrument_libraries", "void", diff --git a/include/envs.h b/include/envs.h index f89e8e62..4bab54ce 100644 --- a/include/envs.h +++ b/include/envs.h @@ -56,6 +56,7 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_DEBUG_MAPS", "AFL_FRIDA_EXCLUDE_RANGES", "AFL_FRIDA_INST_DEBUG_FILE", + "AFL_FRIDA_INST_JIT", "AFL_FRIDA_INST_NO_OPTIMIZE", "AFL_FRIDA_INST_NO_PREFETCH", "AFL_FRIDA_INST_RANGES", -- cgit 1.4.1 From 2a433f90c456b19cf9aa39384540f618c6eeb1a8 Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Tue, 6 Jul 2021 08:09:43 +0100 Subject: Improved OSX support (#1005) Co-authored-by: Your Name --- frida_mode/Scripting.md | 13 ++++++++ frida_mode/src/js/js_api.c | 24 +++++++++++++++ frida_mode/test/deferred/GNUmakefile | 14 +++++---- frida_mode/test/deferred/testinstr.c | 1 - frida_mode/test/entry_point/GNUmakefile | 14 +++++---- frida_mode/test/jpeg/GNUmakefile | 12 ++++---- frida_mode/test/jpeg/get_symbol_addr.py | 36 ----------------------- frida_mode/test/js/GNUmakefile | 6 ++++ frida_mode/test/js/entry.js | 3 +- frida_mode/test/libpcap/GNUmakefile | 12 ++++---- frida_mode/test/libpcap/get_symbol_addr.py | 36 ----------------------- frida_mode/test/persistent_ret/GNUmakefile | 25 +++++++++++----- frida_mode/test/persistent_ret/get_symbol_addr.py | 36 ----------------------- frida_mode/test/png/GNUmakefile | 2 +- frida_mode/test/png/persistent/GNUmakefile | 10 ++++--- frida_mode/test/png/persistent/get_symbol_addr.py | 36 ----------------------- frida_mode/test/png/persistent/hook/GNUmakefile | 17 ++++++++--- frida_mode/test/proj4/GNUmakefile | 10 ++++--- frida_mode/test/proj4/get_symbol_addr.py | 36 ----------------------- frida_mode/test/re2/GNUmakefile | 10 ++++--- frida_mode/test/re2/get_symbol_addr.py | 36 ----------------------- frida_mode/test/unstable/GNUmakefile | 10 ++++--- frida_mode/test/unstable/get_symbol_addr.py | 36 ----------------------- frida_mode/util/get_symbol_addr.sh | 32 ++++++++++++++++++++ 24 files changed, 165 insertions(+), 302 deletions(-) delete mode 100755 frida_mode/test/jpeg/get_symbol_addr.py delete mode 100755 frida_mode/test/libpcap/get_symbol_addr.py delete mode 100755 frida_mode/test/persistent_ret/get_symbol_addr.py delete mode 100755 frida_mode/test/png/persistent/get_symbol_addr.py delete mode 100755 frida_mode/test/proj4/get_symbol_addr.py delete mode 100755 frida_mode/test/re2/get_symbol_addr.py delete mode 100755 frida_mode/test/unstable/get_symbol_addr.py create mode 100755 frida_mode/util/get_symbol_addr.sh (limited to 'frida_mode/src/js/js_api.c') diff --git a/frida_mode/Scripting.md b/frida_mode/Scripting.md index 4c6fe6b2..5467db99 100644 --- a/frida_mode/Scripting.md +++ b/frida_mode/Scripting.md @@ -605,6 +605,19 @@ difficult to diagnose. The code above only prints the instructions when running in the parent process (the one provided by `Process.id` when the JS script is executed). +# OSX +Note that the JavaScript debug symbol api for OSX makes use of the +`CoreSymbolication` APIs and as such the `CoreFoundation` module must be loaded +into the target to make use of it. This can be done by setting: + +``` +AFL_PRELOAD=/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation +``` + +It should be noted that `CoreSymbolication` API may take a while to initialize +and build its caches. For this reason, it may be nescessary to also increase the +value of the `-t` flag passed to `afl-fuzz`. + # API ```js class Afl { diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 36471387..fd8128c5 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -24,6 +24,12 @@ __attribute__((visibility("default"))) void js_api_error(char *msg) { __attribute__((visibility("default"))) void js_api_set_entrypoint( void *address) { + if (address == NULL) { + + js_api_error("js_api_set_entrypoint called with NULL"); + + } + entry_point = GPOINTER_TO_SIZE(address); } @@ -31,6 +37,12 @@ __attribute__((visibility("default"))) void js_api_set_entrypoint( __attribute__((visibility("default"))) void js_api_set_persistent_address( void *address) { + if (address == NULL) { + + js_api_error("js_api_set_persistent_address called with NULL"); + + } + persistent_start = GPOINTER_TO_SIZE(address); } @@ -38,6 +50,12 @@ __attribute__((visibility("default"))) void js_api_set_persistent_address( __attribute__((visibility("default"))) void js_api_set_persistent_return( void *address) { + if (address == NULL) { + + js_api_error("js_api_set_persistent_return called with NULL"); + + } + persistent_ret = GPOINTER_TO_SIZE(address); } @@ -156,6 +174,12 @@ __attribute__((visibility("default"))) void js_api_set_stats_transitions() { __attribute__((visibility("default"))) void js_api_set_persistent_hook( void *address) { + if (address == NULL) { + + js_api_error("js_api_set_persistent_hook called with NULL"); + + } + persistent_hook = address; } diff --git a/frida_mode/test/deferred/GNUmakefile b/frida_mode/test/deferred/GNUmakefile index ae580e3f..f7520051 100644 --- a/frida_mode/test/deferred/GNUmakefile +++ b/frida_mode/test/deferred/GNUmakefile @@ -10,7 +10,7 @@ TESTINSTSRC:=$(PWD)testinstr.c QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out -GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh ifndef ARCH @@ -24,17 +24,21 @@ ifeq "$(ARCH)" "i686" endif endif +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-Wl,-no_pie +endif + ARCH=$(shell uname -m) ifeq "$(ARCH)" "aarch64" - AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000) + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) run 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000) + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) run 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000) + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) run 0x56555000) endif .PHONY: all clean frida @@ -55,7 +59,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) echo -n "000" > $@ $(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + $(CC) $(CFLAGS) $(LDFLAGS) $(TEST_BIN_LDFLAGS) -o $@ $< clean: rm -rf $(BUILD_DIR) diff --git a/frida_mode/test/deferred/testinstr.c b/frida_mode/test/deferred/testinstr.c index 8b3688d7..c7a05ac5 100644 --- a/frida_mode/test/deferred/testinstr.c +++ b/frida_mode/test/deferred/testinstr.c @@ -51,7 +51,6 @@ int run(char *file) { fd = open(file, O_RDONLY); if (fd < 0) { - perror("open"); break; diff --git a/frida_mode/test/entry_point/GNUmakefile b/frida_mode/test/entry_point/GNUmakefile index c99bcecb..5453c1ad 100644 --- a/frida_mode/test/entry_point/GNUmakefile +++ b/frida_mode/test/entry_point/GNUmakefile @@ -10,7 +10,7 @@ TESTINSTSRC:=$(PWD)testinstr.c QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out -GET_SYMBOL_ADDR:=$(ROOT)frida_mode/test/png/persistent/get_symbol_addr.py +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh ifndef ARCH @@ -24,17 +24,21 @@ ifeq "$(ARCH)" "i686" endif endif +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-Wl,-no_pie +endif + ARCH=$(shell uname -m) ifeq "$(ARCH)" "aarch64" - AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000aaaaaaaaa000) + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) run 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x0000555555554000) + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) run 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000) + AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) run 0x56555000) endif .PHONY: all clean qemu frida @@ -55,7 +59,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) echo -n "000" > $@ $(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + $(CC) $(CFLAGS) $(LDFLAGS) $(TEST_BIN_LDFLAGS) -o $@ $< clean: rm -rf $(BUILD_DIR) diff --git a/frida_mode/test/jpeg/GNUmakefile b/frida_mode/test/jpeg/GNUmakefile index e3a8f321..68469782 100644 --- a/frida_mode/test/jpeg/GNUmakefile +++ b/frida_mode/test/jpeg/GNUmakefile @@ -26,7 +26,7 @@ LDFLAGS += -lpthread TEST_BIN:=$(BUILD_DIR)test ifeq "$(shell uname)" "Darwin" -TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup -Wl,-no_pie endif TEST_DATA_DIR:=$(BUILD_DIR)in/ @@ -46,16 +46,18 @@ ifeq "$(ARCH)" "i686" endif endif +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + ifeq "$(ARCH)" "aarch64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x56555000) endif .PHONY: all clean frida hook @@ -77,7 +79,7 @@ $(HARNESS_FILE): | $(HARNESS_BUILD_DIR) wget -O $@ $(HARNESS_URL) $(HARNESS_OBJ): $(HARNESS_FILE) - $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ -c $< + $(CC) $(CXXFLAGS) $(LDFLAGS) $(TEST_BIN_LDFLAGS) -o $@ -c $< ######### JPEGTEST ######## diff --git a/frida_mode/test/jpeg/get_symbol_addr.py b/frida_mode/test/jpeg/get_symbol_addr.py deleted file mode 100755 index 1c46e010..00000000 --- a/frida_mode/test/jpeg/get_symbol_addr.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -import argparse -from elftools.elf.elffile import ELFFile - -def process_file(file, symbol, base): - with open(file, 'rb') as f: - elf = ELFFile(f) - symtab = elf.get_section_by_name('.symtab') - mains = symtab.get_symbol_by_name(symbol) - if len(mains) != 1: - print ("Failed to find main") - return 1 - - main_addr = mains[0]['st_value'] - main = base + main_addr - print ("0x%016x" % main) - return 0 - -def hex_value(x): - return int(x, 16) - -def main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('-f', '--file', dest='file', type=str, - help='elf file name', required=True) - parser.add_argument('-s', '--symbol', dest='symbol', type=str, - help='symbol name', required=True) - parser.add_argument('-b', '--base', dest='base', type=hex_value, - help='elf base address', required=True) - - args = parser.parse_args() - return process_file (args.file, args.symbol, args.base) - -if __name__ == "__main__": - ret = main() - exit(ret) diff --git a/frida_mode/test/js/GNUmakefile b/frida_mode/test/js/GNUmakefile index af40c1c4..766862a5 100644 --- a/frida_mode/test/js/GNUmakefile +++ b/frida_mode/test/js/GNUmakefile @@ -13,6 +13,10 @@ TESTINSTSRC2:=$(PWD)test2.c QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out +ifeq "$(shell uname)" "Darwin" +AFL_PRELOAD=/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation +endif + .PHONY: all 32 clean qemu frida all: $(TESTINSTBIN) $(TESTINSTBIN2) @@ -40,12 +44,14 @@ clean: rm -rf $(BUILD_DIR) frida_js_entry: $(TESTINSTBIN) $(TEST_DATA_FILE) + AFL_PRELOAD=$(AFL_PRELOAD) \ AFL_FRIDA_JS_SCRIPT=entry.js \ $(ROOT)afl-fuzz \ -D \ -O \ -i $(TEST_DATA_DIR) \ -o $(FRIDA_OUT) \ + -t 10000+ \ -- \ $(TESTINSTBIN) @@ diff --git a/frida_mode/test/js/entry.js b/frida_mode/test/js/entry.js index f10ef2d1..0b233ddb 100644 --- a/frida_mode/test/js/entry.js +++ b/frida_mode/test/js/entry.js @@ -9,8 +9,9 @@ new ModuleMap().values().forEach(m => { Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`); }); +Afl.print('Searching...\n'); const entry_point = DebugSymbol.fromName('run'); -Afl.print(`entry_point: ${entry_point.address}`); +Afl.print(`entry_point: ${entry_point}`); Afl.setEntryPoint(entry_point.address); diff --git a/frida_mode/test/libpcap/GNUmakefile b/frida_mode/test/libpcap/GNUmakefile index 8a10be07..4d0bc4f1 100644 --- a/frida_mode/test/libpcap/GNUmakefile +++ b/frida_mode/test/libpcap/GNUmakefile @@ -34,7 +34,7 @@ LDFLAGS += -lpthread TEST_BIN:=$(BUILD_DIR)test ifeq "$(shell uname)" "Darwin" -TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup -Wl,-no_pie endif AFLPP_DRIVER_DUMMY_INPUT:=$(TCPDUMP_TESTS_DIR)in @@ -54,18 +54,20 @@ ifeq "$(ARCH)" "i686" endif endif -AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x4000000000) ifeq "$(ARCH)" "aarch64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x56555000) endif .PHONY: all clean qemu frida hook diff --git a/frida_mode/test/libpcap/get_symbol_addr.py b/frida_mode/test/libpcap/get_symbol_addr.py deleted file mode 100755 index 1c46e010..00000000 --- a/frida_mode/test/libpcap/get_symbol_addr.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -import argparse -from elftools.elf.elffile import ELFFile - -def process_file(file, symbol, base): - with open(file, 'rb') as f: - elf = ELFFile(f) - symtab = elf.get_section_by_name('.symtab') - mains = symtab.get_symbol_by_name(symbol) - if len(mains) != 1: - print ("Failed to find main") - return 1 - - main_addr = mains[0]['st_value'] - main = base + main_addr - print ("0x%016x" % main) - return 0 - -def hex_value(x): - return int(x, 16) - -def main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('-f', '--file', dest='file', type=str, - help='elf file name', required=True) - parser.add_argument('-s', '--symbol', dest='symbol', type=str, - help='symbol name', required=True) - parser.add_argument('-b', '--base', dest='base', type=hex_value, - help='elf base address', required=True) - - args = parser.parse_args() - return process_file (args.file, args.symbol, args.base) - -if __name__ == "__main__": - ret = main() - exit(ret) diff --git a/frida_mode/test/persistent_ret/GNUmakefile b/frida_mode/test/persistent_ret/GNUmakefile index f11269e3..adcacf5a 100644 --- a/frida_mode/test/persistent_ret/GNUmakefile +++ b/frida_mode/test/persistent_ret/GNUmakefile @@ -22,20 +22,30 @@ ifeq "$(ARCH)" "i686" endif endif +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-Wl,-no_pie +endif + ARCH=$(shell uname -m) ifeq "$(ARCH)" "aarch64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x0000aaaaaaaaa000) - AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) main 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_RET=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) slow 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x0000555555554000) - AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) main 0x0000555555554000) + AFL_FRIDA_PERSISTENT_RET=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) slow 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s main -b 0x56555000) - AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x56555000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) main 0x56555000) + AFL_FRIDA_PERSISTENT_RET=$(shell $(GET_SYMBOL_ADDR) $(TESTINSTBIN) slow 0x56555000) +endif + +ifeq "$(shell uname)" "Darwin" +AFL_PRELOAD=/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation endif .PHONY: all 32 clean qemu frida @@ -56,7 +66,7 @@ $(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) echo -n "000" > $@ $(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + $(CC) $(CFLAGS) $(LDFLAGS) $(TEST_BIN_LDFLAGS) -o $@ $< clean: rm -rf $(BUILD_DIR) @@ -83,6 +93,7 @@ frida_ret: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) $(TESTINSTBIN) @@ frida_js: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_PRELOAD=$(AFL_PRELOAD) \ AFL_FRIDA_JS_SCRIPT=test.js \ $(ROOT)afl-fuzz \ -D \ diff --git a/frida_mode/test/persistent_ret/get_symbol_addr.py b/frida_mode/test/persistent_ret/get_symbol_addr.py deleted file mode 100755 index 1c46e010..00000000 --- a/frida_mode/test/persistent_ret/get_symbol_addr.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -import argparse -from elftools.elf.elffile import ELFFile - -def process_file(file, symbol, base): - with open(file, 'rb') as f: - elf = ELFFile(f) - symtab = elf.get_section_by_name('.symtab') - mains = symtab.get_symbol_by_name(symbol) - if len(mains) != 1: - print ("Failed to find main") - return 1 - - main_addr = mains[0]['st_value'] - main = base + main_addr - print ("0x%016x" % main) - return 0 - -def hex_value(x): - return int(x, 16) - -def main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('-f', '--file', dest='file', type=str, - help='elf file name', required=True) - parser.add_argument('-s', '--symbol', dest='symbol', type=str, - help='symbol name', required=True) - parser.add_argument('-b', '--base', dest='base', type=hex_value, - help='elf base address', required=True) - - args = parser.parse_args() - return process_file (args.file, args.symbol, args.base) - -if __name__ == "__main__": - ret = main() - exit(ret) diff --git a/frida_mode/test/png/GNUmakefile b/frida_mode/test/png/GNUmakefile index e05bade2..fdb2c318 100644 --- a/frida_mode/test/png/GNUmakefile +++ b/frida_mode/test/png/GNUmakefile @@ -22,7 +22,7 @@ PNGTEST_URL:="https://raw.githubusercontent.com/google/fuzzbench/master/benchmar TEST_BIN:=$(BUILD_DIR)test ifeq "$(shell uname)" "Darwin" -TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup -Wl,-no_pie endif TEST_DATA_DIR:=$(LIBPNG_DIR)contrib/pngsuite/ diff --git a/frida_mode/test/png/persistent/GNUmakefile b/frida_mode/test/png/persistent/GNUmakefile index 5af64822..c1ad86e5 100644 --- a/frida_mode/test/png/persistent/GNUmakefile +++ b/frida_mode/test/png/persistent/GNUmakefile @@ -21,18 +21,20 @@ ifeq "$(ARCH)" "i686" endif endif -AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x4000000000) +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) main 0x4000000000) ifeq "$(ARCH)" "arm64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) main 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) main 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s main -b 0x56555000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) main 0x56555000) endif .PHONY: all 32 clean qemu qemu_entry frida frida_entry diff --git a/frida_mode/test/png/persistent/get_symbol_addr.py b/frida_mode/test/png/persistent/get_symbol_addr.py deleted file mode 100755 index 1c46e010..00000000 --- a/frida_mode/test/png/persistent/get_symbol_addr.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -import argparse -from elftools.elf.elffile import ELFFile - -def process_file(file, symbol, base): - with open(file, 'rb') as f: - elf = ELFFile(f) - symtab = elf.get_section_by_name('.symtab') - mains = symtab.get_symbol_by_name(symbol) - if len(mains) != 1: - print ("Failed to find main") - return 1 - - main_addr = mains[0]['st_value'] - main = base + main_addr - print ("0x%016x" % main) - return 0 - -def hex_value(x): - return int(x, 16) - -def main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('-f', '--file', dest='file', type=str, - help='elf file name', required=True) - parser.add_argument('-s', '--symbol', dest='symbol', type=str, - help='symbol name', required=True) - parser.add_argument('-b', '--base', dest='base', type=hex_value, - help='elf base address', required=True) - - args = parser.parse_args() - return process_file (args.file, args.symbol, args.base) - -if __name__ == "__main__": - ret = main() - exit(ret) diff --git a/frida_mode/test/png/persistent/hook/GNUmakefile b/frida_mode/test/png/persistent/hook/GNUmakefile index 0ff9fe86..8a1a9a60 100644 --- a/frida_mode/test/png/persistent/hook/GNUmakefile +++ b/frida_mode/test/png/persistent/hook/GNUmakefile @@ -31,18 +31,24 @@ ifeq "$(ARCH)" "i686" endif endif -AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x4000000000) ifeq "$(ARCH)" "arm64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)../get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x56555000) +endif + +ifeq "$(shell uname)" "Darwin" +AFL_PRELOAD=/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation endif .PHONY: all 32 clean format qemu qemu_entry frida frida_entry debug @@ -121,6 +127,7 @@ frida_entry: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) frida_js_load: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_PRELOAD=$(AFL_PRELOAD) \ AFL_FRIDA_JS_SCRIPT=load.js \ $(ROOT)afl-fuzz \ -D \ @@ -128,10 +135,12 @@ frida_js_load: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DI -O \ -i $(TEST_DATA_DIR) \ -o $(FRIDA_OUT) \ + -t 10000+ \ -- \ $(TEST_BIN) $(AFLPP_DRIVER_DUMMY_INPUT) frida_js_cmodule: $(AFLPP_DRIVER_DUMMY_INPUT) $(AFLPP_DRIVER_HOOK_OBJ) | $(BUILD_DIR) + AFL_PRELOAD=$(AFL_PRELOAD) \ AFL_FRIDA_JS_SCRIPT=cmodule.js \ $(ROOT)afl-fuzz \ -D \ diff --git a/frida_mode/test/proj4/GNUmakefile b/frida_mode/test/proj4/GNUmakefile index e324a5d0..6ce03fd3 100644 --- a/frida_mode/test/proj4/GNUmakefile +++ b/frida_mode/test/proj4/GNUmakefile @@ -26,7 +26,7 @@ LDFLAGS += -lpthread TEST_BIN:=$(BUILD_DIR)test ifeq "$(shell uname)" "Darwin" -TEST_BIN_LDFLAGS:=-undefined dynamic_lookup +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup -Wl,-no_pie endif TEST_DATA_DIR:=$(BUILD_DIR)in/ @@ -46,16 +46,18 @@ ifeq "$(ARCH)" "i686" endif endif +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + ifeq "$(ARCH)" "aarch64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x56555000) endif .PHONY: all clean frida hook diff --git a/frida_mode/test/proj4/get_symbol_addr.py b/frida_mode/test/proj4/get_symbol_addr.py deleted file mode 100755 index 1c46e010..00000000 --- a/frida_mode/test/proj4/get_symbol_addr.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -import argparse -from elftools.elf.elffile import ELFFile - -def process_file(file, symbol, base): - with open(file, 'rb') as f: - elf = ELFFile(f) - symtab = elf.get_section_by_name('.symtab') - mains = symtab.get_symbol_by_name(symbol) - if len(mains) != 1: - print ("Failed to find main") - return 1 - - main_addr = mains[0]['st_value'] - main = base + main_addr - print ("0x%016x" % main) - return 0 - -def hex_value(x): - return int(x, 16) - -def main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('-f', '--file', dest='file', type=str, - help='elf file name', required=True) - parser.add_argument('-s', '--symbol', dest='symbol', type=str, - help='symbol name', required=True) - parser.add_argument('-b', '--base', dest='base', type=hex_value, - help='elf base address', required=True) - - args = parser.parse_args() - return process_file (args.file, args.symbol, args.base) - -if __name__ == "__main__": - ret = main() - exit(ret) diff --git a/frida_mode/test/re2/GNUmakefile b/frida_mode/test/re2/GNUmakefile index e1c5347d..ab986190 100644 --- a/frida_mode/test/re2/GNUmakefile +++ b/frida_mode/test/re2/GNUmakefile @@ -46,18 +46,20 @@ ifeq "$(ARCH)" "i686" endif endif -AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x4000000000) +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x4000000000) ifeq "$(ARCH)" "aarch64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(TEST_BIN) -s LLVMFuzzerTestOneInput -b 0x56555000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x56555000) endif .PHONY: all clean qemu frida hook diff --git a/frida_mode/test/re2/get_symbol_addr.py b/frida_mode/test/re2/get_symbol_addr.py deleted file mode 100755 index 1c46e010..00000000 --- a/frida_mode/test/re2/get_symbol_addr.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -import argparse -from elftools.elf.elffile import ELFFile - -def process_file(file, symbol, base): - with open(file, 'rb') as f: - elf = ELFFile(f) - symtab = elf.get_section_by_name('.symtab') - mains = symtab.get_symbol_by_name(symbol) - if len(mains) != 1: - print ("Failed to find main") - return 1 - - main_addr = mains[0]['st_value'] - main = base + main_addr - print ("0x%016x" % main) - return 0 - -def hex_value(x): - return int(x, 16) - -def main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('-f', '--file', dest='file', type=str, - help='elf file name', required=True) - parser.add_argument('-s', '--symbol', dest='symbol', type=str, - help='symbol name', required=True) - parser.add_argument('-b', '--base', dest='base', type=hex_value, - help='elf base address', required=True) - - args = parser.parse_args() - return process_file (args.file, args.symbol, args.base) - -if __name__ == "__main__": - ret = main() - exit(ret) diff --git a/frida_mode/test/unstable/GNUmakefile b/frida_mode/test/unstable/GNUmakefile index fed417a3..938d7c17 100644 --- a/frida_mode/test/unstable/GNUmakefile +++ b/frida_mode/test/unstable/GNUmakefile @@ -22,18 +22,20 @@ ifeq "$(ARCH)" "i686" endif endif -AFL_QEMU_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(UNSTABLE_BIN) -s run_test -b 0x4000000000) +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + +AFL_QEMU_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(UNSTABLE_BIN) run_test 0x4000000000) ifeq "$(ARCH)" "aarch64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(UNSTABLE_BIN) -s run_test -b 0x0000aaaaaaaaa000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(UNSTABLE_BIN) run_test 0x0000aaaaaaaaa000) endif ifeq "$(ARCH)" "x86_64" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(UNSTABLE_BIN) -s run_test -b 0x0000555555554000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(UNSTABLE_BIN) run_test 0x0000555555554000) endif ifeq "$(ARCH)" "x86" - AFL_FRIDA_PERSISTENT_ADDR=$(shell $(PWD)get_symbol_addr.py -f $(UNSTABLE_BIN) -s run_test -b 0x56555000) + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(UNSTABLE_BIN) run_test 0x56555000) endif .PHONY: all 32 clean qemu frida diff --git a/frida_mode/test/unstable/get_symbol_addr.py b/frida_mode/test/unstable/get_symbol_addr.py deleted file mode 100755 index 1c46e010..00000000 --- a/frida_mode/test/unstable/get_symbol_addr.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python3 -import argparse -from elftools.elf.elffile import ELFFile - -def process_file(file, symbol, base): - with open(file, 'rb') as f: - elf = ELFFile(f) - symtab = elf.get_section_by_name('.symtab') - mains = symtab.get_symbol_by_name(symbol) - if len(mains) != 1: - print ("Failed to find main") - return 1 - - main_addr = mains[0]['st_value'] - main = base + main_addr - print ("0x%016x" % main) - return 0 - -def hex_value(x): - return int(x, 16) - -def main(): - parser = argparse.ArgumentParser(description='Process some integers.') - parser.add_argument('-f', '--file', dest='file', type=str, - help='elf file name', required=True) - parser.add_argument('-s', '--symbol', dest='symbol', type=str, - help='symbol name', required=True) - parser.add_argument('-b', '--base', dest='base', type=hex_value, - help='elf base address', required=True) - - args = parser.parse_args() - return process_file (args.file, args.symbol, args.base) - -if __name__ == "__main__": - ret = main() - exit(ret) diff --git a/frida_mode/util/get_symbol_addr.sh b/frida_mode/util/get_symbol_addr.sh new file mode 100755 index 00000000..7f9b7d22 --- /dev/null +++ b/frida_mode/util/get_symbol_addr.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# set -x +target="$1" +symbol="$2" +base="$3" + +test -z "$target" -o -z "$symbol" -o '!' -e "$target" && exit 0 + +test $(uname -s) = "Darwin" && symbol=_"$symbol" + +file "$target" | grep -q executable && { + nm "$target" | grep -i "T $symbol" | awk '{print"0x"$1}' + exit 0 +} + +hex_base=$(echo "$3" | awk '{sub("^0x","");print $0}') +nm "$target" | grep -i "T $symbol" | awk '{print$1}' | tr a-f A-F | \ + xargs echo "ibase=16;obase=10;$hex_base + " | bc | tr A-F a-f | awk '{print "0x"$0}' +exit 0 -- cgit 1.4.1 From 9e8afcc6156fbcc7b0ed41cde1a5873989b65063 Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Thu, 15 Jul 2021 19:32:44 +0100 Subject: Support for setting a fixed seed for the hash function (#1026) Co-authored-by: Your Name --- frida_mode/README.md | 3 +++ frida_mode/frida.map | 1 + frida_mode/include/instrument.h | 3 +++ frida_mode/src/instrument/instrument.c | 38 ++++++++++++++++++++++++++-------- frida_mode/src/js/api.js | 7 +++++++ frida_mode/src/js/js.c | 11 +++------- frida_mode/src/js/js_api.c | 8 +++++++ frida_mode/ts/lib/afl.ts | 12 +++++++++++ include/envs.h | 1 + 9 files changed, 67 insertions(+), 17 deletions(-) (limited to 'frida_mode/src/js/js_api.c') diff --git a/frida_mode/README.md b/frida_mode/README.md index 6cbb4c4c..3009e171 100644 --- a/frida_mode/README.md +++ b/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 diff --git a/frida_mode/frida.map b/frida_mode/frida.map index 8fc0b174..7223d50e 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -14,6 +14,7 @@ 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; diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index 695b46af..29f14da9 100644 --- a/frida_mode/include/instrument.h +++ b/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; diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index e1dabf92..67aafa5a 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/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) { } - /* - * 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. - */ - instrument_hash_seed = - g_get_monotonic_time() ^ (((guint64)getpid()) << 32) ^ syscall(SYS_gettid); + 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. + */ + 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); diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index 1d843024..b8f2d39a 100644 --- a/frida_mode/src/js/api.js +++ b/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"]); diff --git a/frida_mode/src/js/js.c b/frida_mode/src/js/js.c index 86ae6d29..e3cd4933 100644 --- a/frida_mode/src/js/js.c +++ b/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); } + diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index fd8128c5..930a6dc0 100644 --- a/frida_mode/src/js/js_api.c +++ b/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; diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index 67e21beb..6326c099 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/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", diff --git a/include/envs.h b/include/envs.h index 4bab54ce..26cc250f 100644 --- a/include/envs.h +++ b/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", -- cgit 1.4.1