diff options
69 files changed, 1431 insertions, 276 deletions
diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index 2f637412..fdacff62 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -6,6 +6,11 @@ INCLUDES:=$(wildcard $(INC_DIR)*.h) BUILD_DIR:=$(PWD)build/ OBJ_DIR:=$(BUILD_DIR)obj/ +JS_DIR:=$(SRC_DIR)js/ +JS_NAME:=api.js +JS:=$(JS_DIR)$(JS_NAME) +JS_SRC:=$(BUILD_DIR)api.c +JS_OBJ:=$(BUILD_DIR)api.o SOURCES:=$(wildcard $(SRC_DIR)**/*.c) $(wildcard $(SRC_DIR)*.c) OBJS:=$(foreach src,$(SOURCES),$(OBJ_DIR)$(notdir $(patsubst %.c, %.o, $(src)))) CFLAGS+=-fPIC \ @@ -71,25 +76,25 @@ ifndef OS endif GUM_DEVKIT_VERSION=14.2.18 -GUM_DEVKIT_FILENAME=frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar.xz +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)" GUM_DEVKIT_TARBALL:=$(FRIDA_BUILD_DIR)$(GUM_DEVKIT_FILENAME) -GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gum.a -GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gum.h +GUM_DEVIT_LIBRARY=$(FRIDA_BUILD_DIR)libfrida-gumjs.a +GUM_DEVIT_HEADER=$(FRIDA_BUILD_DIR)frida-gumjs.h FRIDA_DIR:=$(PWD)build/frida-source/ FRIDA_MAKEFILE:=$(FRIDA_DIR)Makefile -FRIDA_GUM:=$(FRIDA_DIR)build/frida-linux-x86_64/lib/libfrida-gum-1.0.a +FRIDA_GUM:=$(FRIDA_DIR)build/frida-linux-x86_64/lib/libfrida-gumjs-1.0.a FRIDA_GUM_DEVKIT_DIR:=$(FRIDA_DIR)build/gum-devkit/ -FRIDA_GUM_DEVKIT_HEADER:=$(FRIDA_GUM_DEVKIT_DIR)frida-gum.h -FRIDA_GUM_DEVKIT_TARBALL:=$(FRIDA_DIR)build/frida-gum-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar +FRIDA_GUM_DEVKIT_HEADER:=$(FRIDA_GUM_DEVKIT_DIR)frida-gumjs.h +FRIDA_GUM_DEVKIT_TARBALL:=$(FRIDA_DIR)build/frida-gumjs-devkit-$(GUM_DEVKIT_VERSION)-$(OS)-$(ARCH).tar 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) +.PHONY: all 32 clean format $(FRIDA_GUM) quickjs ############################## ALL ############################################# @@ -113,7 +118,7 @@ $(FRIDA_GUM): $(FRIDA_MAKEFILE) cd $(FRIDA_DIR) && make gum-linux-$(ARCH) $(FRIDA_GUM_DEVKIT_HEADER): $(FRIDA_GUM) - $(FRIDA_DIR)releng/devkit.py frida-gum linux-$(ARCH) $(FRIDA_DIR)build/gum-devkit/ + $(FRIDA_DIR)releng/devkit.py frida-gumjs linux-$(ARCH) $(FRIDA_DIR)build/gum-devkit/ $(FRIDA_GUM_DEVKIT_TARBALL): $(FRIDA_GUM_DEVKIT_HEADER) cd $(FRIDA_GUM_DEVKIT_DIR) && tar cvf $(FRIDA_GUM_DEVKIT_TARBALL) . @@ -150,6 +155,20 @@ $(AFL_COMPILER_RT_OBJ): $(AFL_COMPILER_RT_SRC) -o $@ \ -c $< +############################### JS ############################################# + +$(JS_SRC): $(JS) | $(BUILD_DIR) + cd $(JS_DIR) && xxd -i $(JS_NAME) $@ + +$(JS_OBJ): $(JS_SRC) + $(CC) \ + $(CFLAGS) \ + -I $(ROOT)include \ + -I $(FRIDA_BUILD_DIR) \ + -I $(INC_DIR) \ + -c $< \ + -o $@ + ############################# SOURCE ########################################### define BUILD_SOURCE @@ -167,9 +186,10 @@ $(foreach src,$(SOURCES),$(eval $(call BUILD_SOURCE,$(src),$(OBJ_DIR)$(notdir $( ######################## AFL-FRIDA-TRACE ####################################### -$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR) - $(CC) \ +$(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL_COMPILER_RT_OBJ) GNUmakefile | $(BUILD_DIR) + $(CXX) \ $(OBJS) \ + $(JS_OBJ) \ $(GUM_DEVIT_LIBRARY) \ $(AFL_COMPILER_RT_OBJ) \ $(LDFLAGS) \ diff --git a/frida_mode/README.md b/frida_mode/README.md index 296e6405..6bed52b7 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -78,6 +78,10 @@ following options are currently supported: To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`. +## Scripting + +One of the more powerful features of FRIDA mode is it's support for configuration by JavaScript, rather than using environment variables. For details of how this works see [here](Scripting.md). + ## Performance Additionally, the intention is to be able to make a direct performance diff --git a/frida_mode/Scripting.md b/frida_mode/Scripting.md new file mode 100644 index 00000000..8b961e18 --- /dev/null +++ b/frida_mode/Scripting.md @@ -0,0 +1,240 @@ +# Scripting +FRIDA now supports the ability to configure itself using JavaScript. This allows +the user to make use of the convenience of FRIDA's scripting engine (along with +it's support for debug symbols and exports) to configure all of the things which +were traditionally configured using environment variables. + +By default FRIDA mode will look for the file `afl.js` in the current working +directory of the target. Alternatively, a script file can be configured using +the environment variable `AFL_FRIDA_JS_SCRIPT`. + +This script can make use of all of the standard [frida api functions](https://frida.re/docs/javascript-api/), but FRIDA mode adds some additional functions to allow +you to interact with FRIDA mode itself. These can all be accessed via the global +`Afl` parameter. e.g. `Afl.print("HELLO WORLD");`, + +If you encounter a problem with your script, then you should set the environment +variable `AFL_DEBUG_CHILD=1` to view any diagnostic information. + + +# Example +Most of the time, users will likely be wanting to call the functions which configure an address (e.g. for the entry point, or the persistent address). + +The example below uses the API [`DebugSymbol.fromName()`](https://frida.re/docs/javascript-api/#debugsymbol). Another use API is [`Module.getExportByName()`](https://frida.re/docs/javascript-api/#module). + +```js +/* Use Afl.print instead of console.log */ +Afl.print('******************'); +Afl.print('* AFL FRIDA MODE *'); +Afl.print('******************'); +Afl.print(''); + +/* Print some useful diagnostics stuff */ +Afl.print(`PID: ${Process.id}`); + +new ModuleMap().values().forEach(m => { + Afl.print(`${m.base}-${m.base.add(m.size)} ${m.name}`); +}); + +/* + * Configure entry-point, persistence etc. This will be what most + * people want to do. + */ +const persistent_addr = DebugSymbol.fromName('main'); +Afl.print(`persistent_addr: ${persistent_addr.address}`); + +if (persistent_addr.address.equals(ptr(0))) { + Afl.error('Cannot find symbol main'); +} + +const persistent_ret = DebugSymbol.fromName('slow'); +Afl.print(`persistent_ret: ${persistent_ret.address}`); + +if (persistent_ret.address.equals(ptr(0))) { + Afl.error('Cannot find symbol slow'); +} + +Afl.setPersistentAddress(persistent_addr.address); +Afl.setPersistentReturn(persistent_ret.address); +Afl.setPersistentCount(1000000); + +/* Control instrumentation, you may want to do this too */ +Afl.setInstrumentLibraries(); +const mod = Process.findModuleByName("libc-2.31.so") +Afl.addExcludedRange(mod.base, mod.size); + +/* Some useful options to configure logging */ +Afl.setStdOut("/tmp/stdout.txt"); +Afl.setStdErr("/tmp/stderr.txt"); + +/* Show the address layout. Sometimes helpful */ +Afl.setDebugMaps(); + +/* + * If you are using these options, then things aren't going + * very well for you. + */ +Afl.setInstrumentDebugFile("/tmp/instr.log"); +Afl.setPrefetchDisable(); +Afl.setInstrumentNoOptimize(); +Afl.setInstrumentEnableTracing(); +Afl.setInstrumentTracingUnique(); +Afl.setStatsFile("/tmp/stats.txt"); +Afl.setStatsInterval(1); +Afl.setStatsTransitions(); + +/* *ALWAYS* call this when you have finished all your configuration */ +Afl.done(); +Afl.print("done"); +``` + +# Stripped Binaries + +Lastly, if the binary you attempting to fuzz has no symbol information, and no +exports, then the following approach can be used. + +```js +const module = Process.getModuleByName('target.exe'); +/* Hardcoded offset within the target image */ +const address = module.base.add(0xdeadface); +Afl.setPersistentAddress(address); +``` + +# API +```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); + +/* + * 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. + */ +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(); + +/* + * 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); + +/* + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_ADDR`, again a + * `NativePointer` should be provided as it's argument. + */ +Afl.setPersistentAddress(address); + +/* + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_RET`, again a + * `NativePointer` should be provided as it's argument. + */ +Afl.setPersistentReturn(address); + +/* + * This is equivalent to setting `AFL_FRIDA_PERSISTENT_CNT`, a + * `number` should be provided as it's argument. + */ +Afl.setPersistentCount(count); + +/* + * See `AFL_FRIDA_PERSISTENT_DEBUG`. + */ +Afl.setPersistentDebug(); + +/* + * See `AFL_FRIDA_DEBUG_MAPS`. + */ +Afl.setDebugMaps(); + +/* + * 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); + +/* + * 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(); + +/* + * See `AFL_FRIDA_INST_DEBUG_FILE`. This function takes a single `string` as + * an argument. + */ +Afl.setInstrumentDebugFile(file); + +/* + * See `AFL_FRIDA_INST_NO_PREFETCH`. + */ +Afl.setPrefetchDisable(); + +/* + * See `AFL_FRIDA_INST_NO_OPTIMIZE` + */ +Afl.setInstrumentNoOptimize(); + +/* + * See `AFL_FRIDA_INST_TRACE`. + */ +Afl.setInstrumentEnableTracing(); + +/* + * See `AFL_FRIDA_INST_TRACE_UNIQUE`. + */ +Afl.setInstrumentTracingUnique() + +/* + * See `AFL_FRIDA_OUTPUT_STDOUT`. This function takes a single `string` as + * an argument. + */ +Afl.setStdOut(file); + +/* + * See `AFL_FRIDA_OUTPUT_STDERR`. This function takes a single `string` as + * an argument. + */ +Afl.setStdErr(file); + +/* + * See `AFL_FRIDA_STATS_FILE`. This function takes a single `string` as + * an argument. + */ +Afl.setStatsFile(file); + +/* + * See `AFL_FRIDA_STATS_INTERVAL`. This function takes a `number` as an + * argument + */ +Afl.setStatsInterval(interval); + +/* + * See `AFL_FRIDA_STATS_TRANSITIONS` + */ +Afl.setStatsTransitions() +``` diff --git a/frida_mode/include/asan.h b/frida_mode/include/asan.h index 7a8726e0..67d33591 100644 --- a/frida_mode/include/asan.h +++ b/frida_mode/include/asan.h @@ -1,10 +1,11 @@ #ifndef _ASAN_H #define _ASAN_H -#include "frida-gum.h" +#include "frida-gumjs.h" extern gboolean asan_initialized; +void asan_config(void); void asan_init(void); void asan_arch_init(void); void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator); diff --git a/frida_mode/include/ctx.h b/frida_mode/include/ctx.h index 67274aee..c669478e 100644 --- a/frida_mode/include/ctx.h +++ b/frida_mode/include/ctx.h @@ -1,7 +1,7 @@ #ifndef _CTX_H #define _CTX_H -#include "frida-gum.h" +#include "frida-gumjs.h" #if defined(__x86_64__) gsize ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg); diff --git a/frida_mode/include/entry.h b/frida_mode/include/entry.h index 967831af..801c2bbe 100644 --- a/frida_mode/include/entry.h +++ b/frida_mode/include/entry.h @@ -1,13 +1,15 @@ #ifndef _ENTRY_H #define _ENTRY_H -#include "frida-gum.h" +#include "frida-gumjs.h" -extern guint64 entry_start; +extern guint64 entry_point; + +void entry_config(void); void entry_init(void); -void entry_run(void); +void entry_start(void); void entry_prologue(GumStalkerIterator *iterator, GumStalkerOutput *output); diff --git a/frida_mode/include/frida_cmplog.h b/frida_mode/include/frida_cmplog.h index b620a472..a665e970 100644 --- a/frida_mode/include/frida_cmplog.h +++ b/frida_mode/include/frida_cmplog.h @@ -3,6 +3,7 @@ extern struct cmp_map *__afl_cmp_map; +void cmplog_config(void); void cmplog_init(void); /* Functions to be implemented by the different architectures */ diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index 577481d1..9c8d3a5d 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -1,13 +1,20 @@ #ifndef _INSTRUMENT_H #define _INSTRUMENT_H -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" -extern __thread uint64_t previous_pc; -extern uint8_t * __afl_area_ptr; -extern uint32_t __afl_map_size; +extern char * instrument_debug_filename; +extern gboolean instrument_tracing; +extern gboolean instrument_optimize; +extern gboolean instrument_unique; +extern __thread uint64_t instrument_previous_pc; + +extern uint8_t *__afl_area_ptr; +extern uint32_t __afl_map_size; + +void instrument_config(void); void instrument_init(void); @@ -19,6 +26,7 @@ gboolean instrument_is_coverage_optimize_supported(void); void instrument_coverage_optimize(const cs_insn * instr, GumStalkerOutput *output); +void instrument_debug_config(void); void instrument_debug_init(void); void instrument_debug_start(uint64_t address, GumStalkerOutput *output); void instrument_debug_instruction(uint64_t address, uint16_t size); diff --git a/frida_mode/include/intercept.h b/frida_mode/include/intercept.h new file mode 100644 index 00000000..8fe93b10 --- /dev/null +++ b/frida_mode/include/intercept.h @@ -0,0 +1,11 @@ +#ifndef _INTERCEPTOR_H +#define _INTERCEPTOR_H + +#include "frida-gumjs.h" + +void intercept_hook(void *address, gpointer replacement, gpointer user_data); +void intercept_unhook(void *address); +void intercept_unhook_self(void); + +#endif + diff --git a/frida_mode/include/interceptor.h b/frida_mode/include/interceptor.h deleted file mode 100644 index 0ff754a4..00000000 --- a/frida_mode/include/interceptor.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _INTERCEPTOR_H -#define _INTERCEPTOR_H - -#include "frida-gum.h" - -void intercept(void *address, gpointer replacement, gpointer user_data); -void unintercept(void *address); -void unintercept_self(void); - -#endif - diff --git a/frida_mode/include/js.h b/frida_mode/include/js.h new file mode 100644 index 00000000..77237d55 --- /dev/null +++ b/frida_mode/include/js.h @@ -0,0 +1,18 @@ +#ifndef _JS_H +#define _JS_H + +#include "frida-gumjs.h" + +extern unsigned char api_js[]; +extern unsigned int api_js_len; + +extern gboolean js_done; + +/* Frida Mode */ + +void js_config(void); + +void js_start(void); + +#endif + diff --git a/frida_mode/include/lib.h b/frida_mode/include/lib.h index 237aecb0..a9d56e4e 100644 --- a/frida_mode/include/lib.h +++ b/frida_mode/include/lib.h @@ -1,7 +1,9 @@ #ifndef _LIB_H #define _LIB_H -#include "frida-gum.h" +#include "frida-gumjs.h" + +void lib_config(void); void lib_init(void); diff --git a/frida_mode/include/output.h b/frida_mode/include/output.h index 53a9fdd3..743b2fe6 100644 --- a/frida_mode/include/output.h +++ b/frida_mode/include/output.h @@ -1,8 +1,12 @@ #ifndef _OUTPUT_H #define _OUTPUT_H -#include "frida-gum.h" +#include "frida-gumjs.h" +extern char *output_stdout; +extern char *output_stderr; + +void output_config(void); void output_init(void); #endif diff --git a/frida_mode/include/persistent.h b/frida_mode/include/persistent.h index 25b44ab0..8f00196c 100644 --- a/frida_mode/include/persistent.h +++ b/frida_mode/include/persistent.h @@ -2,7 +2,7 @@ #ifndef _PERSISTENT_H #define _PERSISTENT_H -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" typedef struct arch_api_regs api_regs; @@ -19,9 +19,10 @@ extern unsigned char *__afl_fuzz_ptr; extern guint64 persistent_start; extern guint64 persistent_count; extern guint64 persistent_ret; -extern guint64 persistent_ret_offset; extern gboolean persistent_debug; -extern afl_persistent_hook_fn hook; +extern afl_persistent_hook_fn persistent_hook; + +void persistent_config(void); void persistent_init(void); diff --git a/frida_mode/include/prefetch.h b/frida_mode/include/prefetch.h index 8f0cee68..835d5e8a 100644 --- a/frida_mode/include/prefetch.h +++ b/frida_mode/include/prefetch.h @@ -1,8 +1,11 @@ #ifndef _PREFETCH_H #define _PREFETCH_H -#include "frida-gum.h" +#include "frida-gumjs.h" +extern gboolean prefetch_enable; + +void prefetch_config(void); void prefetch_init(void); void prefetch_write(void *addr); void prefetch_read(void); diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h index c623f473..a667fb76 100644 --- a/frida_mode/include/ranges.h +++ b/frida_mode/include/ranges.h @@ -1,13 +1,20 @@ #ifndef _RANGES_H #define _RANGES_H -#include "frida-gum.h" +#include "frida-gumjs.h" +extern gboolean ranges_debug_maps; +extern gboolean ranges_inst_libs; + +void ranges_config(void); void ranges_init(void); gboolean range_is_excluded(gpointer address); void ranges_exclude(); +void ranges_add_include(GumMemoryRange *range); +void ranges_add_exclude(GumMemoryRange *range); + #endif diff --git a/frida_mode/include/stalker.h b/frida_mode/include/stalker.h index 186ead11..2136fe52 100644 --- a/frida_mode/include/stalker.h +++ b/frida_mode/include/stalker.h @@ -1,8 +1,9 @@ #ifndef _STALKER_H #define _STALKER_H -#include "frida-gum.h" +#include "frida-gumjs.h" +void stalker_config(void); void stalker_init(void); GumStalker *stalker_get(void); void stalker_start(void); diff --git a/frida_mode/include/stats.h b/frida_mode/include/stats.h index 4271132a..1cfd6b8f 100644 --- a/frida_mode/include/stats.h +++ b/frida_mode/include/stats.h @@ -1,7 +1,7 @@ #ifndef _STATS_H #define _STATS_H -#include "frida-gum.h" +#include "frida-gumjs.h" typedef struct { @@ -15,6 +15,11 @@ typedef struct { extern stats_data_header_t *stats_data; +extern char * stats_filename; +extern guint64 stats_interval; +extern gboolean stats_transitions; + +void stats_config(void); void stats_init(void); void stats_collect(const cs_insn *instr, gboolean begin); void stats_print(char *format, ...); diff --git a/frida_mode/include/util.h b/frida_mode/include/util.h index 7b443b5e..525e9d40 100644 --- a/frida_mode/include/util.h +++ b/frida_mode/include/util.h @@ -1,7 +1,7 @@ #ifndef _UTIL_H #define _UTIL_H -#include "frida-gum.h" +#include "frida-gumjs.h" #define UNUSED_PARAMETER(x) (void)(x) #define IGNORED_RETURN(x) (void)!(x) diff --git a/frida_mode/src/asan/asan.c b/frida_mode/src/asan/asan.c index f78f690c..b2e763ca 100644 --- a/frida_mode/src/asan/asan.c +++ b/frida_mode/src/asan/asan.c @@ -1,18 +1,18 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" #include "asan.h" -gboolean asan_initialized = FALSE; +static gboolean asan_enabled = FALSE; +gboolean asan_initialized = FALSE; -void asan_init(void) { +void asan_config(void) { if (getenv("AFL_USE_FASAN") != NULL) { OKF("Frida ASAN mode enabled"); - asan_arch_init(); - asan_initialized = TRUE; + asan_enabled = TRUE; } else { @@ -22,3 +22,14 @@ void asan_init(void) { } +void asan_init(void) { + + if (asan_enabled) { + + asan_arch_init(); + asan_initialized = TRUE; + + } + +} + diff --git a/frida_mode/src/asan/asan_arm32.c b/frida_mode/src/asan/asan_arm32.c index 79475ced..f5fa4713 100644 --- a/frida_mode/src/asan/asan_arm32.c +++ b/frida_mode/src/asan/asan_arm32.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/asan/asan_arm64.c b/frida_mode/src/asan/asan_arm64.c index 66138e42..65524e03 100644 --- a/frida_mode/src/asan/asan_arm64.c +++ b/frida_mode/src/asan/asan_arm64.c @@ -1,5 +1,5 @@ #include <dlfcn.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/asan/asan_x64.c b/frida_mode/src/asan/asan_x64.c index a2eabe3c..5c12669f 100644 --- a/frida_mode/src/asan/asan_x64.c +++ b/frida_mode/src/asan/asan_x64.c @@ -1,5 +1,5 @@ #include <dlfcn.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/asan/asan_x86.c b/frida_mode/src/asan/asan_x86.c index 8490b490..6d2f9e2b 100644 --- a/frida_mode/src/asan/asan_x86.c +++ b/frida_mode/src/asan/asan_x86.c @@ -1,5 +1,5 @@ #include <dlfcn.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/cmplog/cmplog.c b/frida_mode/src/cmplog/cmplog.c index 8814f7f3..a2609c8e 100644 --- a/frida_mode/src/cmplog/cmplog.c +++ b/frida_mode/src/cmplog/cmplog.c @@ -5,7 +5,7 @@ #include <sys/syscall.h> #include <unistd.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" @@ -50,6 +50,10 @@ static void cmplog_get_ranges(void) { } +void cmplog_config(void) { + +} + void cmplog_init(void) { if (__afl_cmp_map != NULL) { OKF("CMPLOG mode enabled"); } @@ -94,10 +98,10 @@ static gboolean cmplog_contains(GumAddress inner_base, GumAddress inner_limit, gboolean cmplog_test_addr(guint64 addr, size_t size) { - if (g_hash_table_contains(hash_yes, (gpointer)addr)) { return true; } - if (g_hash_table_contains(hash_no, (gpointer)addr)) { return false; } + if (g_hash_table_contains(hash_yes, GSIZE_TO_POINTER(addr))) { return true; } + if (g_hash_table_contains(hash_no, GSIZE_TO_POINTER(addr))) { return false; } - void * page_addr = (void *)(addr & page_mask); + void * page_addr = GSIZE_TO_POINTER(addr & page_mask); size_t page_offset = addr & page_offset_mask; /* If it spans a page, then bail */ @@ -109,7 +113,7 @@ gboolean cmplog_test_addr(guint64 addr, size_t size) { */ if (msync(page_addr, page_offset + size, MS_ASYNC) < 0) { - if (!g_hash_table_add(hash_no, (gpointer)addr)) { + if (!g_hash_table_add(hash_no, GSIZE_TO_POINTER(addr))) { FATAL("Failed - g_hash_table_add"); @@ -119,7 +123,7 @@ gboolean cmplog_test_addr(guint64 addr, size_t size) { } else { - if (!g_hash_table_add(hash_yes, (gpointer)addr)) { + if (!g_hash_table_add(hash_yes, GSIZE_TO_POINTER(addr))) { FATAL("Failed - g_hash_table_add"); diff --git a/frida_mode/src/cmplog/cmplog_arm32.c b/frida_mode/src/cmplog/cmplog_arm32.c index 5af28f3f..ac703408 100644 --- a/frida_mode/src/cmplog/cmplog_arm32.c +++ b/frida_mode/src/cmplog/cmplog_arm32.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/cmplog/cmplog_arm64.c b/frida_mode/src/cmplog/cmplog_arm64.c index 04631ff8..dd97f38d 100644 --- a/frida_mode/src/cmplog/cmplog_arm64.c +++ b/frida_mode/src/cmplog/cmplog_arm64.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" #include "cmplog.h" diff --git a/frida_mode/src/cmplog/cmplog_x64.c b/frida_mode/src/cmplog/cmplog_x64.c index ba16445d..0d18767a 100644 --- a/frida_mode/src/cmplog/cmplog_x64.c +++ b/frida_mode/src/cmplog/cmplog_x64.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" #include "cmplog.h" diff --git a/frida_mode/src/cmplog/cmplog_x86.c b/frida_mode/src/cmplog/cmplog_x86.c index a27df0af..dd666c34 100644 --- a/frida_mode/src/cmplog/cmplog_x86.c +++ b/frida_mode/src/cmplog/cmplog_x86.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" #include "cmplog.h" diff --git a/frida_mode/src/ctx/ctx_arm32.c b/frida_mode/src/ctx/ctx_arm32.c index a5c6f6d4..a354c117 100644 --- a/frida_mode/src/ctx/ctx_arm32.c +++ b/frida_mode/src/ctx/ctx_arm32.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/ctx/ctx_arm64.c b/frida_mode/src/ctx/ctx_arm64.c index d09896af..a735401b 100644 --- a/frida_mode/src/ctx/ctx_arm64.c +++ b/frida_mode/src/ctx/ctx_arm64.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/ctx/ctx_x64.c b/frida_mode/src/ctx/ctx_x64.c index 1772a252..da5cb13a 100644 --- a/frida_mode/src/ctx/ctx_x64.c +++ b/frida_mode/src/ctx/ctx_x64.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/ctx/ctx_x86.c b/frida_mode/src/ctx/ctx_x86.c index 9b50cb52..1a587702 100644 --- a/frida_mode/src/ctx/ctx_x86.c +++ b/frida_mode/src/ctx/ctx_x86.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/entry.c b/frida_mode/src/entry.c index e71386a0..186d5098 100644 --- a/frida_mode/src/entry.c +++ b/frida_mode/src/entry.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" @@ -9,27 +9,32 @@ extern void __afl_manual_init(); -guint64 entry_start = 0; +guint64 entry_point = 0; static void entry_launch(void) { __afl_manual_init(); /* Child here */ - previous_pc = 0; + instrument_previous_pc = 0; + +} + +void entry_config(void) { + + entry_point = util_read_address("AFL_ENTRYPOINT"); } void entry_init(void) { - entry_start = util_read_address("AFL_ENTRYPOINT"); - OKF("entry_point: 0x%016" G_GINT64_MODIFIER "X", entry_start); + OKF("entry_point: 0x%016" G_GINT64_MODIFIER "X", entry_point); } -void entry_run(void) { +void entry_start(void) { - if (entry_start == 0) { entry_launch(); } + if (entry_point == 0) { entry_launch(); } } diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index ba82b89f..d6ae505d 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -2,7 +2,7 @@ #include <sys/shm.h> #include <sys/mman.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" #include "debug.h" @@ -18,12 +18,13 @@ #include "stats.h" #include "util.h" -static gboolean tracing = false; -static gboolean optimize = false; -static gboolean unique = false; +gboolean instrument_tracing = false; +gboolean instrument_optimize = false; +gboolean instrument_unique = false; + static GumStalkerTransformer *transformer = NULL; -__thread uint64_t previous_pc = 0; +__thread uint64_t instrument_previous_pc = 0; static GumAddress previous_rip = 0; static u8 * edges_notified = NULL; @@ -61,7 +62,7 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, current_pc = (current_rip >> 4) ^ (current_rip << 8); current_pc &= MAP_SIZE - 1; - edge = current_pc ^ previous_pc; + edge = current_pc ^ instrument_previous_pc; cursor = &__afl_area_ptr[edge]; value = *cursor; @@ -77,11 +78,11 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, } *cursor = value; - previous_pc = current_pc >> 1; + instrument_previous_pc = current_pc >> 1; - if (unlikely(tracing)) { + if (unlikely(instrument_tracing)) { - if (!unique || edges_notified[edge] == 0) { + if (!instrument_unique || edges_notified[edge] == 0) { trace_debug("TRACE: edge: %10" G_GINT64_MODIFIER "d, current_rip: 0x%016" G_GINT64_MODIFIER @@ -90,7 +91,7 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, } - if (unique) { edges_notified[edge] = 1; } + if (instrument_unique) { edges_notified[edge] = 1; } previous_rip = current_rip; @@ -98,8 +99,9 @@ __attribute__((hot)) static void on_basic_block(GumCpuContext *context, } -static void instr_basic_block(GumStalkerIterator *iterator, - GumStalkerOutput *output, gpointer user_data) { +static void instrument_basic_block(GumStalkerIterator *iterator, + GumStalkerOutput * output, + gpointer user_data) { UNUSED_PARAMETER(user_data); @@ -111,7 +113,7 @@ static void instr_basic_block(GumStalkerIterator *iterator, if (unlikely(begin)) { instrument_debug_start(instr->address, output); } - if (instr->address == entry_start) { entry_prologue(iterator, output); } + if (instr->address == entry_point) { entry_prologue(iterator, output); } if (instr->address == persistent_start) { persistent_prologue(output); } if (instr->address == persistent_ret) { persistent_epilogue(output); } @@ -150,7 +152,7 @@ static void instr_basic_block(GumStalkerIterator *iterator, if (likely(!excluded)) { - if (likely(optimize)) { + if (likely(instrument_optimize)) { instrument_coverage_optimize(instr, output); @@ -185,31 +187,39 @@ static void instr_basic_block(GumStalkerIterator *iterator, } -void instrument_init(void) { +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_debug_config(); + asan_config(); + cmplog_config(); - optimize = (getenv("AFL_FRIDA_INST_NO_OPTIMIZE") == NULL); - tracing = (getenv("AFL_FRIDA_INST_TRACE") != NULL); - unique = (getenv("AFL_FRIDA_INST_TRACE_UNIQUE") != NULL); +} + +void instrument_init(void) { - if (!instrument_is_coverage_optimize_supported()) optimize = false; + if (!instrument_is_coverage_optimize_supported()) instrument_optimize = false; - OKF("Instrumentation - optimize [%c]", optimize ? 'X' : ' '); - OKF("Instrumentation - tracing [%c]", tracing ? 'X' : ' '); - OKF("Instrumentation - unique [%c]", unique ? 'X' : ' '); + OKF("Instrumentation - optimize [%c]", instrument_optimize ? 'X' : ' '); + OKF("Instrumentation - tracing [%c]", instrument_tracing ? 'X' : ' '); + OKF("Instrumentation - unique [%c]", instrument_unique ? 'X' : ' '); - if (tracing && optimize) { + if (instrument_tracing && instrument_optimize) { FATAL("AFL_FRIDA_INST_TRACE requires AFL_FRIDA_INST_NO_OPTIMIZE"); } - if (unique && optimize) { + if (instrument_unique && instrument_optimize) { FATAL("AFL_FRIDA_INST_TRACE_UNIQUE requires AFL_FRIDA_INST_NO_OPTIMIZE"); } - if (unique) { tracing = TRUE; } + if (instrument_unique) { instrument_tracing = TRUE; } if (__afl_map_size != 0x10000) { @@ -217,10 +227,10 @@ void instrument_init(void) { } - transformer = - gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + transformer = gum_stalker_transformer_make_from_callback( + instrument_basic_block, NULL, NULL); - if (unique) { + if (instrument_unique) { int shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600); if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c index 450a69a3..0e15940a 100644 --- a/frida_mode/src/instrument/instrument_arm32.c +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c index 49ee86a2..17f97c97 100644 --- a/frida_mode/src/instrument/instrument_arm64.c +++ b/frida_mode/src/instrument/instrument_arm64.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" #include "debug.h" @@ -72,7 +72,7 @@ void instrument_coverage_optimize(const cs_insn * instr, gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); uint8_t **afl_area_ptr_ptr = &__afl_area_ptr; - uint64_t *afl_prev_loc_ptr = &previous_pc; + uint64_t *afl_prev_loc_ptr = &instrument_previous_pc; gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr, sizeof(afl_area_ptr_ptr)); gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c index 0ce26a1c..b8cca634 100644 --- a/frida_mode/src/instrument/instrument_debug.c +++ b/frida_mode/src/instrument/instrument_debug.c @@ -3,7 +3,7 @@ #include <stdio.h> #include <unistd.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" @@ -13,6 +13,8 @@ static int debugging_fd = -1; static gpointer instrument_gen_start = NULL; +char *instrument_debug_filename = NULL; + static void instrument_debug(char *format, ...) { va_list ap; @@ -79,18 +81,25 @@ static void instrument_disasm(guint8 *start, guint8 *end) { } +void instrument_debug_config(void) { + + instrument_debug_filename = getenv("AFL_FRIDA_INST_DEBUG_FILE"); + +} + void instrument_debug_init(void) { - char *filename = getenv("AFL_FRIDA_INST_DEBUG_FILE"); - OKF("Instrumentation debugging - enabled [%c]", filename == NULL ? ' ' : 'X'); + OKF("Instrumentation debugging - enabled [%c]", + instrument_debug_filename == NULL ? ' ' : 'X'); - if (filename == NULL) { return; } + if (instrument_debug_filename == NULL) { return; } - OKF("Instrumentation debugging - file [%s]", filename); + OKF("Instrumentation debugging - file [%s]", instrument_debug_filename); - if (filename == NULL) { return; } + if (instrument_debug_filename == NULL) { return; } - char *path = g_canonicalize_filename(filename, g_get_current_dir()); + char *path = + g_canonicalize_filename(instrument_debug_filename, g_get_current_dir()); OKF("Instrumentation debugging - path [%s]", path); diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c index 7000e65d..a38b5b14 100644 --- a/frida_mode/src/instrument/instrument_x64.c +++ b/frida_mode/src/instrument/instrument_x64.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" @@ -68,7 +68,7 @@ void instrument_coverage_optimize(const cs_insn * instr, current_log_impl = cw->pc; gum_x86_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code)); - uint64_t *afl_prev_loc_ptr = &previous_pc; + uint64_t *afl_prev_loc_ptr = &instrument_previous_pc; gum_x86_writer_put_bytes(cw, (const guint8 *)&__afl_area_ptr, sizeof(__afl_area_ptr)); gum_x86_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr, diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c index 04a19e08..3c3dc272 100644 --- a/frida_mode/src/instrument/instrument_x86.c +++ b/frida_mode/src/instrument/instrument_x86.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" @@ -16,7 +16,7 @@ static void instrument_coverage_function(GumX86Writer *cw) { gum_x86_writer_put_push_reg(cw, GUM_REG_EDX); gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX, - GUM_ADDRESS(&previous_pc)); + 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); diff --git a/frida_mode/src/interceptor.c b/frida_mode/src/intercept.c index d2802752..ed8d27bd 100644 --- a/frida_mode/src/interceptor.c +++ b/frida_mode/src/intercept.c @@ -1,10 +1,10 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" -#include "interceptor.h" +#include "intercept.h" -void intercept(void *address, gpointer replacement, gpointer user_data) { +void intercept_hook(void *address, gpointer replacement, gpointer user_data) { GumInterceptor *interceptor = gum_interceptor_obtain(); gum_interceptor_begin_transaction(interceptor); @@ -15,7 +15,7 @@ void intercept(void *address, gpointer replacement, gpointer user_data) { } -void unintercept(void *address) { +void intercept_unhook(void *address) { GumInterceptor *interceptor = gum_interceptor_obtain(); @@ -26,10 +26,10 @@ void unintercept(void *address) { } -void unintercept_self(void) { +void intercept_unhook_self(void) { GumInvocationContext *ctx = gum_interceptor_get_current_invocation(); - unintercept(ctx->function); + intercept_unhook(ctx->function); } diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js new file mode 100644 index 00000000..983f1efa --- /dev/null +++ b/frida_mode/src/js/api.js @@ -0,0 +1,201 @@ +const write = new NativeFunction( + Module.getExportByName(null, 'write'), + 'int', + ['int', 'pointer', 'int'] +); + +const afl_frida_trace = Process.findModuleByName('afl-frida-trace.so'); + +function get_api(name, ret, args) { + const addr = afl_frida_trace.findExportByName(name); + return new NativeFunction(addr, ret, args); +} + +const js_api_done = get_api( + 'js_api_done', + 'void', + []); + +const js_api_error = get_api( + 'js_api_error', + 'void', + ['pointer']); + +const js_api_set_entrypoint = get_api( + 'js_api_set_entrypoint', + 'void', + ['pointer']); + +const js_api_set_persistent_address = get_api( + 'js_api_set_persistent_address', + 'void', + ['pointer']); + +const js_api_set_persistent_return = get_api( + 'js_api_set_persistent_return', + 'void', + ['pointer']); + +const js_api_set_persistent_count = get_api( + 'js_api_set_persistent_count', + 'void', + ['uint64']); + +const js_api_set_persistent_debug = get_api( + 'js_api_set_persistent_debug', + 'void', + []); + +const js_api_set_debug_maps = get_api( + 'js_api_set_debug_maps', + 'void', + []); + +const js_api_add_include_range = get_api( + 'js_api_add_include_range', + 'void', + ['pointer', 'size_t']); + +const js_api_add_exclude_range = get_api( + 'js_api_add_exclude_range', + 'void', + ['pointer', 'size_t']); + +const js_api_set_instrument_libraries = get_api( + 'js_api_set_instrument_libraries', + 'void', + []); + +const js_api_set_instrument_debug_file = get_api( + 'js_api_set_instrument_debug_file', + 'void', + ['pointer']); + +const js_api_set_prefetch_disable = get_api( + 'js_api_set_prefetch_disable', + 'void', + []); + +const js_api_set_instrument_no_optimize = get_api( + 'js_api_set_instrument_no_optimize', + 'void', + []); + +const js_api_set_instrument_trace = get_api( + 'js_api_set_instrument_trace', + 'void', + []); + +const js_api_set_instrument_trace_unique = get_api( + 'js_api_set_instrument_trace_unique', + 'void', + []); + +const js_api_set_stdout = get_api( + 'js_api_set_stdout', + 'void', + ['pointer']); + +const js_api_set_stderr = get_api( + 'js_api_set_stderr', + 'void', + ['pointer']); + +const js_api_set_stats_file = get_api( + 'js_api_set_stats_file', + 'void', + ['pointer']); + +const js_api_set_stats_interval = get_api( + 'js_api_set_stats_interval', + 'void', + ['uint64']); + +const js_api_set_stats_transitions = get_api( + 'js_api_set_stats_transitions', + 'void', + []); + +const afl = { + print: function (msg) { + const STDOUT_FILENO = 2; + const log = `${msg}\n`; + const buf = Memory.allocUtf8String(log); + write(STDOUT_FILENO, buf, log.length); + }, + done: function() { + js_api_done(); + }, + error: function(msg) { + const buf = Memory.allocUtf8String(msg); + js_api_error(buf); + }, + setEntryPoint: function(addr) { + js_api_set_entrypoint(addr); + }, + setPersistentAddress: function(addr) { + js_api_set_persistent_address(addr); + }, + setPersistentReturn: function(addr) { + js_api_set_persistent_return(addr); + }, + setPersistentCount: function(addr) { + js_api_set_persistent_count(addr); + }, + setPersistentDebug: function() { + js_api_set_persistent_debug(); + }, + setDebugMaps: function() { + js_api_set_debug_maps(); + }, + addIncludedRange: function(address, size) { + js_api_add_include_range(address, size); + }, + addExcludedRange: function(address, size) { + js_api_add_exclude_range(address, size); + }, + setInstrumentLibraries: function() { + js_api_set_instrument_libraries(); + }, + setInstrumentDebugFile: function(file) { + const buf = Memory.allocUtf8String(file); + js_api_set_instrument_debug_file(buf) + }, + setPrefetchDisable: function() { + js_api_set_prefetch_disable(); + }, + setInstrumentNoOptimize: function() { + js_api_set_instrument_no_optimize(); + }, + setInstrumentEnableTracing: function() { + js_api_set_instrument_trace(); + }, + setInstrumentTracingUnique: function() { + js_api_set_instrument_trace_unique(); + }, + setStdOut: function(file) { + const buf = Memory.allocUtf8String(file); + js_api_set_stdout(buf) + }, + setStdErr: function(file) { + const buf = Memory.allocUtf8String(file); + js_api_set_stderr(buf) + }, + setStatsFile: function(file) { + const buf = Memory.allocUtf8String(file); + js_api_set_stats_file(buf) + }, + setStatsInterval: function(interval) { + js_api_set_stats_interval(interval); + }, + setStatsTransitions: function() { + js_api_set_stats_transitions(); + } + +}; + +Object.defineProperty(global, 'Afl', {value: afl, writeable: false}); + +//////////////////////////////////////////////////////////////////////////////// +// END OF API // +//////////////////////////////////////////////////////////////////////////////// diff --git a/frida_mode/src/js/js.c b/frida_mode/src/js/js.c new file mode 100644 index 00000000..79e716ad --- /dev/null +++ b/frida_mode/src/js/js.c @@ -0,0 +1,113 @@ +#include "frida-gumjs.h" + +#include "debug.h" + +#include "js.h" +#include "util.h" + +static char *js_script = NULL; +gboolean js_done = FALSE; + +static gchar * filename = "afl.js"; +static gchar * contents; +static GumScriptBackend *backend; +static GCancellable * cancellable = NULL; +static GError * error = NULL; +static GumScript * script; + +static void js_msg(GumScript *script, const gchar *message, GBytes *data, + gpointer user_data) { + + UNUSED_PARAMETER(script); + UNUSED_PARAMETER(data); + UNUSED_PARAMETER(user_data); + OKF("%s", message); + +} + +void js_config(void) { + + js_script = getenv("AFL_FRIDA_JS_SCRIPT"); + +} + +static gchar *js_get_script() { + + gsize length; + if (js_script != NULL) { filename = js_script; } + + filename = g_canonicalize_filename(filename, g_get_current_dir()); + + if (!g_file_get_contents(filename, &contents, &length, NULL)) { + + if (js_script == NULL) { + + return NULL; + + } else { + + FATAL("Could not load script file: %s", filename); + + } + + } else { + + OKF("Loaded AFL script: %s, %" G_GSIZE_MODIFIER "d bytes", filename, + length); + + gchar *source = g_malloc0(api_js_len + length + 1); + memcpy(source, api_js, api_js_len); + memcpy(&source[api_js_len], contents, length); + + return source; + + } + +} + +static void js_print_script(gchar *source) { + + gchar **split = g_strsplit(source, "\n", 0); + + for (size_t i = 0; split[i] != NULL; i++) { + + OKF("%3" G_GSIZE_MODIFIER "d. %s", i + 1, split[i]); + + } + + g_strfreev(split); + +} + +void js_start(void) { + + GMainContext *context; + + gchar *source = js_get_script(); + if (source == NULL) { return; } + js_print_script(source); + + backend = gum_script_backend_obtain_qjs(); + + script = gum_script_backend_create_sync(backend, "example", source, + cancellable, &error); + + if (error != NULL) { + + g_printerr("%s\n", error->message); + FATAL("Error processing script"); + + } + + gum_script_set_message_handler(script, js_msg, NULL, NULL); + + gum_script_load_sync(script, cancellable); + + context = g_main_context_get_thread_default(); + while (g_main_context_pending(context)) + g_main_context_iteration(context, FALSE); + + if (!js_done) { FATAL("Script didn't call Afl.done()"); } + +} + diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c new file mode 100644 index 00000000..018c0b9a --- /dev/null +++ b/frida_mode/src/js/js_api.c @@ -0,0 +1,142 @@ +#include "debug.h" + +#include "entry.h" +#include "instrument.h" +#include "js.h" +#include "output.h" +#include "persistent.h" +#include "prefetch.h" +#include "ranges.h" +#include "stats.h" +#include "util.h" + +void js_api_done() { + + js_done = TRUE; + +} + +void js_api_error(char *msg) { + + FATAL("%s", msg); + +} + +void js_api_set_entrypoint(void *address) { + + entry_point = GPOINTER_TO_SIZE(address); + +} + +void js_api_set_persistent_address(void *address) { + + persistent_start = GPOINTER_TO_SIZE(address); + +} + +void js_api_set_persistent_return(void *address) { + + persistent_ret = GPOINTER_TO_SIZE(address); + +} + +void js_api_set_persistent_count(uint64_t count) { + + persistent_count = count; + +} + +void js_api_set_persistent_debug() { + + persistent_debug = TRUE; + +} + +void js_api_set_debug_maps() { + + ranges_debug_maps = TRUE; + +} + +void js_api_add_include_range(void *address, gsize size) { + + GumMemoryRange range = {.base_address = GUM_ADDRESS(address), .size = size}; + ranges_add_include(&range); + +} + +void js_api_add_exclude_range(void *address, gsize size) { + + GumMemoryRange range = {.base_address = GUM_ADDRESS(address), .size = size}; + ranges_add_exclude(&range); + +} + +void js_api_set_instrument_libraries() { + + ranges_inst_libs = TRUE; + +} + +void js_api_set_instrument_debug_file(char *path) { + + instrument_debug_filename = g_strdup(path); + +} + +void js_api_set_prefetch_disable(void) { + + prefetch_enable = FALSE; + +} + +void js_api_set_instrument_no_optimize(void) { + + instrument_optimize = FALSE; + +} + +void js_api_set_instrument_trace(void) { + + instrument_tracing = TRUE; + +} + +void js_api_set_instrument_trace_unique(void) { + + instrument_unique = TRUE; + +} + +void js_api_set_stdout(char *file) { + + output_stdout = g_strdup(file); + +} + +void js_api_set_stderr(char *file) { + + output_stderr = g_strdup(file); + +} + +void js_api_set_stats_file(char *file) { + + stats_filename = g_strdup(file); + +} + +void js_api_set_stats_interval(uint64_t interval) { + + stats_interval = interval; + +} + +void js_api_set_stats_transitions() { + + stats_transitions = TRUE; + +} + +// "AFL_FRIDA_PERSISTENT_HOOK", + diff --git a/frida_mode/src/lib/lib.c b/frida_mode/src/lib/lib.c index 13a7d1e7..59a3fcf9 100644 --- a/frida_mode/src/lib/lib.c +++ b/frida_mode/src/lib/lib.c @@ -6,7 +6,7 @@ #include <sys/mman.h> #include <unistd.h> - #include "frida-gum.h" + #include "frida-gumjs.h" #include "debug.h" @@ -151,6 +151,10 @@ static void lib_get_text_section(lib_details_t *details) { } +void lib_config(void) { + +} + void lib_init(void) { lib_details_t lib_details; diff --git a/frida_mode/src/lib/lib_apple.c b/frida_mode/src/lib/lib_apple.c index 8f863861..2aa48a13 100644 --- a/frida_mode/src/lib/lib_apple.c +++ b/frida_mode/src/lib/lib_apple.c @@ -1,5 +1,5 @@ #ifdef __APPLE__ - #include "frida-gum.h" + #include "frida-gumjs.h" #include "debug.h" @@ -56,6 +56,10 @@ gboolean lib_get_text_section(const GumDarwinSectionDetails *details, } +void lib_config(void) { + +} + void lib_init(void) { GumDarwinModule *module = NULL; diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index b17d9f49..85b0bbf3 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -11,14 +11,15 @@ #include <sys/personality.h> #endif -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" #include "debug.h" #include "entry.h" #include "instrument.h" -#include "interceptor.h" +#include "intercept.h" +#include "js.h" #include "lib.h" #include "output.h" #include "persistent.h" @@ -44,13 +45,6 @@ typedef int *(*main_fn_t)(int argc, char **argv, char **envp); static main_fn_t main_fn = NULL; -static int on_fork(void) { - - prefetch_read(); - return fork(); - -} - #ifdef __APPLE__ static void on_main_os(int argc, char **argv, char **envp) { @@ -174,23 +168,36 @@ void afl_frida_start(void) { afl_print_cmdline(); afl_print_env(); + /* Configure */ + entry_config(); + instrument_config(); + js_config(); + lib_config(); + output_config(); + persistent_config(); + prefetch_config(); + ranges_config(); + stalker_config(); + stats_config(); + + js_start(); + + /* Initialize */ + output_init(); + embedded_init(); - stalker_init(); - lib_init(); entry_init(); instrument_init(); - output_init(); + lib_init(); persistent_init(); prefetch_init(); + stalker_init(); ranges_init(); stats_init(); - void *fork_addr = - GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork")); - intercept(fork_addr, on_fork, NULL); - + /* Start */ stalker_start(); - entry_run(); + entry_start(); } @@ -198,7 +205,7 @@ static int *on_main(int argc, char **argv, char **envp) { on_main_os(argc, argv, envp); - unintercept_self(); + intercept_unhook_self(); afl_frida_start(); @@ -212,7 +219,7 @@ extern int *main(int argc, char **argv, char **envp); static void intercept_main(void) { main_fn = main; - intercept(main, on_main, NULL); + intercept_hook(main, on_main, NULL); } @@ -225,7 +232,7 @@ static void intercept_main(void) { OKF("Entry Point: 0x%016" G_GINT64_MODIFIER "x", entry); void *main = GSIZE_TO_POINTER(entry); main_fn = main; - intercept(main, on_main, NULL); + intercept_hook(main, on_main, NULL); } @@ -236,8 +243,8 @@ static int on_libc_start_main(int *(main)(int, char **, char **), int argc, void(*stack_end)) { main_fn = main; - unintercept_self(); - intercept(main, on_main, NULL); + intercept_unhook_self(); + intercept_hook(main, on_main, NULL); return __libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end); @@ -245,7 +252,7 @@ static int on_libc_start_main(int *(main)(int, char **, char **), int argc, static void intercept_main(void) { - intercept(__libc_start_main, on_libc_start_main, NULL); + intercept_hook(__libc_start_main, on_libc_start_main, NULL); } diff --git a/frida_mode/src/output.c b/frida_mode/src/output.c index 8a222b25..e2b744e7 100644 --- a/frida_mode/src/output.c +++ b/frida_mode/src/output.c @@ -2,17 +2,17 @@ #include <fcntl.h> #include <unistd.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" #include "output.h" -static int output_fd = -1; +char *output_stdout = NULL; +char *output_stderr = NULL; -static void output_redirect(int fd, char *variable) { +static void output_redirect(int fd, char *filename) { - char *filename = getenv(variable); char *path = NULL; if (filename == NULL) { return; } @@ -21,8 +21,8 @@ static void output_redirect(int fd, char *variable) { OKF("Redirect %d -> '%s'", fd, path); - output_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + int output_fd = open(path, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); g_free(path); @@ -34,12 +34,24 @@ static void output_redirect(int fd, char *variable) { } + close(output_fd); + +} + +void output_config(void) { + + output_stdout = getenv("AFL_FRIDA_OUTPUT_STDOUT"); + output_stderr = getenv("AFL_FRIDA_OUTPUT_STDERR"); + } void output_init(void) { - output_redirect(STDOUT_FILENO, "AFL_FRIDA_OUTPUT_STDOUT"); - output_redirect(STDERR_FILENO, "AFL_FRIDA_OUTPUT_STDERR"); + OKF("Output - StdOut: %s", output_stdout); + OKF("Output - StdErr: %s", output_stderr); + + output_redirect(STDOUT_FILENO, output_stdout); + output_redirect(STDERR_FILENO, output_stderr); } diff --git a/frida_mode/src/persistent/persistent.c b/frida_mode/src/persistent/persistent.c index 243d501d..e3e0b0ca 100644 --- a/frida_mode/src/persistent/persistent.c +++ b/frida_mode/src/persistent/persistent.c @@ -1,6 +1,6 @@ #include <dlfcn.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" #include "debug.h" @@ -8,17 +8,18 @@ #include "persistent.h" #include "util.h" -int __afl_sharedmem_fuzzing = 0; -afl_persistent_hook_fn hook = NULL; +int __afl_sharedmem_fuzzing = 0; +static char *hook_name = NULL; + +afl_persistent_hook_fn persistent_hook = NULL; guint64 persistent_start = 0; guint64 persistent_count = 0; guint64 persistent_ret = 0; gboolean persistent_debug = FALSE; -void persistent_init(void) { - - char *hook_name = getenv("AFL_FRIDA_PERSISTENT_HOOK"); +void persistent_config(void) { + hook_name = getenv("AFL_FRIDA_PERSISTENT_HOOK"); persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR"); persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT"); persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET"); @@ -33,6 +34,11 @@ void persistent_init(void) { } + if (persistent_start != 0 && persistent_count == 0) persistent_count = 1000; + + if (persistent_start != 0 && !persistent_is_supported()) + FATAL("Persistent mode not supported on this architecture"); + if (persistent_ret != 0 && persistent_start == 0) { FATAL( @@ -41,13 +47,9 @@ void persistent_init(void) { } - if (persistent_start != 0 && persistent_count == 0) persistent_count = 1000; - - if (persistent_count != 0 && persistent_count < 100) - WARNF("Persistent count out of recommended range (<100)"); +} - if (persistent_start != 0 && !persistent_is_supported()) - FATAL("Persistent mode not supported on this architecture"); +void persistent_init(void) { OKF("Instrumentation - persistent mode [%c] (0x%016" G_GINT64_MODIFIER "X)", persistent_start == 0 ? ' ' : 'X', persistent_start); @@ -58,27 +60,26 @@ void persistent_init(void) { OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)", persistent_ret == 0 ? ' ' : 'X', persistent_ret); - if (hook_name != NULL) { + if (hook_name == NULL) { return; } - void *hook_obj = dlopen(hook_name, RTLD_NOW); - if (hook_obj == NULL) - FATAL("Failed to load AFL_FRIDA_PERSISTENT_HOOK (%s)", hook_name); + void *hook_obj = dlopen(hook_name, RTLD_NOW); + if (hook_obj == NULL) + FATAL("Failed to load AFL_FRIDA_PERSISTENT_HOOK (%s)", hook_name); - int (*afl_persistent_hook_init_ptr)(void) = - dlsym(hook_obj, "afl_persistent_hook_init"); - if (afl_persistent_hook_init_ptr == NULL) - FATAL("Failed to find afl_persistent_hook_init in %s", hook_name); + int (*afl_persistent_hook_init_ptr)(void) = + dlsym(hook_obj, "afl_persistent_hook_init"); + if (afl_persistent_hook_init_ptr == NULL) + FATAL("Failed to find afl_persistent_hook_init in %s", hook_name); - if (afl_persistent_hook_init_ptr() == 0) - FATAL("afl_persistent_hook_init returned a failure"); + if (afl_persistent_hook_init_ptr() == 0) + FATAL("afl_persistent_hook_init returned a failure"); - hook = (afl_persistent_hook_fn)dlsym(hook_obj, "afl_persistent_hook"); - if (hook == NULL) - FATAL("Failed to find afl_persistent_hook in %s", hook_name); + persistent_hook = + (afl_persistent_hook_fn)dlsym(hook_obj, "afl_persistent_hook"); + if (persistent_hook == NULL) + FATAL("Failed to find afl_persistent_hook in %s", hook_name); - __afl_sharedmem_fuzzing = 1; - - } + __afl_sharedmem_fuzzing = 1; } diff --git a/frida_mode/src/persistent/persistent_arm32.c b/frida_mode/src/persistent/persistent_arm32.c index 6a3c06fa..f12f1af8 100644 --- a/frida_mode/src/persistent/persistent_arm32.c +++ b/frida_mode/src/persistent/persistent_arm32.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c index d7c6c76b..e618fbac 100644 --- a/frida_mode/src/persistent/persistent_arm64.c +++ b/frida_mode/src/persistent/persistent_arm64.c @@ -1,5 +1,5 @@ #include <unistd.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" #include "debug.h" @@ -318,7 +318,7 @@ static void instrument_exit(GumArm64Writer *cw) { static int instrument_afl_persistent_loop_func(void) { int ret = __afl_persistent_loop(persistent_count); - previous_pc = 0; + instrument_previous_pc = 0; return ret; } @@ -337,7 +337,7 @@ static void instrument_afl_persistent_loop(GumArm64Writer *cw) { static void persistent_prologue_hook(GumArm64Writer * cw, struct arm64_regs *regs) { - if (hook == NULL) return; + if (persistent_hook == NULL) return; gum_arm64_writer_put_sub_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP, GUM_RED_ZONE_SIZE); @@ -354,7 +354,7 @@ static void persistent_prologue_hook(GumArm64Writer * cw, gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X2, 0); gum_arm64_writer_put_call_address_with_arguments( - cw, GUM_ADDRESS(hook), 4, GUM_ARG_ADDRESS, GUM_ADDRESS(regs), + 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); diff --git a/frida_mode/src/persistent/persistent_x64.c b/frida_mode/src/persistent/persistent_x64.c index 653acefe..a91abc1c 100644 --- a/frida_mode/src/persistent/persistent_x64.c +++ b/frida_mode/src/persistent/persistent_x64.c @@ -1,5 +1,5 @@ #include <unistd.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" #include "debug.h" @@ -199,7 +199,7 @@ static void instrument_exit(GumX86Writer *cw) { static int instrument_afl_persistent_loop_func(void) { int ret = __afl_persistent_loop(persistent_count); - previous_pc = 0; + instrument_previous_pc = 0; return ret; } @@ -220,7 +220,7 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) { static void persistent_prologue_hook(GumX86Writer * cw, struct x86_64_regs *regs) { - if (hook == NULL) return; + if (persistent_hook == NULL) return; gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, -(GUM_RED_ZONE_SIZE)); @@ -236,7 +236,7 @@ static void persistent_prologue_hook(GumX86Writer * cw, gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RDX, GUM_REG_RDX, 0); gum_x86_writer_put_call_address_with_arguments( - cw, GUM_CALL_CAPI, GUM_ADDRESS(hook), 4, GUM_ARG_ADDRESS, + 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); diff --git a/frida_mode/src/persistent/persistent_x86.c b/frida_mode/src/persistent/persistent_x86.c index 7add6e99..1d01d8e4 100644 --- a/frida_mode/src/persistent/persistent_x86.c +++ b/frida_mode/src/persistent/persistent_x86.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" @@ -152,7 +152,7 @@ static void instrument_exit(GumX86Writer *cw) { static int instrument_afl_persistent_loop_func(void) { int ret = __afl_persistent_loop(persistent_count); - previous_pc = 0; + instrument_previous_pc = 0; return ret; } @@ -167,7 +167,7 @@ static void instrument_afl_persistent_loop(GumX86Writer *cw) { static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) { - if (hook == NULL) return; + if (persistent_hook == NULL) return; gum_x86_writer_put_mov_reg_address(cw, GUM_REG_ECX, GUM_ADDRESS(&__afl_fuzz_len)); @@ -180,7 +180,7 @@ 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(hook), 5, GUM_ARG_ADDRESS, + 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, GUM_REG_ECX); diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c index 65c09fba..50d10c9e 100644 --- a/frida_mode/src/prefetch.c +++ b/frida_mode/src/prefetch.c @@ -2,10 +2,11 @@ #include <sys/shm.h> #include <sys/mman.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" +#include "intercept.h" #include "prefetch.h" #include "stalker.h" @@ -20,9 +21,10 @@ typedef struct { } prefetch_data_t; -static prefetch_data_t *prefetch_data = NULL; +gboolean prefetch_enable = TRUE; -static int prefetch_shm_id = -1; +static prefetch_data_t *prefetch_data = NULL; +static int prefetch_shm_id = -1; /* * We do this from the transformer since we need one anyway for coverage, this @@ -72,14 +74,33 @@ void prefetch_read(void) { } +void prefetch_config(void) { + + prefetch_enable = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL); + +} + +static int prefetch_on_fork(void) { + + prefetch_read(); + return fork(); + +} + +static void prefetch_hook_fork(void) { + + void *fork_addr = + GSIZE_TO_POINTER(gum_module_find_export_by_name(NULL, "fork")); + intercept_hook(fork_addr, prefetch_on_fork, NULL); + +} + void prefetch_init(void) { g_assert_cmpint(sizeof(prefetch_data_t), ==, PREFETCH_SIZE); - gboolean prefetch = (getenv("AFL_FRIDA_INST_NO_PREFETCH") == NULL); + OKF("Instrumentation - prefetch [%c]", prefetch_enable ? 'X' : ' '); - OKF("Instrumentation - prefetch [%c]", prefetch ? 'X' : ' '); - - if (!prefetch) { return; } + if (!prefetch_enable) { return; } /* * Make our shared memory, we can attach before we fork, just like AFL does * with the coverage bitmap region and fork will take care of ensuring both @@ -108,5 +129,7 @@ void prefetch_init(void) { /* Clear it, not sure it's necessary, just seems like good practice */ memset(prefetch_data, '\0', sizeof(prefetch_data_t)); + prefetch_hook_fork(); + } diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index ef25b371..534f202b 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" @@ -17,11 +17,14 @@ typedef struct { } convert_name_ctx_t; -GArray *module_ranges = NULL; -GArray *libs_ranges = NULL; -GArray *include_ranges = NULL; -GArray *exclude_ranges = NULL; -GArray *ranges = NULL; +gboolean ranges_debug_maps = FALSE; +gboolean ranges_inst_libs = FALSE; + +static GArray *module_ranges = NULL; +static GArray *libs_ranges = NULL; +static GArray *include_ranges = NULL; +static GArray *exclude_ranges = NULL; +static GArray *ranges = NULL; static void convert_address_token(gchar *token, GumMemoryRange *range) { @@ -225,6 +228,43 @@ static GArray *collect_module_ranges(void) { } +static void check_for_overlaps(GArray *array) { + + for (guint i = 1; i < array->len; i++) { + + GumMemoryRange *prev = &g_array_index(array, GumMemoryRange, i - 1); + GumMemoryRange *curr = &g_array_index(array, GumMemoryRange, i); + GumAddress prev_limit = prev->base_address + prev->size; + GumAddress curr_limit = curr->base_address + curr->size; + if (prev_limit > curr->base_address) { + + FATAL("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); + + } + + } + +} + +void ranges_add_include(GumMemoryRange *range) { + + g_array_append_val(include_ranges, *range); + g_array_sort(include_ranges, range_sort); + check_for_overlaps(include_ranges); + +} + +void ranges_add_exclude(GumMemoryRange *range) { + + g_array_append_val(exclude_ranges, *range); + g_array_sort(exclude_ranges, range_sort); + check_for_overlaps(exclude_ranges); + +} + static GArray *collect_ranges(char *env_key) { char * env_val; @@ -253,23 +293,7 @@ static GArray *collect_ranges(char *env_key) { g_array_sort(result, range_sort); - /* Check for overlaps */ - for (i = 1; i < token_count; i++) { - - GumMemoryRange *prev = &g_array_index(result, GumMemoryRange, i - 1); - GumMemoryRange *curr = &g_array_index(result, GumMemoryRange, i); - GumAddress prev_limit = prev->base_address + prev->size; - GumAddress curr_limit = curr->base_address + curr->size; - if (prev_limit > curr->base_address) { - - FATAL("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); - - } - - } + check_for_overlaps(result); print_ranges(env_key, result); @@ -285,15 +309,15 @@ static GArray *collect_libs_ranges(void) { GumMemoryRange range; result = g_array_new(false, false, sizeof(GumMemoryRange)); - if (getenv("AFL_INST_LIBS") == NULL) { + if (ranges_inst_libs) { - range.base_address = lib_get_text_base(); - range.size = lib_get_text_limit() - lib_get_text_base(); + range.base_address = 0; + range.size = G_MAXULONG; } else { - range.base_address = 0; - range.size = G_MAXULONG; + range.base_address = lib_get_text_base(); + range.size = lib_get_text_limit() - lib_get_text_base(); } @@ -480,30 +504,13 @@ static GArray *merge_ranges(GArray *a) { } -static gboolean exclude_ranges_callback(const GumRangeDetails *details, - gpointer user_data) { +void ranges_config(void) { - UNUSED_PARAMETER(user_data); - gchar * name; - gboolean found; - GumStalker *stalker; - if (details->file == NULL) { return TRUE; } - name = g_path_get_basename(details->file->path); - - found = (g_strcmp0(name, "afl-frida-trace.so") == 0); - g_free(name); - if (!found) { return TRUE; } - - stalker = stalker_get(); - gum_stalker_exclude(stalker, details->range); - - return FALSE; + if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { ranges_debug_maps = TRUE; } + if (getenv("AFL_INST_LIBS") != NULL) { ranges_inst_libs = TRUE; } -} - -static void ranges_exclude_self(void) { - - gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, exclude_ranges_callback, NULL); + include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES"); + exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES"); } @@ -515,16 +522,20 @@ void ranges_init(void) { GArray * step3; GArray * step4; - if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { + if (ranges_debug_maps) { gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges_callback, NULL); } + OKF("Ranges - Instrument libraries [%c]", ranges_inst_libs ? 'X' : ' '); + + print_ranges("AFL_FRIDA_INST_RANGES", include_ranges); + print_ranges("AFL_FRIDA_EXCLUDE_RANGES", exclude_ranges); + module_ranges = collect_module_ranges(); libs_ranges = collect_libs_ranges(); - include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES"); /* If include ranges is empty, then assume everything is included */ if (include_ranges->len == 0) { @@ -535,8 +546,6 @@ void ranges_init(void) { } - exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES"); - /* Intersect with .text section of main executable unless AFL_INST_LIBS */ step1 = intersect_ranges(module_ranges, libs_ranges); print_ranges("step1", step1); @@ -565,9 +574,6 @@ void ranges_init(void) { g_array_free(step2, TRUE); g_array_free(step1, TRUE); - /* *NEVER* stalk the stalker, only bad things will ever come of this! */ - ranges_exclude_self(); - ranges_exclude(); } diff --git a/frida_mode/src/stalker.c b/frida_mode/src/stalker.c index 63f3c529..98483cde 100644 --- a/frida_mode/src/stalker.c +++ b/frida_mode/src/stalker.c @@ -2,18 +2,47 @@ #include "instrument.h" #include "stalker.h" +#include "util.h" static GumStalker *stalker = NULL; -void stalker_init(void) { +void stalker_config(void) { if (!gum_stalker_is_supported()) { FATAL("Failed to initialize embedded"); } +} + +static gboolean stalker_exclude_self(const GumRangeDetails *details, + gpointer user_data) { + + UNUSED_PARAMETER(user_data); + gchar * name; + gboolean found; + GumStalker *stalker; + if (details->file == NULL) { return TRUE; } + name = g_path_get_basename(details->file->path); + + found = (g_strcmp0(name, "afl-frida-trace.so") == 0); + g_free(name); + if (!found) { return TRUE; } + + stalker = stalker_get(); + gum_stalker_exclude(stalker, details->range); + + return FALSE; + +} + +void stalker_init(void) { + stalker = gum_stalker_new(); if (stalker == NULL) { FATAL("Failed to initialize stalker"); } gum_stalker_set_trust_threshold(stalker, 0); + /* *NEVER* stalk the stalker, only bad things will ever come of this! */ + gum_process_enumerate_ranges(GUM_PAGE_EXECUTE, stalker_exclude_self, NULL); + } GumStalker *stalker_get(void) { diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c index 0d7b9fb0..0dd8be70 100644 --- a/frida_mode/src/stats/stats.c +++ b/frida_mode/src/stats/stats.c @@ -5,7 +5,7 @@ #include <sys/shm.h> #include <sys/mman.h> -#include "frida-gum.h" +#include "frida-gumjs.h" #include "config.h" #include "debug.h" @@ -17,15 +17,16 @@ stats_data_header_t *stats_data = NULL; -static int stats_parent_pid = -1; -static int stats_fd = -1; -static gboolean stats_transitions = FALSE; -static guint64 stats_interval = 0; +static int stats_parent_pid = -1; +static int stats_fd = -1; -void stats_init(void) { +char * stats_filename = NULL; +guint64 stats_interval = 0; +gboolean stats_transitions = FALSE; - stats_parent_pid = getpid(); - char *filename = getenv("AFL_FRIDA_STATS_FILE"); +void stats_config(void) { + + stats_filename = getenv("AFL_FRIDA_STATS_FILE"); stats_interval = util_read_num("AFL_FRIDA_STATS_INTERVAL"); if (getenv("AFL_FRIDA_STATS_TRANSITIONS") != NULL) { @@ -33,10 +34,16 @@ void stats_init(void) { } - OKF("Stats - file [%s]", filename); +} + +void stats_init(void) { + + stats_parent_pid = getpid(); + + OKF("Stats - file [%s]", stats_filename); OKF("Stats - interval [%" G_GINT64_MODIFIER "u]", stats_interval); - if (stats_interval != 0 && filename == NULL) { + if (stats_interval != 0 && stats_filename == NULL) { FATAL( "AFL_FRIDA_STATS_FILE must be specified if " @@ -46,7 +53,7 @@ void stats_init(void) { if (stats_interval == 0) { stats_interval = 10; } - if (filename == NULL) { return; } + if (stats_filename == NULL) { return; } if (!stats_is_supported_arch()) { @@ -56,11 +63,11 @@ void stats_init(void) { char *path = NULL; - if (filename == NULL) { return; } + if (stats_filename == NULL) { return; } if (stats_transitions) { gum_stalker_set_counters_enabled(TRUE); } - path = g_canonicalize_filename(filename, g_get_current_dir()); + path = g_canonicalize_filename(stats_filename, g_get_current_dir()); OKF("Stats - path [%s]", path); diff --git a/frida_mode/src/stats/stats_arm32.c b/frida_mode/src/stats/stats_arm32.c index 7eea7f91..71953af3 100644 --- a/frida_mode/src/stats/stats_arm32.c +++ b/frida_mode/src/stats/stats_arm32.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/stats/stats_arm64.c b/frida_mode/src/stats/stats_arm64.c index 592af87a..d9d374a4 100644 --- a/frida_mode/src/stats/stats_arm64.c +++ b/frida_mode/src/stats/stats_arm64.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/stats/stats_x64.c b/frida_mode/src/stats/stats_x64.c index c3e8742a..7c3a90d7 100644 --- a/frida_mode/src/stats/stats_x64.c +++ b/frida_mode/src/stats/stats_x64.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/src/stats/stats_x86.c b/frida_mode/src/stats/stats_x86.c index 1906e809..d9c4f652 100644 --- a/frida_mode/src/stats/stats_x86.c +++ b/frida_mode/src/stats/stats_x86.c @@ -1,4 +1,4 @@ -#include "frida-gum.h" +#include "frida-gumjs.h" #include "debug.h" diff --git a/frida_mode/test/deferred/GNUmakefile b/frida_mode/test/deferred/GNUmakefile index c268ef66..ae580e3f 100644 --- a/frida_mode/test/deferred/GNUmakefile +++ b/frida_mode/test/deferred/GNUmakefile @@ -37,7 +37,7 @@ ifeq "$(ARCH)" "x86" AFL_ENTRYPOINT=$(shell $(GET_SYMBOL_ADDR) -f $(TESTINSTBIN) -s run -b 0x56555000) endif -.PHONY: all clean qemu frida +.PHONY: all clean frida all: $(TESTINSTBIN) make -C $(ROOT)frida_mode/ diff --git a/frida_mode/test/js/GNUmakefile b/frida_mode/test/js/GNUmakefile new file mode 100644 index 00000000..8ea71656 --- /dev/null +++ b/frida_mode/test/js/GNUmakefile @@ -0,0 +1,44 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +TESTINSTR_DATA_FILE:=$(TESTINSTR_DATA_DIR)in + +TESTINSTBIN:=$(BUILD_DIR)testinstr +TESTINSTSRC:=$(PWD)testinstr.c + +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +.PHONY: all 32 clean qemu frida + +all: $(TESTINSTBIN) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TESTINSTR_DATA_FILE): | $(TESTINSTR_DATA_DIR) + echo -n "000" > $@ + +$(TESTINSTBIN): $(TESTINSTSRC) | $(BUILD_DIR) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< + +clean: + rm -rf $(BUILD_DIR) + +frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_FRIDA_JS_SCRIPT=test.js \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ diff --git a/frida_mode/test/js/Makefile b/frida_mode/test/js/Makefile new file mode 100644 index 00000000..7a237f99 --- /dev/null +++ b/frida_mode/test/js/Makefile @@ -0,0 +1,16 @@ +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 + +debug: + @gmake debug diff --git a/frida_mode/test/js/test.js b/frida_mode/test/js/test.js new file mode 100644 index 00000000..f10ef2d1 --- /dev/null +++ b/frida_mode/test/js/test.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/testinstr.c b/frida_mode/test/js/testinstr.c new file mode 100644 index 00000000..bd605c52 --- /dev/null +++ b/frida_mode/test/js/testinstr.c @@ -0,0 +1,121 @@ +/* + 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 <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#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/persistent_ret/GNUmakefile b/frida_mode/test/persistent_ret/GNUmakefile index 2de51d86..81fdd069 100644 --- a/frida_mode/test/persistent_ret/GNUmakefile +++ b/frida_mode/test/persistent_ret/GNUmakefile @@ -82,6 +82,16 @@ frida_ret: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) -- \ $(TESTINSTBIN) @@ +frida_js: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) + AFL_FRIDA_JS_SCRIPT=test.js \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TESTINSTR_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TESTINSTBIN) @@ + debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE) gdb \ --ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \ diff --git a/frida_mode/test/persistent_ret/test.js b/frida_mode/test/persistent_ret/test.js new file mode 100644 index 00000000..43c6ad7c --- /dev/null +++ b/frida_mode/test/persistent_ret/test.js @@ -0,0 +1,38 @@ +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 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(); +Afl.print("done"); diff --git a/include/envs.h b/include/envs.h index 54bb6597..f89e8e62 100644 --- a/include/envs.h +++ b/include/envs.h @@ -60,7 +60,8 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_INST_NO_PREFETCH", "AFL_FRIDA_INST_RANGES", "AFL_FRIDA_INST_TRACE", - "AFL_FRIDA_INST_UNSTABLE", + "AFL_FRIDA_INST_TRACE_UNIQUE", + "AFL_FRIDA_JS_SCRIPT", "AFL_FRIDA_OUTPUT_STDOUT", "AFL_FRIDA_OUTPUT_STDERR", "AFL_FRIDA_PERSISTENT_ADDR", |