diff options
Diffstat (limited to 'frida_mode')
37 files changed, 1033 insertions, 252 deletions
diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index c0abe14c..52439979 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -103,7 +103,7 @@ ifndef OS $(error "Operating system unsupported") endif -GUM_DEVKIT_VERSION=15.1.10 +GUM_DEVKIT_VERSION=15.1.11 GUM_DEVKIT_FILENAME=frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz GUM_DEVKIT_URL="https://github.com/frida/frida/releases/download/$(GUM_DEVKIT_VERSION)/$(GUM_DEVKIT_FILENAME)" diff --git a/frida_mode/README.md b/frida_mode/README.md index 8211224d..a75324d5 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -215,6 +215,11 @@ gdb \ ``` * `AFL_FRIDA_SECCOMP_FILE` - Write a log of any syscalls made by the target to the specified file. +* `AFL_FRIDA_STALKER_ADJACENT_BLOCKS` - Configure the number of adjacent blocks + to fetch when generating instrumented code. By fetching blocks in the same + order they appear in the original program, rather than the order of execution + should help reduce locallity and adjacency. This includes allowing us to vector + between adjancent blocks using a NOP slide rather than an immediate branch. * `AFL_FRIDA_STALKER_IC_ENTRIES` - Configure the number of inline cache entries stored along-side branch instructions which provide a cache to avoid having to call back into FRIDA to find the next block. Default is 32. diff --git a/frida_mode/Scripting.md b/frida_mode/Scripting.md index 691b03d1..2ee0c858 100644 --- a/frida_mode/Scripting.md +++ b/frida_mode/Scripting.md @@ -246,7 +246,7 @@ 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: -``` +```js const slow = DebugSymbol.fromName('slow').address; Afl.print(`slow: ${slow}`); @@ -281,13 +281,90 @@ Afl.done(); 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. -**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. +## Replacing LLVMFuzzerTestOneInput +The function `LLVMFuzzerTestOneInput` can be replaced just like any other. Also +any replaced function can also call itself. In the example below, we replace +`LLVMFuzzerTestOneInput` with `My_LLVMFuzzerTestOneInput` which ignores the +parameters `buf` and `len` and then calls the original `LLVMFuzzerTestOneInput` +with the paramaters `__afl_fuzz_ptr` and `__afl_fuzz_len`. This allows us to +carry out in-memory fuzzing without the need for any hook function. It should be +noted that the replacement function and the original can *NOT* share the same +name, since otherwise the `C` code in the `CModule` will not compile due to a +symbol name collision. + +```js +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 My_LLVMFuzzerTestOneInput(char *buf, int len) { + + LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len); + + } + `, + { + LLVMFuzzerTestOneInput: LLVMFuzzerTestOneInput, + __afl_fuzz_ptr: Afl.getAflFuzzPtr(), + __afl_fuzz_len: Afl.getAflFuzzLen() + }); + +Afl.setEntryPoint(cm.My_LLVMFuzzerTestOneInput); +Afl.setPersistentAddress(cm.My_LLVMFuzzerTestOneInput); +Afl.setInMemoryFuzzing(); +Interceptor.replace(LLVMFuzzerTestOneInput, cm.My_LLVMFuzzerTestOneInput); +``` + +## Hooking `main` +Lastly, it should be noted that using FRIDA mode's scripting support to hook +the `main` function is a special case. This is because the `main` function is +already hooked by the FRIDA mode engine itself and hence the function `main` (or +at least the first basic block already been compiled by Stalker ready for +execution). Hence any attempt to use `Interceptor.replace` like in the example +above will not work. Instead the JS bindings provide a function `setJsMainHook` +for just this scenario as demonstrated in the example below. + +```js +const main = DebugSymbol.fromName('main').address; +Afl.print(`main: ${main}`); + +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); + + int main(int argc, char **argv) { + + LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len); + + } + `, + { + LLVMFuzzerTestOneInput: LLVMFuzzerTestOneInput, + __afl_fuzz_ptr: Afl.getAflFuzzPtr(), + __afl_fuzz_len: Afl.getAflFuzzLen() + }); + +Afl.setEntryPoint(cm.main); +Afl.setPersistentAddress(cm.main); +Afl.setInMemoryFuzzing(); +Afl.setJsMainHook(cm.main); +``` +## Library Fuzzing + +It doesn't take too much imagination to see that the above example can be +extended to use FRIDA's `Module.load` API so that the replaced `main` function +can then call an arbitrary function. In this way, if we have a library which we +wish to fuzz rather than an execuatble, then a surrogate executable can be used. # Patching Consider the [following](test/js/test2.c) test code... @@ -620,41 +697,31 @@ value of the `-t` flag passed to `afl-fuzz`. # 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); + 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. */ - public static addIncludedRange(addressess: NativePointer, size: number): void { - Afl.jsApiAddIncludeRange(addressess, size); + 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. */ - public static done(): void { - Afl.jsApiDone(); + 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 @@ -662,49 +729,48 @@ class Afl { * 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); + 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. */ - public static getAflFuzzLen(): NativePointer { - - return Afl.jsApiGetSymbol("__afl_fuzz_len"); + 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. */ - public static getAflFuzzPtr(): NativePointer { - - return Afl.jsApiGetSymbol("__afl_fuzz_ptr"); + 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. */ - 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); + static print(msg) { + const STDOUT_FILENO = 2; + const log = `${msg}\n`; + const buf = Memory.allocUtf8String(log); + Afl.jsApiWrite(STDOUT_FILENO, buf, log.length); + } + /** + * See `AFL_FRIDA_INST_NO_BACKPATCH`. + */ + static setBackpatchDisable() { + Afl.jsApiSetBackpatchDisable(); } - /** * See `AFL_FRIDA_DEBUG_MAPS`. */ - public static setDebugMaps(): void { - Afl.jsApiSetDebugMaps(); + 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 @@ -713,143 +779,198 @@ class Afl { * function should be called with a `NativePointer` as its * argument. */ - public static setEntryPoint(address: NativePointer): void { - Afl.jsApiSetEntryPoint(address); + static setEntryPoint(address) { + Afl.jsApiSetEntryPoint(address); } - /** * Function used to enable in-memory test cases for fuzzing. */ - public static setInMemoryFuzzing(): void { - Afl.jsApiAflSharedMemFuzzing.writeInt(1); + static setInMemoryFuzzing() { + Afl.jsApiAflSharedMemFuzzing.writeInt(1); + } + /** + * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string` + * as an argument. + */ + static setInstrumentCoverageFile(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentCoverageFile(buf); } - /** * 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); + static setInstrumentDebugFile(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentDebugFile(buf); } - /** * See `AFL_FRIDA_INST_TRACE`. */ - public static setInstrumentEnableTracing(): void { - Afl.jsApiSetInstrumentTrace(); + static setInstrumentEnableTracing() { + Afl.jsApiSetInstrumentTrace(); + } + /** + * See `AFL_FRIDA_INST_JIT`. + */ + static setInstrumentJit() { + Afl.jsApiSetInstrumentJit(); } - /** * See `AFL_INST_LIBS`. */ - public static setInstrumentLibraries(): void { - Afl.jsApiSetInstrumentLibraries(); + static setInstrumentLibraries() { + Afl.jsApiSetInstrumentLibraries(); } - /** * See `AFL_FRIDA_INST_NO_OPTIMIZE` */ - public static setInstrumentNoOptimize(): void { - Afl.jsApiSetInstrumentNoOptimize(); + static setInstrumentNoOptimize() { + Afl.jsApiSetInstrumentNoOptimize(); + } + /* + * See `AFL_FRIDA_INST_SEED` + */ + static setInstrumentSeed(seed) { + Afl.jsApiSetInstrumentSeed(seed); } - /** * See `AFL_FRIDA_INST_TRACE_UNIQUE`. */ - public static setInstrumentTracingUnique(): void { - Afl.jsApiSetInstrumentTraceUnique(); + static setInstrumentTracingUnique() { + Afl.jsApiSetInstrumentTraceUnique(); + } + /** + * See `AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE`. This function takes a single + * `string` as an argument. + */ + static setInstrumentUnstableCoverageFile(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetInstrumentUnstableCoverageFile(buf); + } + /* + * Set a callback to be called in place of the usual `main` function. This see + * `Scripting.md` for details. + */ + static setJsMainHook(address) { + Afl.jsApiSetJsMainHook(address); } - /** * 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); + static setPersistentAddress(address) { + 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); + static setPersistentCount(count) { + Afl.jsApiSetPersistentCount(count); } - /** * See `AFL_FRIDA_PERSISTENT_DEBUG`. */ - public static setPersistentDebug(): void { - Afl.jsApiSetPersistentDebug(); + static setPersistentDebug() { + 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); + 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. */ - public static setPersistentReturn(address: NativePointer): void { - Afl.jsApiSetPersistentReturn(address); + static setPersistentReturn(address) { + Afl.jsApiSetPersistentReturn(address); + } + /** + * See `AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH`. + */ + static setPrefetchBackpatchDisable() { + Afl.jsApiSetPrefetchBackpatchDisable(); } - /** * See `AFL_FRIDA_INST_NO_PREFETCH`. */ - public static setPrefetchDisable(): void { - Afl.jsApiSetPrefetchDisable(); + static setPrefetchDisable() { + Afl.jsApiSetPrefetchDisable(); + } + /** + * See `AFL_FRIDA_SECCOMP_FILE`. This function takes a single `string` as + * an argument. + */ + static setSeccompFile(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetSeccompFile(buf); + } + /** + * See `AFL_FRIDA_STALKER_ADJACENT_BLOCKS`. + */ + static setStalkerAdjacentBlocks(val) { + Afl.jsApiSetStalkerAdjacentBlocks(val); } - /* - * Set a function to be called for each instruction which is instrumented - * by AFL FRIDA mode. + * 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_STALKER_IC_ENTRIES`. */ - public static setStalkerCallback(callback: NativePointer): void { - Afl.jsApiSetStalkerCallback(callback); + static setStalkerIcEntries(val) { + Afl.jsApiSetStalkerIcEntries(val); } - /** * 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); + static setStatsFile(file) { + 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); + static setStatsInterval(interval) { + Afl.jsApiSetStatsInterval(interval); } - /** * 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); + static setStdErr(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStdErr(buf); } - /** * See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as * an argument. */ - public static setStdOut(file: string): void { - const buf = Memory.allocUtf8String(file); - Afl.jsApiSetStdOut(buf); + static setStdOut(file) { + const buf = Memory.allocUtf8String(file); + Afl.jsApiSetStdOut(buf); + } + /** + * See `AFL_FRIDA_TRACEABLE`. + */ + static setTraceable() { + Afl.jsApiSetTraceable(); + } + 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); } - } - ``` diff --git a/frida_mode/frida.map b/frida_mode/frida.map index 7be41aa0..5276db91 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -20,6 +20,7 @@ js_api_set_instrument_trace; js_api_set_instrument_trace_unique; js_api_set_instrument_unstable_coverage_file; + js_api_set_js_main_hook; js_api_set_persistent_address; js_api_set_persistent_count; js_api_set_persistent_debug; @@ -29,6 +30,7 @@ js_api_set_prefetch_disable; js_api_set_seccomp_file; js_api_set_stalker_callback; + js_api_set_stalker_adjacent_blocks; js_api_set_stalker_ic_entries; js_api_set_stats_file; js_api_set_stats_interval; diff --git a/frida_mode/include/asan.h b/frida_mode/include/asan.h index 67d33591..6745eb02 100644 --- a/frida_mode/include/asan.h +++ b/frida_mode/include/asan.h @@ -9,6 +9,7 @@ void asan_config(void); void asan_init(void); void asan_arch_init(void); void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator); +void asan_exclude_module_by_symbol(gchar *symbol_name); #endif diff --git a/frida_mode/include/js.h b/frida_mode/include/js.h index a5ecb712..39aa0573 100644 --- a/frida_mode/include/js.h +++ b/frida_mode/include/js.h @@ -7,11 +7,14 @@ typedef gboolean (*js_api_stalker_callback_t)(const cs_insn *insn, gboolean begin, gboolean excluded, GumStalkerOutput *output); +typedef int (*js_main_hook_t)(int argc, char **argv, char **envp); + extern unsigned char api_js[]; extern unsigned int api_js_len; extern gboolean js_done; extern js_api_stalker_callback_t js_user_callback; +extern js_main_hook_t js_main_hook; /* Frida Mode */ diff --git a/frida_mode/include/stalker.h b/frida_mode/include/stalker.h index 8a111b90..666787e9 100644 --- a/frida_mode/include/stalker.h +++ b/frida_mode/include/stalker.h @@ -5,6 +5,7 @@ extern guint stalker_ic_entries; extern gboolean backpatch_enable; +extern guint stalker_adjacent_blocks; void stalker_config(void); void stalker_init(void); diff --git a/frida_mode/src/asan/asan.c b/frida_mode/src/asan/asan.c index d649bd76..884bec53 100644 --- a/frida_mode/src/asan/asan.c +++ b/frida_mode/src/asan/asan.c @@ -1,6 +1,7 @@ #include "frida-gumjs.h" #include "asan.h" +#include "ranges.h" #include "util.h" static gboolean asan_enabled = FALSE; @@ -32,3 +33,23 @@ void asan_init(void) { } +static gboolean asan_exclude_module(const GumModuleDetails *details, + gpointer user_data) { + + gchar * symbol_name = (gchar *)user_data; + GumAddress address; + + address = gum_module_find_export_by_name(details->name, symbol_name); + if (address == 0) { return TRUE; } + + ranges_add_exclude((GumMemoryRange *)details->range); + return FALSE; + +} + +void asan_exclude_module_by_symbol(gchar *symbol_name) { + + gum_process_enumerate_modules(asan_exclude_module, symbol_name); + +} + diff --git a/frida_mode/src/asan/asan_arm64.c b/frida_mode/src/asan/asan_arm64.c index 88c76535..b2adfa52 100644 --- a/frida_mode/src/asan/asan_arm64.c +++ b/frida_mode/src/asan/asan_arm64.c @@ -88,6 +88,8 @@ void asan_arch_init(void) { } + asan_exclude_module_by_symbol("__asan_loadN"); + } #endif diff --git a/frida_mode/src/asan/asan_x64.c b/frida_mode/src/asan/asan_x64.c index c7b70967..a287ea34 100644 --- a/frida_mode/src/asan/asan_x64.c +++ b/frida_mode/src/asan/asan_x64.c @@ -85,6 +85,8 @@ void asan_arch_init(void) { } + asan_exclude_module_by_symbol("__asan_loadN"); + } #endif diff --git a/frida_mode/src/asan/asan_x86.c b/frida_mode/src/asan/asan_x86.c index afc89936..331d026b 100644 --- a/frida_mode/src/asan/asan_x86.c +++ b/frida_mode/src/asan/asan_x86.c @@ -85,6 +85,8 @@ void asan_arch_init(void) { } + asan_exclude_module_by_symbol("__asan_loadN"); + } #endif diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c index 81e1a4b0..443baa1d 100644 --- a/frida_mode/src/cmplog/cmplog.c +++ b/frida_mode/src/cmplog/cmplog.c @@ -33,8 +33,22 @@ static gboolean cmplog_range(const GumRangeDetails *details, static gint cmplog_sort(gconstpointer a, gconstpointer b) { - return ((GumMemoryRange *)b)->base_address - - ((GumMemoryRange *)a)->base_address; + GumMemoryRange *ra = (GumMemoryRange *)a; + GumMemoryRange *rb = (GumMemoryRange *)b; + + if (ra->base_address < rb->base_address) { + + return -1; + + } else if (ra->base_address > rb->base_address) { + + return 1; + + } else { + + return 0; + + } } diff --git a/frida_mode/src/ctx/ctx_arm32.c b/frida_mode/src/ctx/ctx_arm32.c index 049b5548..28fc706b 100644 --- a/frida_mode/src/ctx/ctx_arm32.c +++ b/frida_mode/src/ctx/ctx_arm32.c @@ -1,6 +1,7 @@ #include "frida-gumjs.h" #include "ctx.h" +#include "util.h" #if defined(__arm__) diff --git a/frida_mode/src/ctx/ctx_arm64.c b/frida_mode/src/ctx/ctx_arm64.c index 01f321e3..63b6cf09 100644 --- a/frida_mode/src/ctx/ctx_arm64.c +++ b/frida_mode/src/ctx/ctx_arm64.c @@ -1,6 +1,7 @@ #include "frida-gumjs.h" #include "ctx.h" +#include "util.h" #if defined(__aarch64__) diff --git a/frida_mode/src/ctx/ctx_x86.c b/frida_mode/src/ctx/ctx_x86.c index abfeafc8..438e1fde 100644 --- a/frida_mode/src/ctx/ctx_x86.c +++ b/frida_mode/src/ctx/ctx_x86.c @@ -1,6 +1,7 @@ #include "frida-gumjs.h" #include "ctx.h" +#include "util.h" #if defined(__i386__) diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c index a36daf88..562e74eb 100644 --- a/frida_mode/src/entry.c +++ b/frida_mode/src/entry.c @@ -36,7 +36,7 @@ static void entry_launch(void) { } -#if defined(__linux__) && !defined(__ANDROID__) +#if defined(__linux__) && defined(PR_SET_PTRACER) && !defined(__ANDROID__) void entry_on_fork(void) { if (traceable) { diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c index 95a24808..c1984eb2 100644 --- a/frida_mode/src/instrument/instrument_coverage.c +++ b/frida_mode/src/instrument/instrument_coverage.c @@ -237,7 +237,7 @@ static void instrument_coverage_mark(void *key, void *value, void *user_data) { } -static void coverage_write(void *data, size_t size) { +static void coverage_write(int fd, void *data, size_t size) { ssize_t written; size_t remain = size; @@ -245,7 +245,7 @@ static void coverage_write(void *data, size_t size) { for (char *cursor = (char *)data; remain > 0; remain -= written, cursor += written) { - written = write(normal_coverage_fd, cursor, remain); + written = write(fd, cursor, remain); if (written < 0) { @@ -257,7 +257,7 @@ static void coverage_write(void *data, size_t size) { } -static void coverage_format(char *format, ...) { +static void coverage_format(int fd, char *format, ...) { va_list ap; char buffer[4096] = {0}; @@ -272,11 +272,11 @@ static void coverage_format(char *format, ...) { len = strnlen(buffer, sizeof(buffer)); - coverage_write(buffer, len); + coverage_write(fd, buffer, len); } -static void coverage_write_modules(GArray *coverage_modules) { +static void coverage_write_modules(int fd, GArray *coverage_modules) { guint emitted = 0; for (guint i = 0; i < coverage_modules->len; i++) { @@ -285,16 +285,16 @@ static void coverage_write_modules(GArray *coverage_modules) { &g_array_index(coverage_modules, coverage_range_t, i); if (module->count == 0) continue; - coverage_format("%3u, ", emitted); - coverage_format("%016" G_GINT64_MODIFIER "X, ", module->base_address); - coverage_format("%016" G_GINT64_MODIFIER "X, ", module->limit); + coverage_format(fd, "%3u, ", emitted); + coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", module->base_address); + coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", module->limit); /* entry */ - coverage_format("%016" G_GINT64_MODIFIER "X, ", 0); + coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0); /* checksum */ - coverage_format("%016" G_GINT64_MODIFIER "X, ", 0); + coverage_format(fd, "%016" G_GINT64_MODIFIER "X, ", 0); /* timestamp */ - coverage_format("%08" G_GINT32_MODIFIER "X, ", 0); - coverage_format("%s\n", module->path); + coverage_format(fd, "%08" G_GINT32_MODIFIER "X, ", 0); + coverage_format(fd, "%s\n", module->path); emitted++; } @@ -304,7 +304,7 @@ static void coverage_write_modules(GArray *coverage_modules) { static void coverage_write_events(void *key, void *value, void *user_data) { UNUSED_PARAMETER(key); - UNUSED_PARAMETER(user_data); + int fd = *((int *)user_data); normal_coverage_data_t *val = (normal_coverage_data_t *)value; if (val->module == NULL) { return; } @@ -317,20 +317,20 @@ static void coverage_write_events(void *key, void *value, void *user_data) { }; - coverage_write(&evt, sizeof(coverage_event_t)); + coverage_write(fd, &evt, sizeof(coverage_event_t)); } -static void coverage_write_header(guint coverage_marked_modules) { +static void coverage_write_header(int fd, guint coverage_marked_modules) { char version[] = "DRCOV VERSION: 2\n"; char flavour[] = "DRCOV FLAVOR: frida\n"; char columns[] = "Columns: id, base, end, entry, checksum, timestamp, path\n"; - coverage_write(version, sizeof(version) - 1); - coverage_write(flavour, sizeof(flavour) - 1); - coverage_format("Module Table: version 2, count %u\n", + coverage_write(fd, version, sizeof(version) - 1); + coverage_write(fd, flavour, sizeof(flavour) - 1); + coverage_format(fd, "Module Table: version 2, count %u\n", coverage_marked_modules); - coverage_write(columns, sizeof(columns) - 1); + coverage_write(fd, columns, sizeof(columns) - 1); } @@ -412,10 +412,11 @@ static void instrument_coverage_normal_run() { instrument_coverage_print("Coverage - Marked Modules: %u\n", coverage_marked_modules); - coverage_write_header(coverage_marked_modules); - coverage_write_modules(coverage_modules); - coverage_format("BB Table: %u bbs\n", ctx.count); - g_hash_table_foreach(coverage_hash, coverage_write_events, NULL); + coverage_write_header(normal_coverage_fd, coverage_marked_modules); + coverage_write_modules(normal_coverage_fd, coverage_modules); + coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", ctx.count); + g_hash_table_foreach(coverage_hash, coverage_write_events, + &normal_coverage_fd); g_hash_table_unref(coverage_hash); @@ -636,10 +637,11 @@ static void instrument_coverage_unstable_run(void) { instrument_coverage_print("Coverage - Marked Modules: %u\n", coverage_marked_modules); - coverage_write_header(coverage_marked_modules); - coverage_write_modules(coverage_modules); - coverage_format("BB Table: %u bbs\n", ctx.count); - g_hash_table_foreach(unstable_blocks, coverage_write_events, NULL); + coverage_write_header(unstable_coverage_fd, coverage_marked_modules); + coverage_write_modules(unstable_coverage_fd, coverage_modules); + coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", ctx.count); + g_hash_table_foreach(unstable_blocks, coverage_write_events, + &unstable_coverage_fd); g_hash_table_unref(unstable_blocks); g_array_free(unstable_edge_ids, TRUE); diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c index c474d034..41162f2a 100644 --- a/frida_mode/src/instrument/instrument_x64.c +++ b/frida_mode/src/instrument/instrument_x64.c @@ -5,7 +5,7 @@ #if defined(__linux__) #if !defined(__ANDROID__) - #include <asm/prctl.h> + #include <sys/prctl.h> #include <sys/syscall.h> #else #include <linux/ashmem.h> @@ -52,54 +52,41 @@ typedef struct { // shared_mem[cur_location ^ prev_location]++; // prev_location = cur_location >> 1; - // 0x7ffff6cbb9b6: lea rsp,[rsp-0x80] - // - // 0x7ffff6cbb9bb: push rax - // 0x7ffff6cbb9bc: lahf - // 0x7ffff6cbb9bd: push rax - // 0x7ffff6cbb9be: push rbx - // - // 0x7ffff6cbb9bf: mov eax,DWORD PTR [rip+0x33bd7b] - // 0x7ffff6cbb9c5: xor eax,0x3f77 - // 0x7ffff6cbb9ca: add eax,0x10000 - // 0x7ffff6cbb9cf: mov bl,BYTE PTR [rax] - // 0x7ffff6cbb9d1: add bl,0x1 - // 0x7ffff6cbb9d4: adc bl,0x0 - // 0x7ffff6cbb9d7: mov BYTE PTR [rax],bl - // - // 0x7ffff6cbb9d9: mov DWORD PTR [rip+0x33bd5d],0x9fbb - // - // 0x7ffff6cbb9e3: pop rbx - // 0x7ffff6cbb9e4: pop rax - // 0x7ffff6cbb9e5: sahf - // 0x7ffff6cbb9e6: pop rax - // - // 0x7ffff6cbb9e7: lea rsp,[rsp+0x80] - - uint8_t lea_rsp_rsp_sub_rz[5]; - - uint8_t push_rax; + // mov QWORD PTR [rsp-0x80],rax + // lahf + // mov QWORD PTR [rsp-0x88],rax + // mov QWORD PTR [rsp-0x90],rbx + // mov eax,DWORD PTR [rip+0x333d5a] # 0x7ffff6ff2740 + // mov DWORD PTR [rip+0x333d3c],0x9fbb # 0x7ffff6ff2740 + // xor eax,0x103f77 + // mov bl,BYTE PTR [rax] + // add bl,0x1 + // adc bl,0x0 + // mov BYTE PTR [rax],bl + // mov rbx,QWORD PTR [rsp-0x90] + // mov rax,QWORD PTR [rsp-0x88] + // sahf + // mov rax,QWORD PTR [rsp-0x80] + + uint8_t mov_rax_rsp_88[8]; uint8_t lahf; - uint8_t push_rax2; - uint8_t push_rbx; + uint8_t mov_rax_rsp_90[8]; + uint8_t mov_rbx_rsp_98[8]; uint8_t mov_eax_prev_loc[6]; + uint8_t mov_prev_loc_curr_loc_shr1[10]; + uint8_t xor_eax_curr_loc[5]; - uint8_t add_eax_afl_area[5]; uint8_t mov_rbx_ptr_rax[2]; uint8_t add_bl_1[3]; uint8_t adc_bl_0[3]; uint8_t mov_ptr_rax_rbx[2]; - uint8_t mov_prev_loc_curr_loc_shr1[10]; - - uint8_t pop_rbx; - uint8_t pop_rax2; + uint8_t mov_rsp_98_rbx[8]; + uint8_t mov_rsp_90_rax[8]; uint8_t sahf; - uint8_t pop_rax; - - uint8_t lsa_rsp_rsp_add_rz[8]; + uint8_t mov_rsp_88_rax[8]; } afl_log_code_asm_t; @@ -115,29 +102,24 @@ typedef union { static const afl_log_code_asm_t template = { - .lea_rsp_rsp_sub_rz = {0x48, 0x8D, 0x64, 0x24, 0x80}, - .push_rax = 0x50, + .mov_rax_rsp_88 = {0x48, 0x89, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF}, .lahf = 0x9f, - .push_rax2 = 0x50, - .push_rbx = 0x53, + .mov_rax_rsp_90 = {0x48, 0x89, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF}, + .mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF}, .mov_eax_prev_loc = {0x8b, 0x05}, - .xor_eax_curr_loc = {0x35}, + .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05}, - .add_eax_afl_area = {0x05}, + .xor_eax_curr_loc = {0x35}, .mov_rbx_ptr_rax = {0x8a, 0x18}, .add_bl_1 = {0x80, 0xc3, 0x01}, .adc_bl_0 = {0x80, 0xd3, 0x00}, .mov_ptr_rax_rbx = {0x88, 0x18}, - .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05}, - - .pop_rbx = 0x5b, - .pop_rax2 = 0x58, + .mov_rsp_98_rbx = {0x48, 0x8B, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF}, + .mov_rsp_90_rax = {0x48, 0x8B, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF}, .sahf = 0x9e, - .pop_rax = 0x58, - - .lsa_rsp_rsp_add_rz = {0x48, 0x8D, 0xA4, 0x24, 0x80, 0x00, 0x00, 0x00}, + .mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF}, } @@ -162,7 +144,13 @@ static gboolean instrument_coverage_find_low(const GumRangeDetails *details, } - last_limit = details->range->base_address + details->range->size; + /* + * Align our buffer on a 64k boundary so that the low 16-bits of the address + * are zero, then we can just XOR the base address in, when we XOR with the + * current block ID. + */ + last_limit = GUM_ALIGN_SIZE( + details->range->base_address + details->range->size, (64ULL << 10)); return TRUE; } @@ -421,13 +409,8 @@ void instrument_coverage_optimize(const cs_insn * instr, sizeof(code.code.xor_eax_curr_loc) - sizeof(guint32); - *((guint32 *)&code.bytes[xor_curr_loc_offset]) = (guint32)(area_offset); - - gssize lea_rax_offset = offsetof(afl_log_code, code.add_eax_afl_area) + - sizeof(code.code.add_eax_afl_area) - sizeof(guint32); - - *((guint32 *)&code.bytes[lea_rax_offset]) = - (guint32)GPOINTER_TO_SIZE(__afl_area_ptr); + *((guint32 *)&code.bytes[xor_curr_loc_offset]) = + (guint32)(GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset); gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code)); diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c index 79664afa..ad837e2d 100644 --- a/frida_mode/src/instrument/instrument_x86.c +++ b/frida_mode/src/instrument/instrument_x86.c @@ -1,67 +1,144 @@ #include "frida-gumjs.h" #include "instrument.h" +#include "stalker.h" #include "util.h" #if defined(__i386__) -static GumAddress current_log_impl = GUM_ADDRESS(0); +static GHashTable *coverage_blocks = NULL; -static void instrument_coverage_function(GumX86Writer *cw) { + #pragma pack(push, 1) +typedef struct { - gum_x86_writer_put_pushfx(cw); - gum_x86_writer_put_push_reg(cw, GUM_REG_ECX); - gum_x86_writer_put_push_reg(cw, GUM_REG_EDX); + // cur_location = (block_address >> 4) ^ (block_address << 8); + // shared_mem[cur_location ^ prev_location]++; + // prev_location = cur_location >> 1; - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX, - GUM_ADDRESS(&instrument_previous_pc)); - gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_EDX, GUM_REG_ECX); - gum_x86_writer_put_xor_reg_reg(cw, GUM_REG_EDX, GUM_REG_EDI); + uint8_t mov_eax_esp_4[4]; + uint8_t lahf; + uint8_t mov_eax_esp_8[4]; + uint8_t mov_ebx_esp_c[4]; - gum_x86_writer_put_add_reg_imm(cw, GUM_REG_EDX, GUM_ADDRESS(__afl_area_ptr)); + uint8_t mov_eax_prev_loc[5]; + uint8_t mov_prev_loc_curr_loc_shr1[10]; - /* add byte ptr [edx], 1 */ - uint8_t add_byte_ptr_edx_1[] = {0x80, 0x02, 0x01}; - gum_x86_writer_put_bytes(cw, add_byte_ptr_edx_1, sizeof(add_byte_ptr_edx_1)); + uint8_t xor_eax_curr_loc[5]; + uint8_t add_eax_area_ptr[5]; - /* adc byte ptr [edx], 0 */ - uint8_t adc_byte_ptr_edx_0[] = {0x80, 0x12, 0x00}; - gum_x86_writer_put_bytes(cw, adc_byte_ptr_edx_0, sizeof(adc_byte_ptr_edx_0)); + uint8_t mov_ebx_ptr_eax[2]; + uint8_t add_bl_1[3]; + uint8_t adc_bl_0[3]; + uint8_t mov_ptr_eax_ebx[2]; - uint8_t ror_di_1[] = {0x66, 0xd1, 0xcf}; - gum_x86_writer_put_bytes(cw, ror_di_1, sizeof(ror_di_1)); - gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_ECX, GUM_REG_EDI); + uint8_t mov_esp_c_ebx[4]; + uint8_t mov_esp_8_eax[4]; + uint8_t sahf; + uint8_t mov_esp_4_eax[4]; - gum_x86_writer_put_pop_reg(cw, GUM_REG_EDX); - gum_x86_writer_put_pop_reg(cw, GUM_REG_ECX); - gum_x86_writer_put_popfx(cw); - gum_x86_writer_put_ret(cw); +} afl_log_code_asm_t; + + #pragma pack(pop) + +typedef union { + + afl_log_code_asm_t code; + uint8_t bytes[0]; + +} afl_log_code; + +static const afl_log_code_asm_t template = + { + + .mov_eax_esp_4 = {0x89, 0x44, 0x24, 0xFC}, + .lahf = 0x9f, + .mov_eax_esp_8 = {0x89, 0x44, 0x24, 0xF8}, + .mov_ebx_esp_c = {0x89, 0x5C, 0x24, 0xF4}, + + .mov_eax_prev_loc = {0xA1}, + .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05}, + + .xor_eax_curr_loc = {0x35}, + .add_eax_area_ptr = {0x05}, + .mov_ebx_ptr_eax = {0x8a, 0x18}, + .add_bl_1 = {0x80, 0xc3, 0x01}, + .adc_bl_0 = {0x80, 0xd3, 0x00}, + .mov_ptr_eax_ebx = {0x88, 0x18}, + + .mov_esp_c_ebx = {0x8B, 0x5C, 0x24, 0xF4}, + .mov_esp_8_eax = {0x8B, 0x44, 0x24, 0xF8}, + .sahf = 0x9e, + .mov_esp_4_eax = {0x8B, 0x44, 0x24, 0xFC}, } +; + gboolean instrument_is_coverage_optimize_supported(void) { return true; } -static void instrument_coverate_write_function(GumStalkerOutput *output) { +static void instrument_coverage_switch(GumStalkerObserver *self, + gpointer start_address, + const cs_insn * from_insn, + gpointer * target) { - GumX86Writer *cw = output->writer.x86; + UNUSED_PARAMETER(self); + UNUSED_PARAMETER(start_address); + + cs_x86 * x86; + cs_x86_op *op; + if (from_insn == NULL) { return; } + + x86 = &from_insn->detail->x86; + op = x86->operands; + + if (!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target))) { + + return; + + } + + switch (from_insn->id) { + + case X86_INS_CALL: + case X86_INS_JMP: + if (x86->op_count != 1) { + + FATAL("Unexpected operand count: %d", x86->op_count); + + } + + if (op[0].type != X86_OP_IMM) { return; } + + break; + case X86_INS_RET: + break; + default: + return; - if (current_log_impl == 0 || - !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || - !gum_x86_writer_can_branch_directly_between(cw->pc + 128, - current_log_impl)) { + } + + *target = (guint8 *)*target + sizeof(afl_log_code); + +} + +static void instrument_coverage_suppress_init(void) { - gconstpointer after_log_impl = cw->code + 1; + static gboolean initialized = false; + if (initialized) { return; } + initialized = true; - gum_x86_writer_put_jmp_near_label(cw, after_log_impl); + GumStalkerObserver * observer = stalker_get_observer(); + GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer); + iface->switch_callback = instrument_coverage_switch; - current_log_impl = cw->pc; - instrument_coverage_function(cw); + coverage_blocks = g_hash_table_new(g_direct_hash, g_direct_equal); + if (coverage_blocks == NULL) { - gum_x86_writer_put_label(cw, after_log_impl); + FATAL("Failed to g_hash_table_new, errno: %d", errno); } @@ -70,14 +147,61 @@ static void instrument_coverate_write_function(GumStalkerOutput *output) { void instrument_coverage_optimize(const cs_insn * instr, GumStalkerOutput *output) { + afl_log_code code = {0}; GumX86Writer *cw = output->writer.x86; guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address)); - instrument_coverate_write_function(output); + gsize map_size_pow2; + gsize area_offset_ror; + + code.code = template; + + instrument_coverage_suppress_init(); + + // gum_x86_writer_put_breakpoint(cw); + + if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) { + + FATAL("Failed - g_hash_table_add"); + + } + + gssize prev_loc_value_offset2 = + offsetof(afl_log_code, code.mov_eax_prev_loc) + + sizeof(code.code.mov_eax_prev_loc) - sizeof(gint); + + *((gint *)&code.bytes[prev_loc_value_offset2]) = + (gint)GPOINTER_TO_SIZE(&instrument_previous_pc); + + gssize curr_loc_shr_1_offset = + offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) + + sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32); + + map_size_pow2 = util_log2(__afl_map_size); + area_offset_ror = util_rotate(area_offset, 1, map_size_pow2); + + *((guint32 *)&code.bytes[curr_loc_shr_1_offset]) = (guint32)(area_offset_ror); + + gssize prev_loc_value_offset = + offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) + + sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(gint) - + sizeof(guint32); + + *((gint *)&code.bytes[prev_loc_value_offset]) = + (gint)GPOINTER_TO_SIZE(&instrument_previous_pc); + + gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) + + sizeof(code.code.xor_eax_curr_loc) - + sizeof(guint32); + + *((guint32 *)&code.bytes[xor_curr_loc_offset]) = (guint32)area_offset; + + gssize add_area_ptr_offset = offsetof(afl_log_code, code.add_eax_area_ptr) + + sizeof(code.code.add_eax_area_ptr) - + sizeof(guint32); + + *((guint32 *)&code.bytes[add_area_ptr_offset]) = (guint32)__afl_area_ptr; - gum_x86_writer_put_push_reg(cw, GUM_REG_EDI); - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EDI, area_offset); - gum_x86_writer_put_call_address(cw, current_log_impl); - gum_x86_writer_put_pop_reg(cw, GUM_REG_EDI); + gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code)); } diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index 5db62389..215fbdaf 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -151,6 +151,13 @@ class Afl { const buf = Memory.allocUtf8String(file); Afl.jsApiSetInstrumentUnstableCoverageFile(buf); } + /* + * Set a callback to be called in place of the usual `main` function. This see + * `Scripting.md` for details. + */ + static setJsMainHook(address) { + Afl.jsApiSetJsMainHook(address); + } /** * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a * `NativePointer` should be provided as it's argument. @@ -205,6 +212,12 @@ class Afl { const buf = Memory.allocUtf8String(file); Afl.jsApiSetSeccompFile(buf); } + /** + * See `AFL_FRIDA_STALKER_ADJACENT_BLOCKS`. + */ + static setStalkerAdjacentBlocks(val) { + Afl.jsApiSetStalkerAdjacentBlocks(val); + } /* * Set a function to be called for each instruction which is instrumented * by AFL FRIDA mode. @@ -285,6 +298,7 @@ Afl.jsApiSetInstrumentSeed = Afl.jsApiGetFunction("js_api_set_instrument_seed", Afl.jsApiSetInstrumentTrace = Afl.jsApiGetFunction("js_api_set_instrument_trace", "void", []); Afl.jsApiSetInstrumentTraceUnique = Afl.jsApiGetFunction("js_api_set_instrument_trace_unique", "void", []); Afl.jsApiSetInstrumentUnstableCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_unstable_coverage_file", "void", ["pointer"]); +Afl.jsApiSetJsMainHook = Afl.jsApiGetFunction("js_api_set_js_main_hook", "void", ["pointer"]); 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", []); @@ -293,6 +307,7 @@ Afl.jsApiSetPersistentReturn = Afl.jsApiGetFunction("js_api_set_persistent_retur Afl.jsApiSetPrefetchBackpatchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_backpatch_disable", "void", []); Afl.jsApiSetPrefetchDisable = Afl.jsApiGetFunction("js_api_set_prefetch_disable", "void", []); Afl.jsApiSetSeccompFile = Afl.jsApiGetFunction("js_api_set_seccomp_file", "void", ["pointer"]); +Afl.jsApiSetStalkerAdjacentBlocks = Afl.jsApiGetFunction("js_api_set_stalker_adjacent_blocks", "void", ["uint32"]); Afl.jsApiSetStalkerCallback = Afl.jsApiGetFunction("js_api_set_stalker_callback", "void", ["pointer"]); Afl.jsApiSetStalkerIcEntries = Afl.jsApiGetFunction("js_api_set_stalker_ic_entries", "void", ["uint32"]); Afl.jsApiSetStatsFile = Afl.jsApiGetFunction("js_api_set_stats_file", "void", ["pointer"]); diff --git a/frida_mode/src/js/js.c b/frida_mode/src/js/js.c index 37cd377b..5f477388 100644 --- a/frida_mode/src/js/js.c +++ b/frida_mode/src/js/js.c @@ -3,10 +3,11 @@ #include "js.h" #include "util.h" -static char * js_script = NULL; gboolean js_done = FALSE; js_api_stalker_callback_t js_user_callback = NULL; +js_main_hook_t js_main_hook = NULL; +static char * js_script = NULL; static gchar * filename = "afl.js"; static gchar * contents; static GumScriptBackend * backend; diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 570da335..5021b531 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -11,6 +11,10 @@ #include "stats.h" #include "util.h" +typedef uint8_t u8; + +extern void __afl_set_persistent_mode(u8 mode); + __attribute__((visibility("default"))) void js_api_done() { js_done = TRUE; @@ -47,6 +51,8 @@ __attribute__((visibility("default"))) void js_api_set_persistent_address( persistent_start = GPOINTER_TO_SIZE(address); + __afl_set_persistent_mode(1); + } __attribute__((visibility("default"))) void js_api_set_persistent_return( @@ -242,3 +248,17 @@ __attribute__((visibility("default"))) void js_api_set_backpatch_disable(void) { } +__attribute__((visibility("default"))) void js_api_set_stalker_adjacent_blocks( + guint val) { + + stalker_adjacent_blocks = val; + +} + +__attribute__((visibility("default"))) void js_api_set_js_main_hook( + const js_main_hook_t hook) { + + js_main_hook = hook; + +} + diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index cb88eabe..913e3a46 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -36,13 +36,13 @@ extern mach_port_t mach_task_self(); extern GumAddress gum_darwin_find_entrypoint(mach_port_t task); #else -extern int __libc_start_main(int *(main)(int, char **, char **), int argc, +extern int __libc_start_main(int (*main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void(*stack_end)); #endif -typedef int *(*main_fn_t)(int argc, char **argv, char **envp); +typedef int (*main_fn_t)(int argc, char **argv, char **envp); static main_fn_t main_fn = NULL; @@ -217,7 +217,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) { } -static int *on_main(int argc, char **argv, char **envp) { +static int on_main(int argc, char **argv, char **envp) { on_main_os(argc, argv, envp); @@ -225,12 +225,20 @@ static int *on_main(int argc, char **argv, char **envp) { afl_frida_start(); - return main_fn(argc, argv, envp); + if (js_main_hook != NULL) { + + return js_main_hook(argc, argv, envp); + + } else { + + return main_fn(argc, argv, envp); + + } } #if defined(EMBEDDED) -extern int *main(int argc, char **argv, char **envp); +extern int main(int argc, char **argv, char **envp); static void intercept_main(void) { @@ -253,7 +261,7 @@ static void intercept_main(void) { } #else -static int on_libc_start_main(int *(main)(int, char **, char **), int argc, +static int on_libc_start_main(int (*main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void(*stack_end)) { diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c index 902274b3..5425b01b 100644 --- a/frida_mode/src/persistent/persistent_x86.c +++ b/frida_mode/src/persistent/persistent_x86.c @@ -4,6 +4,7 @@ #include "instrument.h" #include "persistent.h" +#include "util.h" #if defined(__i386__) diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index 027417ee..9844c74c 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -166,8 +166,22 @@ static void convert_token(gchar *token, GumMemoryRange *range) { gint range_sort(gconstpointer a, gconstpointer b) { - return ((GumMemoryRange *)a)->base_address - - ((GumMemoryRange *)b)->base_address; + GumMemoryRange *ra = (GumMemoryRange *)a; + GumMemoryRange *rb = (GumMemoryRange *)b; + + if (ra->base_address < rb->base_address) { + + return -1; + + } else if (ra->base_address > rb->base_address) { + + return 1; + + } else { + + return 0; + + } } @@ -249,7 +263,7 @@ static void check_for_overlaps(GArray *array) { GumAddress curr_limit = curr->base_address + curr->size; if (prev_limit > curr->base_address) { - FFATAL("OVerlapping ranges 0x%016" G_GINT64_MODIFIER + FFATAL("Overlapping ranges 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x 0x%016" G_GINT64_MODIFIER "x-0x%016" G_GINT64_MODIFIER "x", prev->base_address, prev_limit, curr->base_address, curr_limit); diff --git a/frida_mode/src/seccomp/seccomp_event.c b/frida_mode/src/seccomp/seccomp_event.c index aca0967a..0907eff8 100644 --- a/frida_mode/src/seccomp/seccomp_event.c +++ b/frida_mode/src/seccomp/seccomp_event.c @@ -10,7 +10,13 @@ int seccomp_event_create(void) { +#ifdef SYS_eventfd int fd = syscall(SYS_eventfd, 0, 0); +#else +# ifdef SYS_eventfd2 + int fd = syscall(SYS_eventfd2, 0, 0); +# endif +#endif if (fd < 0) { FFATAL("seccomp_event_create"); } return fd; diff --git a/frida_mode/src/seccomp/seccomp_filter.c b/frida_mode/src/seccomp/seccomp_filter.c index a7c0926c..5aee398f 100644 --- a/frida_mode/src/seccomp/seccomp_filter.c +++ b/frida_mode/src/seccomp/seccomp_filter.c @@ -72,7 +72,13 @@ static struct sock_filter filter[] = { /* Allow us to make anonymous maps */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), +#ifdef __NR_mmap BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mmap, 0, 3), +#else +# ifdef __NR_mmap2 + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mmap2, 0, 3), +# endif +#endif BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, args[4]))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, -1, 0, 1), diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c index 35a9d856..b4dd5a47 100644 --- a/frida_mode/src/stalker.c +++ b/frida_mode/src/stalker.c @@ -7,6 +7,7 @@ guint stalker_ic_entries = 0; gboolean backpatch_enable = TRUE; +guint stalker_adjacent_blocks = 0; static GumStalker *stalker = NULL; @@ -60,7 +61,9 @@ void stalker_config(void) { backpatch_enable = (getenv("AFL_FRIDA_INST_NO_BACKPATCH") == NULL); - stalker_ic_entries = util_read_num("AFL_FRIDA_STALKER_IC_ENTRIES"); + stalker_ic_entries = util_read_num("AFL_FRIDA_STALKER_ADJACENT_BLOCKS"); + + stalker_adjacent_blocks = util_read_num("AFL_FRIDA_STALKER_IC_ENTRIES"); observer = g_object_new(GUM_TYPE_AFL_STALKER_OBSERVER, NULL); @@ -92,6 +95,7 @@ void stalker_init(void) { FOKF("Instrumentation - backpatch [%c]", backpatch_enable ? 'X' : ' '); FOKF("Stalker - ic_entries [%u]", stalker_ic_entries); + FOKF("Stalker - adjacent_blocks [%u]", stalker_adjacent_blocks); #if !(defined(__x86_64__) || defined(__i386__)) if (stalker_ic_entries != 0) { @@ -100,13 +104,34 @@ void stalker_init(void) { } -#endif + if (stalker_adjacent_blocks != 0) { + FFATAL("AFL_FRIDA_STALKER_ADJACENT_BLOCKS not supported"); + + } + +#endif if (stalker_ic_entries == 0) { stalker_ic_entries = 32; } + if (instrument_coverage_filename == NULL) { + + if (stalker_adjacent_blocks == 0) { stalker_adjacent_blocks = 32; } + + } else { + + if (stalker_adjacent_blocks != 0) { + + FFATAL( + "AFL_FRIDA_STALKER_ADJACENT_BLOCKS and AFL_FRIDA_INST_COVERAGE_FILE " + "are incompatible"); + + } + + } + #if defined(__x86_64__) || defined(__i386__) - stalker = - g_object_new(GUM_TYPE_STALKER, "ic-entries", stalker_ic_entries, NULL); + stalker = g_object_new(GUM_TYPE_STALKER, "ic-entries", stalker_ic_entries, + "adjacent-blocks", stalker_adjacent_blocks, NULL); #else stalker = gum_stalker_new(); #endif diff --git a/frida_mode/test/freetype2/GNUmakefile b/frida_mode/test/freetype2/GNUmakefile index 891660ca..f7a50de2 100644 --- a/frida_mode/test/freetype2/GNUmakefile +++ b/frida_mode/test/freetype2/GNUmakefile @@ -84,7 +84,7 @@ all: $(TEST_BIN) make -C $(ROOT)frida_mode/ 32: - CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + CFLAGS="-m32" CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all $(BUILD_DIR): mkdir -p $@ @@ -126,7 +126,7 @@ $(HARNESS_SRC): wget -O $@ $(HARNESS_URL) $(HARNESS_OBJ): $(HARNESS_SRC) - $(CC) -o $@ -c $< + $(CC) $(CFLAGS) -o $@ -c $< ########## TEST ####### diff --git a/frida_mode/test/js/GNUmakefile b/frida_mode/test/js/GNUmakefile index aad81d08..c702ad98 100644 --- a/frida_mode/test/js/GNUmakefile +++ b/frida_mode/test/js/GNUmakefile @@ -10,6 +10,7 @@ TESTINSTSRC:=$(PWD)test.c TESTINSTBIN2:=$(BUILD_DIR)test2 TESTINSTSRC2:=$(PWD)test2.c +AFLPP_DRIVER_DUMMY_INPUT:=$(BUILD_DIR)dummy QEMU_OUT:=$(BUILD_DIR)qemu-out FRIDA_OUT:=$(BUILD_DIR)frida-out @@ -40,9 +41,36 @@ $(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) $(TESTINSTBIN2): $(TESTINSTSRC2) | $(BUILD_DIR) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< +$(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR) + dd if=/dev/zero bs=1048576 count=1 of=$@ + clean: rm -rf $(BUILD_DIR) +frida_js_main: $(TESTINSTBIN) $(TEST_DATA_FILE) $(AFLPP_DRIVER_DUMMY_INPUT) + AFL_PRELOAD=$(AFL_PRELOAD) \ + AFL_FRIDA_JS_SCRIPT=main.js \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -t 10000+ \ + -- \ + $(TESTINSTBIN) $(AFLPP_DRIVER_DUMMY_INPUT) + +frida_js_fuzz: $(TESTINSTBIN) $(TEST_DATA_FILE) $(AFLPP_DRIVER_DUMMY_INPUT) + AFL_PRELOAD=$(AFL_PRELOAD) \ + AFL_FRIDA_JS_SCRIPT=fuzz.js \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -t 10000+ \ + -- \ + $(TESTINSTBIN) $(AFLPP_DRIVER_DUMMY_INPUT) + frida_js_entry: $(TESTINSTBIN) $(TEST_DATA_FILE) AFL_PRELOAD=$(AFL_PRELOAD) \ AFL_FRIDA_JS_SCRIPT=entry.js \ diff --git a/frida_mode/test/js/fuzz.js b/frida_mode/test/js/fuzz.js new file mode 100644 index 00000000..24eca2b6 --- /dev/null +++ b/frida_mode/test/js/fuzz.js @@ -0,0 +1,41 @@ +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 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 My_LLVMFuzzerTestOneInput(char *buf, int len) { + + LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len); + + } + `, + { + LLVMFuzzerTestOneInput: LLVMFuzzerTestOneInput, + __afl_fuzz_ptr: Afl.getAflFuzzPtr(), + __afl_fuzz_len: Afl.getAflFuzzLen() + }); + +Afl.setEntryPoint(cm.My_LLVMFuzzerTestOneInput); +Afl.setPersistentAddress(cm.My_LLVMFuzzerTestOneInput); +Afl.setInMemoryFuzzing(); +Interceptor.replace(LLVMFuzzerTestOneInput, cm.My_LLVMFuzzerTestOneInput); +Afl.print("done"); +Afl.done(); diff --git a/frida_mode/test/js/main.js b/frida_mode/test/js/main.js new file mode 100644 index 00000000..06306fc4 --- /dev/null +++ b/frida_mode/test/js/main.js @@ -0,0 +1,44 @@ +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 main = DebugSymbol.fromName('main').address; +Afl.print(`main: ${main}`); + +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); + + int main(int argc, char **argv) { + + LLVMFuzzerTestOneInput(__afl_fuzz_ptr, *__afl_fuzz_len); + + } + `, + { + LLVMFuzzerTestOneInput: LLVMFuzzerTestOneInput, + __afl_fuzz_ptr: Afl.getAflFuzzPtr(), + __afl_fuzz_len: Afl.getAflFuzzLen() + }); + +Afl.setEntryPoint(cm.main); +Afl.setPersistentAddress(cm.main); +Afl.setInMemoryFuzzing(); +Afl.setJsMainHook(cm.main); +Afl.print("done"); +Afl.done(); diff --git a/frida_mode/test/unstable/GNUmakefile b/frida_mode/test/unstable/GNUmakefile index 0ccc5fb1..54bbe662 100644 --- a/frida_mode/test/unstable/GNUmakefile +++ b/frida_mode/test/unstable/GNUmakefile @@ -86,11 +86,23 @@ frida: $(UNSTABLE_BIN) $(UNSTABLE_DATA_FILE) $(UNSTABLE_BIN) @@ frida_coverage: $(UNSTABLE_BIN) $(UNSTABLE_DATA_FILE) - AFL_DEBUG=1 \ AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ AFL_FRIDA_OUTPUT_STDOUT=/tmp/stdout.txt \ AFL_FRIDA_OUTPUT_STDERR=/tmp/stderr.txt \ AFL_FRIDA_INST_COVERAGE_FILE=/tmp/coverage.dat \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(UNSTABLE_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(UNSTABLE_BIN) @@ + +frida_unstable: $(UNSTABLE_BIN) $(UNSTABLE_DATA_FILE) + AFL_DEBUG=1 \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_FRIDA_OUTPUT_STDOUT=/tmp/stdout.txt \ + AFL_FRIDA_OUTPUT_STDERR=/tmp/stderr.txt \ AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE=/tmp/unstable.dat \ $(ROOT)afl-fuzz \ -D \ diff --git a/frida_mode/test/vorbis/GNUmakefile b/frida_mode/test/vorbis/GNUmakefile new file mode 100644 index 00000000..59ae9a59 --- /dev/null +++ b/frida_mode/test/vorbis/GNUmakefile @@ -0,0 +1,200 @@ +PWD:=$(shell pwd)/ +ROOT:=$(PWD)../../../ +BUILD_DIR:=$(PWD)build/ + +AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so +AFLPP_QEMU_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/qemu_hook.so + +OGG_GIT_REPO:=https://github.com/xiph/ogg.git +OGG_BUILD_DIR:=$(BUILD_DIR)ogg/ +OGG_DIR:=$(OGG_BUILD_DIR)ogg/ +OGG_INSTALL:=$(OGG_BUILD_DIR)install/ +OGG_LIB:=$(OGG_INSTALL)lib/libogg.a + +VORBIS_GIT_REPO:=https://github.com/xiph/vorbis.git +VORBIS_BUILD_DIR:=$(BUILD_DIR)vorbis/ +VORBIS_DIR:=$(VORBIS_BUILD_DIR)vorbis/ +VORBIS_INSTALL:=$(VORBIS_BUILD_DIR)install/ +VORBIS_LIB:=$(VORBIS_INSTALL)lib/libvorbis.a +VORBISFILE_LIB:=$(VORBIS_INSTALL)lib/libvorbisfile.a + +DECODE_URL:=https://raw.githubusercontent.com/google/oss-fuzz/688aadaf44499ddada755562109e5ca5eb3c5662/projects/vorbis/decode_fuzzer.cc +DECODE_SRC:=$(BUILD_DIR)decode_fuzzer.cc +DECODE_OBJ:=$(BUILD_DIR)decode_fuzzer.o + +HARNESS_URL:=https://raw.githubusercontent.com/llvm/llvm-project/main/compiler-rt/lib/fuzzer/standalone/StandaloneFuzzTargetMain.c +HARNESS_SRC:=$(BUILD_DIR)StandaloneFuzzTargetMain.c +HARNESS_OBJ:=$(BUILD_DIR)StandaloneFuzzTargetMain.o + +LDFLAGS += -lpthread + +TEST_BIN:=$(BUILD_DIR)decode_fuzzer +ifeq "$(shell uname)" "Darwin" +TEST_BIN_LDFLAGS:=-undefined dynamic_lookup -Wl,-no_pie +endif + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +TEST_DATA_SRC:=https://github.com/google/fuzzbench/blob/master/benchmarks/vorbis-2017-12-11/seeds/sound.ogg?raw=true +TEST_DATA_FILE:=$(TEST_DATA_DIR)sound.ogg +DUMMY_DATA_FILE:=$(BUILD_DIR)default_seed + +FRIDA_OUT:=$(BUILD_DIR)frida-out +QEMU_OUT:=$(BUILD_DIR)qemu-out + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +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 $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000aaaaaaaaa000) +endif + +ifeq "$(ARCH)" "x86_64" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x0000555555554000) +endif + +ifeq "$(ARCH)" "x86" + AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_BIN) LLVMFuzzerTestOneInput 0x56555000) +endif + +.PHONY: all clean frida hook + +all: $(TEST_BIN) + make -C $(ROOT)frida_mode/ + +32: + CXXFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +########## OGG ####### + +$(OGG_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(OGG_DIR): | $(OGG_BUILD_DIR) + git clone $(OGG_GIT_REPO) $@ + git -C $(OGG_DIR) checkout c8391c2b267a7faf9a09df66b1f7d324e9eb7766 + +$(OGG_LIB): | $(OGG_DIR) + cd $(OGG_DIR) && ./autogen.sh + cd $(OGG_DIR) && ./configure \ + --prefix=$(OGG_INSTALL) \ + --enable-static \ + --disable-shared \ + --disable-crc + make -C $(OGG_DIR) install + +ogg: $(OGG_LIB) + +########## VORBIS ####### + +$(VORBIS_BUILD_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(VORBIS_DIR): | $(VORBIS_BUILD_DIR) + git clone $(VORBIS_GIT_REPO) $@ + git -C $(VORBIS_DIR) checkout c1c2831fc7306d5fbd7bc800324efd12b28d327f + +$(VORBIS_LIB): $(OGG_LIB) | $(VORBIS_DIR) + cd $(VORBIS_DIR) && ./autogen.sh + cd $(VORBIS_DIR) && ./configure \ + --prefix=$(VORBIS_INSTALL) \ + --enable-static \ + --disable-shared \ + --with-ogg=$(OGG_INSTALL) + make -C $(VORBIS_DIR) install + +vorbis: $(VORBIS_LIB) + +########## HARNESS ####### + +$(DECODE_SRC): + wget -O $@ $(DECODE_URL) + +$(DECODE_OBJ): $(DECODE_SRC) + $(CXX) -o $@ -c $< -I$(VORBIS_DIR)include/ -I$(OGG_DIR)include/ + +decode: $(DECODE_OBJ) + +########## HARNESS ####### + +$(HARNESS_SRC): + wget -O $@ $(HARNESS_URL) + +$(HARNESS_OBJ): $(HARNESS_SRC) + $(CC) -o $@ -c $< + +harness: $(HARNESS_OBJ) + +########## TEST ####### + +$(TEST_BIN): $(VORBIS_LIB) $(OGG_LIB) $(HARNESS_OBJ) $(DECODE_OBJ) + $(CXX) \ + $(CXXFLAGS) \ + -std=c++11 \ + $(DECODE_OBJ) \ + $(HARNESS_OBJ) \ + $(VORBISFILE_LIB) \ + $(VORBIS_LIB) \ + $(OGG_LIB) \ + -o $@ + +########## DUMMY ####### + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(DUMMY_DATA_FILE): | $(TEST_DATA_DIR) + dd if=/dev/zero bs=1048576 count=1 of=$@ + +###### TEST DATA ####### + +$(TEST_DATA_FILE): + wget -O $@ $(TEST_DATA_SRC) + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TEST_BIN) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(TEST_DATA_FILE) $(DUMMY_DATA_FILE) + AFL_FRIDA_PERSISTENT_CNT=1000000 \ + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -m none \ + -d \ + -O \ + -V 30 \ + -- \ + $(TEST_BIN) $(DUMMY_DATA_FILE) + +qemu: $(TEST_BIN) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(TEST_DATA_FILE) $(DUMMY_DATA_FILE) + AFL_QEMU_PERSISTENT_CNT=1000000 \ + AFL_QEMU_PERSISTENT_HOOK=$(AFLPP_QEMU_DRIVER_HOOK_OBJ) \ + AFL_QEMU_PERSISTENT_ADDR=$(AFL_QEMU_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_QEMU_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -i $(TEST_DATA_DIR) \ + -o $(QEMU_OUT) \ + -m none \ + -d \ + -Q \ + -V 30 \ + -- \ + $(TEST_BIN) $(DUMMY_DATA_FILE) diff --git a/frida_mode/test/vorbis/Makefile b/frida_mode/test/vorbis/Makefile new file mode 100644 index 00000000..07b139e9 --- /dev/null +++ b/frida_mode/test/vorbis/Makefile @@ -0,0 +1,13 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida diff --git a/frida_mode/test/vorbis/get_symbol_addr.py b/frida_mode/test/vorbis/get_symbol_addr.py new file mode 100755 index 00000000..1c46e010 --- /dev/null +++ b/frida_mode/test/vorbis/get_symbol_addr.py @@ -0,0 +1,36 @@ +#!/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/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index 3639d670..0473cbf6 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/frida_mode/ts/lib/afl.ts @@ -179,6 +179,14 @@ class Afl { Afl.jsApiSetInstrumentUnstableCoverageFile(buf); } + /* + * Set a callback to be called in place of the usual `main` function. This see + * `Scripting.md` for details. + */ + public static setJsMainHook(address: NativePointer): void { + Afl.jsApiSetJsMainHook(address); + } + /** * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a * `NativePointer` should be provided as it's argument. @@ -241,6 +249,13 @@ class Afl { Afl.jsApiSetSeccompFile(buf); } + /** + * See `AFL_FRIDA_STALKER_ADJACENT_BLOCKS`. + */ + public static setStalkerAdjacentBlocks(val: number): void { + Afl.jsApiSetStalkerAdjacentBlocks(val); + } + /* * Set a function to be called for each instruction which is instrumented * by AFL FRIDA mode. @@ -380,6 +395,11 @@ class Afl { "void", ["pointer"]); + private static readonly jsApiSetJsMainHook = Afl.jsApiGetFunction( + "js_api_set_js_main_hook", + "void", + ["pointer"]); + private static readonly jsApiSetPersistentAddress = Afl.jsApiGetFunction( "js_api_set_persistent_address", "void", @@ -420,6 +440,11 @@ class Afl { "void", ["pointer"]); + private static readonly jsApiSetStalkerAdjacentBlocks = Afl.jsApiGetFunction( + "js_api_set_stalker_adjacent_blocks", + "void", + ["uint32"]); + private static readonly jsApiSetStalkerCallback = Afl.jsApiGetFunction( "js_api_set_stalker_callback", "void", |
