diff options
31 files changed, 852 insertions, 210 deletions
diff --git a/README.md b/README.md index 53b2b8d0..921fc0c6 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ <img align="right" src="https://raw.githubusercontent.com/AFLplusplus/Website/master/static/aflpp_bg.svg" alt="AFL++ logo" width="250" heigh="250"> -Release version: [4.01c](https://github.com/AFLplusplus/AFLplusplus/releases) +Release version: [4.02c](https://github.com/AFLplusplus/AFLplusplus/releases) -GitHub version: 4.02a +GitHub version: 4.02c Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) diff --git a/docs/Changelog.md b/docs/Changelog.md index 05bbe827..957f6206 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,10 +8,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to <afl-users+subscribe@googlegroups.com>. -### Version ++4.02a (dev) - - afl-fuzz: - - change post_process hook to allow returning NULL and 0 length to - tell afl-fuzz to skip this mutated input +### Version ++4.02c (release) - afl-cc: - important fix for the default pcguard mode when LLVM IR vector selects are produced, thanks to @juppytt for reporting! @@ -19,6 +16,11 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. - Adacore submitted CMPLOG support to the gcc_plugin! :-) - llvm_mode: - laf cmp splitting fixed for more comparison types + - frida_mode: + - now works on Android! + - afl-fuzz: + - change post_process hook to allow returning NULL and 0 length to + tell afl-fuzz to skip this mutated input ### Version ++4.01c (release) diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index bc7df6c0..43b8932a 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -13,6 +13,16 @@ 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)))) + +TARGET_CC?=$(CC) +TARGET_CXX?=$(CXX) +HOST_CC?=$(CC) +HOST_CXX?=$(CXX) +IS_ANDROID:=$(findstring android, $(shell $(TARGET_CC) --version 2>/dev/null)) +IS_x86:=$(findstring i686, $(shell $(TARGET_CC) --version 2>/dev/null)) +IS_x86_64:=$(findstring x86_64, $(shell $(TARGET_CC) --version 2>/dev/null)) +IS_ARM:=$(findstring arm, $(shell $(TARGET_CC) --version 2>/dev/null)) +IS_ARM64:=$(findstring aarch64, $(shell $(TARGET_CC) --version 2>/dev/null)) CFLAGS+=-fPIC \ -D_GNU_SOURCE \ -D_FORTIFY_SOURCE=2 \ @@ -21,6 +31,10 @@ CFLAGS+=-fPIC \ -funroll-loops \ -ffunction-sections \ +ifdef IS_ANDROID +CFLAGS+=-DANDROID +endif + AFL_CFLAGS:=-Wno-unused-parameter \ -Wno-sign-compare \ -Wno-unused-function \ @@ -28,9 +42,16 @@ AFL_CFLAGS:=-Wno-unused-parameter \ -Wno-int-to-pointer-cast \ -Wno-pointer-sign +ifdef IS_ANDROID +LDFLAGS+= -static-libstdc++ \ + -DANDROID \ + -llog \ + -shared +else LDFLAGS+=-shared \ -lpthread \ -lresolv +endif ifdef DEBUG CFLAGS+=-Werror \ @@ -43,10 +64,12 @@ endif FRIDA_BUILD_DIR:=$(BUILD_DIR)frida/ FRIDA_TRACE:=$(BUILD_DIR)afl-frida-trace.so +FRIDA_TRACE_LIB:=$(BUILD_DIR)libafl-frida-trace.a FRIDA_TRACE_EMBEDDED:=$(BUILD_DIR)afl-frida-trace-embedded TARGET_CC?=$(CC) TARGET_CXX?=$(CXX) +TARGET_AR?=$(AR) HOST_CC?=$(CC) HOST_CXX?=$(CXX) @@ -76,11 +99,11 @@ else ifdef DEBUG AFL_CFLAGS:=$(AFL_CFLAGS) -Wno-prio-ctor-dtor endif + LDFLAGS+= -z noexecstack \ -Wl,--gc-sections \ -Wl,--exclude-libs,ALL \ - -ldl \ - -lrt + -ldl LDSCRIPT:=-Wl,--version-script=$(PWD)frida.map endif @@ -91,25 +114,28 @@ ifeq "$(shell uname)" "Linux" endif endif -ifneq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" "" + +ifdef IS_ANDROID OS:=android - ifneq "$(findstring aarch64, $(shell $(CC) --version 2>/dev/null))" "" - ARCH:=arm64 + ifdef IS_x86 + ARCH:=x86 endif - ifneq "$(findstring arm, $(shell $(CC) --version 2>/dev/null))" "" - ARCH:=arm + ifdef IS_x86 + ARCH:=x86_64 endif - ifneq "$(findstring x86_64, $(shell $(CC) --version 2>/dev/null))" "" - ARCH:=x86_64 + ifdef IS_ARM + ARCH:=arm endif - ifneq "$(findstring i686, $(shell $(CC) --version 2>/dev/null))" "" - ARCH:=x86 + ifdef IS_ARM64 + ARCH:=arm64 endif endif + ifeq "$(ARCH)" "armhf" TARGET_CC:=arm-linux-gnueabihf-gcc TARGET_CXX:=arm-linux-gnueabihf-g++ + TARGET_AR:=arm-linux-gnueabihf-ar endif ifndef OS @@ -157,7 +183,7 @@ BIN2C_SRC:=$(PWD)util/bin2c.c ############################## ALL ############################################# -all: $(FRIDA_TRACE) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN) +all: $(FRIDA_TRACE) $(FRIDA_TRACE_LIB) $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) $(ADDR_BIN) 32: CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all @@ -221,10 +247,22 @@ else ifeq "$(ARCH)" "arm64" CFLAGS+=-I $(FRIDA_DIR)build/frida_thin-$(OS)-$(ARCH)/include/frida-1.0 \ -I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/glib-2.0/ \ - -I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \ + -I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \ -I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/capstone/ \ -I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \ +ifeq "$(OS)" "android" + CFLAGS += -static-libstdc++ +endif +else +CFLAGS+=-I $(FRIDA_DIR)build/frida_thin-$(OS)-$(ARCH)/include/frida-1.0 \ + -I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/glib-2.0/ \ + -I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \ + -I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/capstone/ \ + -I $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \ + +endif + TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \ $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \ $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libsqlite3.a \ @@ -242,13 +280,15 @@ TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \ $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/liblzma.a \ $(FRIDA_DIR)build/frida_thin-sdk-$(OS)-$(ARCH)/lib/libz.a \ -else - CFLAGS+=-I $(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/include/frida-1.0 \ -I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/glib-2.0/ \ -I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/glib-2.0/include/ \ -I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/capstone/ \ - -I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ \ + -I $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/include/json-glib-1.0/ + +ifeq "$(OS)" "android" + CFLAGS += -static-libstdc++ +endif TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \ $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libsoup-2.4.a \ @@ -267,11 +307,6 @@ TRACE_LDFLAGS+=$(FRIDA_DIR)build/frida-$(OS)-$(ARCH)/lib/libfrida-gum-1.0.a \ $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/liblzma.a \ $(FRIDA_DIR)build/sdk-$(OS)-$(ARCH)/lib/libz.a \ -endif - - - - else $(GUM_DEVKIT_TARBALL): | $(FRIDA_BUILD_DIR) @@ -353,6 +388,15 @@ $(FRIDA_TRACE): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL cp -v $(FRIDA_TRACE) $(ROOT) +$(FRIDA_TRACE_LIB): $(GUM_DEVIT_LIBRARY) $(GUM_DEVIT_HEADER) $(OBJS) $(JS_OBJ) $(AFL_COMPILER_RT_OBJ) $(AFL_PERFORMANCE_OBJ) GNUmakefile | $(BUILD_DIR) + $(TARGET_AR) \ + -rcs \ + $@ \ + $(OBJS) \ + $(JS_OBJ) \ + $(AFL_COMPILER_RT_OBJ) \ + $(AFL_PERFORMANCE_OBJ) \ + ############################# HOOK ############################################# $(AFLPP_FRIDA_DRIVER_HOOK_OBJ): $(AFLPP_FRIDA_DRIVER_HOOK_SRC) $(GUM_DEVIT_HEADER) | $(BUILD_DIR) @@ -364,6 +408,7 @@ $(AFLPP_QEMU_DRIVER_HOOK_OBJ): $(AFLPP_QEMU_DRIVER_HOOK_SRC) | $(BUILD_DIR) hook: $(AFLPP_FRIDA_DRIVER_HOOK_OBJ) $(AFLPP_QEMU_DRIVER_HOOK_OBJ) ############################# ADDR ############################################# +ifneq "$(OS)" "android" $(ADDR_BIN): $(ADDR_SRC) | $(BUILD_DIR) -$(TARGET_CC) \ $(CFLAGS) \ @@ -377,7 +422,20 @@ $(ADDR_BIN): $(ADDR_SRC) | $(BUILD_DIR) -ldl \ -lrt \ $< -o $@ - +else +$(ADDR_BIN): $(ADDR_SRC) | $(BUILD_DIR) + -$(TARGET_CC) \ + $(CFLAGS) \ + -Werror \ + -Wall \ + -Wextra \ + -Wpointer-arith \ + -z noexecstack \ + -Wl,--gc-sections \ + -Wl,--exclude-libs,ALL \ + -ldl \ + $< -o $@ +endif addr: $(ADDR_BIN) ############################# CLEAN ############################################ diff --git a/frida_mode/README.md b/frida_mode/README.md index 29f7968b..bfe0948b 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -146,6 +146,8 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent QEMU driver to provide a `main` loop for a user provided `LLVMFuzzerTestOneInput`, this option configures the driver to read input from `stdin` rather than using in-memory test cases. +* `AFL_FRIDA_INST_COVERAGE_ABSOLUTE` - Generate coverage files using absolute + virtual addresses rather than relative virtual addresses. * `AFL_FRIDA_INST_COVERAGE_FILE` - File to write DynamoRIO format coverage information (e.g., to be loaded within IDA lighthouse). * `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks diff --git a/frida_mode/frida.map b/frida_mode/frida.map index 8e956460..73fff686 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -13,6 +13,7 @@ js_api_set_debug_maps; js_api_set_entrypoint; js_api_set_instrument_cache_size; + js_api_set_instrument_coverage_absolute; js_api_set_instrument_coverage_file; js_api_set_instrument_debug_file; js_api_set_instrument_jit; diff --git a/frida_mode/hook/frida_hook.c b/frida_mode/hook/frida_hook.c index 3bfdb207..79e2348d 100644 --- a/frida_mode/hook/frida_hook.c +++ b/frida_mode/hook/frida_hook.c @@ -31,7 +31,7 @@ __attribute__((visibility("default"))) void afl_persistent_hook( // do a length check matching the target! void **esp = (void **)regs->esp; - void * arg1 = esp[0]; + void *arg1 = esp[0]; void **arg2 = &esp[1]; memcpy(arg1, input_buf, input_buf_len); *arg2 = (void *)input_buf_len; @@ -50,6 +50,16 @@ __attribute__((visibility("default"))) void afl_persistent_hook( } +#elif defined(__arm__) + +__attribute__((visibility("default"))) void afl_persistent_hook( + GumCpuContext *regs, uint8_t *input_buf, uint32_t input_buf_len) { + // do a length check matching the target! + + memcpy((void *)regs->r[0], input_buf, input_buf_len); + regs->r[1] = input_buf_len; +} + #else #pragma error "Unsupported architecture" #endif diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index b85aa571..8c93d881 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -7,13 +7,14 @@ extern char *instrument_debug_filename; extern char *instrument_coverage_filename; +extern bool instrument_coverage_absolute; extern gboolean instrument_tracing; extern gboolean instrument_optimize; extern gboolean instrument_unique; extern guint64 instrument_hash_zero; extern char *instrument_coverage_unstable_filename; extern gboolean instrument_coverage_insn; -extern char * instrument_regs_filename; +extern char *instrument_regs_filename; extern gboolean instrument_use_fixed_seed; extern guint64 instrument_fixed_seed; diff --git a/frida_mode/include/seccomp.h b/frida_mode/include/seccomp.h index 0cd90bc2..0886759c 100644 --- a/frida_mode/include/seccomp.h +++ b/frida_mode/include/seccomp.h @@ -1,7 +1,7 @@ #ifndef _SECCOMP_H #define _SECCOMP_H -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__ANDROID__) #include <stdint.h> #include <linux/filter.h> diff --git a/frida_mode/include/shm.h b/frida_mode/include/shm.h new file mode 100644 index 00000000..8338ccba --- /dev/null +++ b/frida_mode/include/shm.h @@ -0,0 +1,9 @@ +#ifndef _SHM_H +#define _SHM_H + +#include <stddef.h> + +void *shm_create(size_t size); + +#endif + diff --git a/frida_mode/src/asan/asan.c b/frida_mode/src/asan/asan.c index 3a672d31..ad171337 100644 --- a/frida_mode/src/asan/asan.c +++ b/frida_mode/src/asan/asan.c @@ -36,6 +36,15 @@ static gboolean asan_exclude_module(const GumModuleDetails *details, address = gum_module_find_export_by_name(details->name, symbol_name); if (address == 0) { return TRUE; } + /* If the reported address of the symbol is outside of the range of the module + * then ignore it */ + if (address < details->range->base_address) { return TRUE; } + if (address > (details->range->base_address + details->range->size)) { + + return TRUE; + + } + ranges_add_exclude((GumMemoryRange *)details->range); return FALSE; diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 93c498e8..e1e4ac22 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -1,7 +1,5 @@ #include <fcntl.h> #include <unistd.h> -#include <sys/shm.h> -#include <sys/mman.h> #include <sys/syscall.h> #include "frida-gumjs.h" @@ -17,6 +15,7 @@ #include "persistent.h" #include "prefetch.h" #include "ranges.h" +#include "shm.h" #include "stalker.h" #include "stats.h" #include "util.h" @@ -33,7 +32,7 @@ gboolean instrument_use_fixed_seed = FALSE; guint64 instrument_fixed_seed = 0; char *instrument_coverage_unstable_filename = NULL; gboolean instrument_coverage_insn = FALSE; -char * instrument_regs_filename = NULL; +char *instrument_regs_filename = NULL; static GumStalkerTransformer *transformer = NULL; @@ -237,9 +236,12 @@ static void instrument_basic_block(GumStalkerIterator *iterator, } if (unlikely(instrument_regs_filename != NULL)) { + gum_stalker_iterator_put_callout(iterator, instrument_write_regs, (void *)(size_t)regs_fd, NULL); + } + } } @@ -274,6 +276,7 @@ static void instrument_basic_block(GumStalkerIterator *iterator, instrument_flush(output); instrument_debug_end(output); instrument_coverage_end(instr->address + instr->size); + } void instrument_config(void) { @@ -344,29 +347,7 @@ void instrument_init(void) { transformer = gum_stalker_transformer_make_from_callback( instrument_basic_block, NULL, NULL); - if (instrument_unique) { - - int shm_id = - shmget(IPC_PRIVATE, __afl_map_size, IPC_CREAT | IPC_EXCL | 0600); - if (shm_id < 0) { FATAL("shm_id < 0 - errno: %d\n", errno); } - - edges_notified = shmat(shm_id, NULL, 0); - g_assert(edges_notified != MAP_FAILED); - - /* - * Configure the shared memory region to be removed once the process - * dies. - */ - if (shmctl(shm_id, IPC_RMID, NULL) < 0) { - - FATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); - - } - - /* Clear it, not sure it's necessary, just seems like good practice */ - memset(edges_notified, '\0', __afl_map_size); - - } + if (instrument_unique) { edges_notified = shm_create(__afl_map_size); } if (instrument_use_fixed_seed) { @@ -404,6 +385,7 @@ void instrument_init(void) { instrument_regs_filename == NULL ? " " : instrument_regs_filename); if (instrument_regs_filename != NULL) { + char *path = g_canonicalize_filename(instrument_regs_filename, g_get_current_dir()); @@ -415,6 +397,7 @@ void instrument_init(void) { if (regs_fd < 0) { FFATAL("Failed to open regs file '%s'", path); } g_free(path); + } asan_init(); @@ -444,6 +427,7 @@ void instrument_on_fork() { } void instrument_regs_format(int fd, char *format, ...) { + va_list ap; char buffer[4096] = {0}; int ret; @@ -458,4 +442,6 @@ void instrument_regs_format(int fd, char *format, ...) { len = strnlen(buffer, sizeof(buffer)); IGNORED_RETURN(write(fd, buffer, len)); + } + diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c index 73923326..f2e825ee 100644 --- a/frida_mode/src/instrument/instrument_arm32.c +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -5,21 +5,159 @@ #if defined(__arm__) + #define PAGE_MASK (~(GUM_ADDRESS(0xfff))) + #define PAGE_ALIGNED(x) ((GUM_ADDRESS(x) & PAGE_MASK) == GUM_ADDRESS(x)) + gboolean instrument_cache_enabled = FALSE; gsize instrument_cache_size = 0; +extern __thread guint64 instrument_previous_pc; + +__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_SIZE]; + + #pragma pack(push, 1) +typedef struct { + + // cur_location = (block_address >> 4) ^ (block_address << 8); + // shared_mem[cur_location ^ prev_location]++; + // prev_location = cur_location >> 1; + + /* We can remove this branch when we add support for branch suppression */ + uint32_t b_code; /* b imm */ + uint8_t *shared_mem; + uint64_t *prev_location; + + /* code */ + + /* save regs */ + uint32_t str_r0_sp_rz; /* str r0, [sp - RED_ZONE] */ + uint32_t str_r1_sp_rz_4; /* str r1, [sp - (RED_ZONE + 4)] */ + + /* load prev */ + uint32_t ldr_r0_pprev; /* ldr r0, [pc-x] */ + uint32_t ldrh_r1_r0; /* ldrh r1, [r0] */ + + /* load curr */ + uint32_t mov_r0_block_id; /* mov r0, #imm16 */ + + /* calculate new */ + uint32_t eor_r0_r0_r1; /* eor r0, r0, r1 */ + + /* load map */ + uint32_t ldr_r1_pmap; /* ldr r1, [pc-x] */ + + /* calculate offset */ + uint32_t add_r1_r1_r0; /* add r1, r1, r0 */ + + /* Load the value */ + uint32_t ldrb_r0_r1; /* ldrb r0, [r1] */ + + /* Increment the value */ + uint32_t add_r0_r0_1; /* add r0, r0, #1 */ + uint32_t add_r0_r0_r0_lsr_8; /* add r0, r0, r0, lsr #8 */ + + /* Save the value */ + uint32_t strb_r0_r1; /* strb r0, [r1] */ + + /* load curr shifted */ + uint32_t mov_r0_block_id_shr_1; /* mov r0, #imm16 >> 1*/ + + /* Update prev */ + uint32_t ldr_r1_pprev; /* ldr r1, [pc-x] */ + uint32_t strh_r0_r1; /* strh r0, [r1] */ + + /* restore regs */ + uint32_t ldr_r1_sp_rz_4; /* ldr r1, [sp - (RED_ZONE + 4)] */ + uint32_t ldr_r0_sp_rz; /* ldr r0, [sp - RED_ZONE] */ + +} afl_log_code_asm_t; + +typedef union { + + afl_log_code_asm_t code; + uint8_t bytes[0]; + +} afl_log_code; + + #pragma pack(pop) + +static const afl_log_code_asm_t template = + { + + .b_code = GUINT32_TO_LE(0xea000001), + .shared_mem = (uint8_t *)GUINT32_TO_LE(0xcefaadde), + .prev_location = (uint64_t *)GUINT32_TO_LE(0xadba0df0), + .str_r0_sp_rz = GUINT32_TO_LE(0xe50d0080), + .str_r1_sp_rz_4 = GUINT32_TO_LE(0xe50d1084), + .ldr_r0_pprev = GUINT32_TO_LE(0xe51f0014), + .ldrh_r1_r0 = GUINT32_TO_LE(0xe1d010b0), + .mov_r0_block_id = GUINT32_TO_LE(0xe3000000), + .eor_r0_r0_r1 = GUINT32_TO_LE(0xe0200001), + .ldr_r1_pmap = GUINT32_TO_LE(0xe51f1028), + .add_r1_r1_r0 = GUINT32_TO_LE(0xe0811000), + .ldrb_r0_r1 = GUINT32_TO_LE(0xe5d10000), + .add_r0_r0_1 = GUINT32_TO_LE(0xe2800001), + .add_r0_r0_r0_lsr_8 = GUINT32_TO_LE(0xe0800420), + .strb_r0_r1 = GUINT32_TO_LE(0xe5c10000), + .mov_r0_block_id_shr_1 = GUINT32_TO_LE(0xe3000000), + .ldr_r1_pprev = GUINT32_TO_LE(0xe51f1040), + .strh_r0_r1 = GUINT32_TO_LE(0xe1c100b0), + .ldr_r1_sp_rz_4 = GUINT32_TO_LE(0xe51d1084), + .ldr_r0_sp_rz = GUINT32_TO_LE(0xe51d0080), + +} + +; + gboolean instrument_is_coverage_optimize_supported(void) { - return false; + return true; + +} + +static void patch_t3_insn(uint32_t *insn, uint16_t val) { + + uint32_t orig = GUINT32_FROM_LE(*insn); + uint32_t imm12 = (val & 0xfff); + uint32_t imm4 = (val >> 12); + orig |= imm12; + orig |= (imm4 << 16); + *insn = GUINT32_TO_LE(orig); } void instrument_coverage_optimize(const cs_insn *instr, GumStalkerOutput *output) { - UNUSED_PARAMETER(instr); - UNUSED_PARAMETER(output); - FFATAL("Optimized coverage not supported on this architecture"); + afl_log_code code = {0}; + GumArmWriter *cw = output->writer.arm; + gpointer block_start; + guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address)); + gsize map_size_pow2; + gsize area_offset_ror; + GumAddress code_addr = 0; + + // gum_arm64_writer_put_brk_imm(cw, 0x0); + + code_addr = cw->pc; + + block_start = GSIZE_TO_POINTER(GUM_ADDRESS(cw->code)); + + code.code = template; + + g_assert(PAGE_ALIGNED(__afl_area_ptr)); + + map_size_pow2 = util_log2(__afl_map_size); + area_offset_ror = util_rotate(area_offset, 1, map_size_pow2); + + code.code.shared_mem = __afl_area_ptr; + code.code.prev_location = instrument_previous_pc_addr; + + patch_t3_insn(&code.code.mov_r0_block_id, (uint16_t)area_offset); + patch_t3_insn(&code.code.mov_r0_block_id_shr_1, (uint16_t)area_offset_ror); + + // gum_arm_writer_put_breakpoint(cw); + gum_arm_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code)); } @@ -28,13 +166,32 @@ void instrument_coverage_optimize_insn(const cs_insn *instr, UNUSED_PARAMETER(instr); UNUSED_PARAMETER(output); - FFATAL("Optimized coverage not supported on this architecture"); } void instrument_coverage_optimize_init(void) { - FWARNF("Optimized coverage not supported on this architecture"); + char *shm_env = getenv(SHM_ENV_VAR); + FVERBOSE("SHM_ENV_VAR: %s", shm_env); + + if (shm_env == NULL) { + + FWARNF("SHM_ENV_VAR not set, using dummy for debugging purposes"); + + __afl_area_ptr = area_ptr_dummy; + memset(area_ptr_dummy, '\0', sizeof(area_ptr_dummy)); + + } + + FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr); + + if (instrument_previous_pc_addr == NULL) { + + instrument_previous_pc_addr = &instrument_previous_pc; + *instrument_previous_pc_addr = instrument_hash_zero; + FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr); + + } } @@ -81,6 +238,7 @@ void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) { } void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) { + int fd = (int)user_data; instrument_regs_format(fd, "r0 : 0x%08x, r1 : 0x%08x, r2 : 0x%08x, r3 : 0x%08x\n", @@ -97,6 +255,7 @@ void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) { fd, "r12: 0x%08x, sp : 0x%08x, lr : 0x%08x, pc : 0x%08x\n", cpu_context->r12, cpu_context->sp, cpu_context->lr, cpu_context->pc); instrument_regs_format(fd, "cpsr: 0x%08x\n\n", cpu_context->cpsr); + } #endif diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c index 9157f8f5..87811b38 100644 --- a/frida_mode/src/instrument/instrument_arm64.c +++ b/frida_mode/src/instrument/instrument_arm64.c @@ -407,6 +407,7 @@ void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) { } void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) { + int fd = (int)(size_t)user_data; instrument_regs_format( fd, "x0 : 0x%016x, x1 : 0x%016x, x2 : 0x%016x, x3 : 0x%016x\n", @@ -440,6 +441,7 @@ void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) { fd, "x28: 0x%016x, fp : 0x%016x, lr : 0x%016x, sp : 0x%016x\n", cpu_context->x[28], cpu_context->fp, cpu_context->lr, cpu_context->sp); instrument_regs_format(fd, "pc : 0x%016x\n\n", cpu_context->pc); + } #endif diff --git a/frida_mode/src/instrument/instrument_coverage.c b/frida_mode/src/instrument/instrument_coverage.c index 07d4d622..ff2f4024 100644 --- a/frida_mode/src/instrument/instrument_coverage.c +++ b/frida_mode/src/instrument/instrument_coverage.c @@ -9,6 +9,7 @@ #include "util.h" char *instrument_coverage_filename = NULL; +bool instrument_coverage_absolute = false; static int normal_coverage_fd = -1; static int normal_coverage_pipes[2] = {-1, -1}; @@ -237,6 +238,18 @@ static void instrument_coverage_mark(void *key, void *value, void *user_data) { } +static void instrument_coverage_mark_first(void *key, void *value, + void *user_data) { + + UNUSED_PARAMETER(key); + coverage_range_t *module = (coverage_range_t *)user_data; + normal_coverage_data_t *val = (normal_coverage_data_t *)value; + + val->module = module; + module->count++; + +} + static void coverage_write(int fd, void *data, size_t size) { ssize_t written; @@ -404,28 +417,69 @@ static void instrument_coverage_normal_run() { instrument_coverage_print("Coverage - Preparing\n"); - GArray *coverage_modules = coverage_get_modules(); + if (instrument_coverage_absolute) { - guint size = g_hash_table_size(coverage_hash); - instrument_coverage_print("Coverage - Total Entries: %u\n", size); + guint size = g_hash_table_size(coverage_hash); + instrument_coverage_print("Coverage - Total Entries: %u\n", size); - coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0}; + coverage_range_t module = { - g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx); - instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count); + .base_address = GUM_ADDRESS(0), + .limit = GUM_ADDRESS(-1), + .size = GUM_ADDRESS(-1), + .path = "absolute", + .offset = 0, + .is_executable = true, + .count = size, + .id = 0, - guint coverage_marked_modules = coverage_mark_modules(coverage_modules); - instrument_coverage_print("Coverage - Marked Modules: %u\n", - coverage_marked_modules); + }; - 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); + instrument_coverage_print("Coverage Module - 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n", + module.base_address, module.limit, module.path); - g_hash_table_unref(coverage_hash); + GArray *coverage_modules = + g_array_sized_new(false, false, sizeof(coverage_range_t), 1); + g_array_append_val(coverage_modules, module); + + g_hash_table_foreach(coverage_hash, instrument_coverage_mark_first, + &module); + + coverage_write_header(normal_coverage_fd, 1); + coverage_write_modules(normal_coverage_fd, coverage_modules); + coverage_format(normal_coverage_fd, "BB Table: %u bbs\n", size); + g_hash_table_foreach(coverage_hash, coverage_write_events, + &normal_coverage_fd); + + } else { + + GArray *coverage_modules = coverage_get_modules(); + + guint size = g_hash_table_size(coverage_hash); + instrument_coverage_print("Coverage - Total Entries: %u\n", size); + + coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0}; + + /* For each coverage event in the hashtable associate it with a module and + * count the number of entries per module */ + g_hash_table_foreach(coverage_hash, instrument_coverage_mark, &ctx); + instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count); + + /* For each module with coverage events assign it an incrementing number */ + guint coverage_marked_modules = coverage_mark_modules(coverage_modules); + instrument_coverage_print("Coverage - Marked Modules: %u\n", + coverage_marked_modules); + + 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); instrument_coverage_print("Coverage - Completed\n"); } @@ -622,8 +676,6 @@ static void instrument_coverage_unstable_run(void) { instrument_coverage_print("Coverage - Preparing\n"); - GArray *coverage_modules = coverage_get_modules(); - instrument_coverage_print("Found edges: %u\n", edges); GArray *unstable_edge_ids = instrument_coverage_unstable_read_unstable_ids(); @@ -634,20 +686,60 @@ static void instrument_coverage_unstable_run(void) { guint size = g_hash_table_size(unstable_blocks); instrument_coverage_print("Unstable blocks: %u\n", size); - coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0}; + if (instrument_coverage_absolute) { + + instrument_coverage_print("Coverage - Total Entries: %u\n", size); + + coverage_range_t module = { + + .base_address = GUM_ADDRESS(0), + .limit = GUM_ADDRESS(-1), + .size = GUM_ADDRESS(-1), + .path = "absolute", + .offset = 0, + .is_executable = true, + .count = size, + .id = 0, + + }; + + instrument_coverage_print("Coverage Module - 0x%016" G_GINT64_MODIFIER + "X - 0x%016" G_GINT64_MODIFIER "X (%s)\n", + module.base_address, module.limit, module.path); - g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx); - instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count); + GArray *coverage_modules = + g_array_sized_new(false, false, sizeof(coverage_range_t), 1); + g_array_append_val(coverage_modules, module); - guint coverage_marked_modules = coverage_mark_modules(coverage_modules); - instrument_coverage_print("Coverage - Marked Modules: %u\n", - coverage_marked_modules); + g_hash_table_foreach(unstable_blocks, instrument_coverage_mark_first, + &module); - 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); + coverage_write_header(unstable_coverage_fd, 1); + coverage_write_modules(unstable_coverage_fd, coverage_modules); + coverage_format(unstable_coverage_fd, "BB Table: %u bbs\n", size); + g_hash_table_foreach(unstable_blocks, coverage_write_events, + &unstable_coverage_fd); + + } else { + + GArray *coverage_modules = coverage_get_modules(); + + coverage_mark_ctx_t ctx = {.modules = coverage_modules, .count = 0}; + + g_hash_table_foreach(unstable_blocks, instrument_coverage_mark, &ctx); + instrument_coverage_print("Coverage - Marked Entries: %u\n", ctx.count); + + guint coverage_marked_modules = coverage_mark_modules(coverage_modules); + instrument_coverage_print("Coverage - Marked Modules: %u\n", + coverage_marked_modules); + + 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); @@ -660,6 +752,8 @@ static void instrument_coverage_unstable_run(void) { void instrument_coverage_config(void) { instrument_coverage_filename = getenv("AFL_FRIDA_INST_COVERAGE_FILE"); + instrument_coverage_absolute = + (getenv("AFL_FRIDA_INST_COVERAGE_ABSOLUTE") != NULL); } diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c index 17245d65..5577a588 100644 --- a/frida_mode/src/instrument/instrument_debug.c +++ b/frida_mode/src/instrument/instrument_debug.c @@ -63,12 +63,14 @@ static void instrument_disasm(guint8 *start, guint8 *end, count = cs_disasm(capstone, curr, size, GPOINTER_TO_SIZE(curr), 0, &insn); if (insn == NULL) { + instrument_debug("\t0x%" G_GINT64_MODIFIER "x\t* 0x%016" G_GSIZE_MODIFIER "x\n", (uint64_t)(size_t)curr, *(size_t *)curr); len += sizeof(size_t); continue; + } for (i = 0; i != count; i++) { diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c index 9d754082..13ced4a3 100644 --- a/frida_mode/src/instrument/instrument_x64.c +++ b/frida_mode/src/instrument/instrument_x64.c @@ -469,6 +469,7 @@ gpointer instrument_cur(GumStalkerOutput *output) { } void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) { + int fd = (int)(size_t)user_data; instrument_regs_format( fd, "rax: 0x%016x, rbx: 0x%016x, rcx: 0x%016x, rdx: 0x%016x\n", @@ -483,6 +484,7 @@ void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) { fd, "r12: 0x%016x, r13: 0x%016x, r14: 0x%016x, r15: 0x%016x\n", cpu_context->r12, cpu_context->r13, cpu_context->r14, cpu_context->r15); instrument_regs_format(fd, "rip: 0x%016x\n\n", cpu_context->rip); + } #endif diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c index eb0c7184..eabd5be4 100644 --- a/frida_mode/src/instrument/instrument_x86.c +++ b/frida_mode/src/instrument/instrument_x86.c @@ -271,6 +271,7 @@ void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) { } void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) { + int fd = (int)(size_t)user_data; instrument_regs_format( fd, "eax: 0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x\n", @@ -279,6 +280,7 @@ void instrument_write_regs(GumCpuContext *cpu_context, gpointer user_data) { fd, "esi: 0x%08x, edi: 0x%08x, ebp: 0x%08x, esp: 0x%08x\n", cpu_context->esi, cpu_context->edi, cpu_context->ebp, cpu_context->esp); instrument_regs_format(fd, "eip: 0x%08x\n\n", cpu_context->eip); + } #endif diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index 721ef82c..fce7a5d7 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -105,6 +105,12 @@ class Afl { Afl.jsApiSetInstrumentCacheSize(size); } /** + * See `AFL_FRIDA_INST_COVERAGE_ABSOLUTE`. + */ + static setInstrumentCoverageAbsolute() { + Afl.jsApiSetInstrumentCoverageAbsolute(); + } + /** * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string` * as an argument. */ @@ -324,6 +330,7 @@ Afl.jsApiSetCacheDisable = Afl.jsApiGetFunction("js_api_set_cache_disable", "voi Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []); Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]); Afl.jsApiSetInstrumentCacheSize = Afl.jsApiGetFunction("js_api_set_instrument_cache_size", "void", ["size_t"]); +Afl.jsApiSetInstrumentCoverageAbsolute = Afl.jsApiGetFunction("js_api_set_instrument_coverage_absolute", "void", []); Afl.jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_coverage_file", "void", ["pointer"]); Afl.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]); Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []); diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index d0c0aa60..01bba4ff 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -115,6 +115,13 @@ __attribute__((visibility("default"))) void js_api_set_instrument_libraries() { } +__attribute__((visibility("default"))) void +js_api_set_instrument_coverage_absolute(void) { + + instrument_coverage_absolute = true; + +} + __attribute__((visibility("default"))) void js_api_set_instrument_coverage_file( char *path) { @@ -158,7 +165,9 @@ __attribute__((visibility("default"))) void js_api_set_instrument_no_optimize( __attribute__((visibility("default"))) void js_api_set_instrument_regs_file( char *path) { + instrument_regs_filename = g_strdup(path); + } __attribute__((visibility("default"))) void js_api_set_instrument_seed( diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index 844c42b9..c8c50b37 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -36,6 +36,18 @@ #ifdef __APPLE__ extern mach_port_t mach_task_self(); extern GumAddress gum_darwin_find_entrypoint(mach_port_t task); +#elif defined(__ANDROID__) +typedef struct { + + void (**preinit_array)(void); + void (**init_array)(void); + void (**fini_array)(void); + +} structors_array_t; + +extern void __libc_init(void *raw_args, void (*onexit)(void) __unused, + int (*slingshot)(int, char **, char **), + structors_array_t const *const structors); #else extern int __libc_start_main(int (*main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), @@ -69,7 +81,11 @@ static void on_main_os(int argc, char **argv, char **envp) { GumInterceptor *interceptor = gum_interceptor_obtain(); gum_interceptor_begin_transaction(interceptor); + #if defined(__ANDROID__) + gum_interceptor_revert(interceptor, __libc_init); + #else gum_interceptor_revert(interceptor, __libc_start_main); + #endif gum_interceptor_end_transaction(interceptor); gum_interceptor_flush(interceptor); @@ -277,6 +293,24 @@ static void intercept_main(void) { } +#elif defined(__ANDROID__) +static void on_libc_init(void *raw_args, void (*onexit)(void) __unused, + int (*slingshot)(int, char **, char **), + structors_array_t const *const structors) { + + main_fn = slingshot; + intercept_unhook_self(); + intercept_hook(slingshot, on_main, NULL); + return __libc_init(raw_args, onexit, slingshot, structors); + +} + +static void intercept_main(void) { + + intercept_hook(__libc_init, on_libc_init, NULL); + +} + #else static int on_libc_start_main(int (*main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), diff --git a/frida_mode/src/persistent/persistent_arm32.c b/frida_mode/src/persistent/persistent_arm32.c index b4e50897..dbe51eb5 100644 --- a/frida_mode/src/persistent/persistent_arm32.c +++ b/frida_mode/src/persistent/persistent_arm32.c @@ -1,75 +1,294 @@ #include "frida-gumjs.h" +#include "instrument.h" #include "persistent.h" #include "util.h" #if defined(__arm__) -struct arm_regs { +// struct _GumArmCpuContext { - uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; +// guint32 pc; +// guint32 sp; +// guint32 cpsr; - union { +// guint32 r8; +// guint32 r9; +// guint32 r10; +// guint32 r11; +// guint32 r12; - uint32_t r11; - uint32_t fp; +// GumArmVectorReg v[16]; - }; +// guint32 _padding; - union { +// guint32 r[8]; +// guint32 lr; +// }; - uint32_t r12; - uint32_t ip; +// r11 - fp +// r12 - ip +// r13 - sp +// r14 - lr +// r15 - pc - }; +static GumCpuContext saved_regs = {0}; +static gpointer saved_lr = NULL; - union { +gboolean persistent_is_supported(void) { - uint32_t r13; - uint32_t sp; + return true; - }; +} - union { +static void instrument_persitent_save_regs(GumArmWriter *cw, + GumCpuContext *regs) { + + /* Save Regs */ + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP, + GUM_RED_ZONE_SIZE); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_SP, + GUM_RED_ZONE_SIZE + sizeof(guint32)); + + gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(regs)); + + /* Save r1-r7 */ + for (size_t i = ARM_REG_R1; i < ARM_REG_R8; i++) { + + gum_arm_writer_put_str_reg_reg_offset( + cw, i, ARM_REG_R0, offsetof(GumCpuContext, r[i - ARM_REG_R0])); + + } + + /* Save r8-r12 */ + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R8, ARM_REG_R0, + offsetof(GumCpuContext, r8)); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R9, ARM_REG_R0, + offsetof(GumCpuContext, r9)); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R10, ARM_REG_R0, + offsetof(GumCpuContext, r10)); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R11, ARM_REG_R0, + offsetof(GumCpuContext, r11)); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R12, ARM_REG_R0, + offsetof(GumCpuContext, r12)); + + /* Save sp & lr */ + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_SP, ARM_REG_R0, + offsetof(GumCpuContext, sp)); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0, + offsetof(GumCpuContext, lr)); + + /* Save r0 (load from stack into r1) */ + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_SP, + GUM_RED_ZONE_SIZE); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0, + offsetof(GumCpuContext, r[0])); + + /* Save CPSR */ + gum_arm_writer_put_mov_reg_cpsr(cw, ARM_REG_R1); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0, + offsetof(GumCpuContext, cpsr)); + + /* Save PC */ + gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R1, + GUM_ADDRESS(persistent_start)); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0, + offsetof(GumCpuContext, pc)); + + /* Restore Regs */ + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_SP, + GUM_RED_ZONE_SIZE + sizeof(guint32)); + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP, + GUM_RED_ZONE_SIZE); - uint32_t r14; - uint32_t lr; +} - }; +static void instrument_persitent_restore_regs(GumArmWriter *cw, + GumCpuContext *regs) { - union { + gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(regs)); - uint32_t r15; - uint32_t pc; + /* Restore CPSR */ + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0, + offsetof(GumCpuContext, cpsr)); + gum_arm_writer_put_mov_cpsr_reg(cw, ARM_REG_R1); - }; + /* Restore sp & lr */ + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_SP, ARM_REG_R0, + offsetof(GumCpuContext, sp)); + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0, + offsetof(GumCpuContext, lr)); - uint32_t cpsr; + /* Restore r8-r12 */ + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R8, ARM_REG_R0, + offsetof(GumCpuContext, r8)); + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R9, ARM_REG_R0, + offsetof(GumCpuContext, r9)); + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R10, ARM_REG_R0, + offsetof(GumCpuContext, r10)); + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R11, ARM_REG_R0, + offsetof(GumCpuContext, r11)); + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R12, ARM_REG_R0, + offsetof(GumCpuContext, r12)); - uint8_t vfp_zregs[32][16]; - uint32_t vfp_xregs[16]; + /* Restore r7-r0 */ + for (size_t i = ARM_REG_R7; i >= ARM_REG_R0; i--) { -}; + gum_arm_writer_put_ldr_reg_reg_offset( + cw, i, ARM_REG_R0, offsetof(GumCpuContext, r[i - ARM_REG_R0])); -typedef struct arm_regs arch_api_regs; + } -gboolean persistent_is_supported(void) { +} + +static void instrument_exit(GumArmWriter *cw) { + + gum_arm_writer_put_sub_reg_reg_reg(cw, ARM_REG_R0, ARM_REG_R0, ARM_REG_R0); + gum_arm_writer_put_call_address_with_arguments(cw, GUM_ADDRESS(_exit), 1, + GUM_ARG_REGISTER, ARM_REG_R0); + +} + +static int instrument_afl_persistent_loop_func(void) { + + int ret = __afl_persistent_loop(persistent_count); + if (instrument_previous_pc_addr == NULL) { + + FATAL("instrument_previous_pc_addr uninitialized"); + + } - return false; + *instrument_previous_pc_addr = instrument_hash_zero; + return ret; + +} + +static void instrument_afl_persistent_loop(GumArmWriter *cw) { + + gum_arm_writer_put_sub_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP, + GUM_RED_ZONE_SIZE); + gum_arm_writer_put_call_address_with_arguments( + cw, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0); + gum_arm_writer_put_add_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP, + GUM_RED_ZONE_SIZE); + +} + +static void persistent_prologue_hook(GumArmWriter *cw, GumCpuContext *regs) { + + if (persistent_hook == NULL) return; + + gum_arm_writer_put_sub_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP, + GUM_RED_ZONE_SIZE); + gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R2, + GUM_ADDRESS(&__afl_fuzz_len)); + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R2, ARM_REG_R2, 0); + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R2, ARM_REG_R2, 0); + + gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R1, + GUM_ADDRESS(&__afl_fuzz_ptr)); + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R1, 0); + + gum_arm_writer_put_call_address_with_arguments( + cw, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS, GUM_ADDRESS(regs), + GUM_ARG_REGISTER, ARM_REG_R1, GUM_ARG_REGISTER, ARM_REG_R2); + + gum_arm_writer_put_add_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP, + GUM_RED_ZONE_SIZE); + +} + +static void instrument_persitent_save_lr(GumArmWriter *cw) { + + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP, + GUM_RED_ZONE_SIZE); + + gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(&saved_lr)); + gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0, 0); + + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP, + GUM_RED_ZONE_SIZE); } void persistent_prologue_arch(GumStalkerOutput *output) { - UNUSED_PARAMETER(output); - FFATAL("Persistent mode not supported on this architecture"); + /* + * SAVE REGS + * SAVE RET + * POP RET + * loop: + * CALL instrument_afl_persistent_loop + * TEST EAX, EAX + * JZ end: + * call hook (optionally) + * RESTORE REGS + * call original + * jmp loop: + * + * end: + * JMP SAVED RET + * + * original: + * INSTRUMENTED PERSISTENT FUNC + */ + + GumArmWriter *cw = output->writer.arm; + + gconstpointer loop = cw->code + 1; + + FVERBOSE("Persistent loop reached"); + + instrument_persitent_save_regs(cw, &saved_regs); + + /* loop: */ + gum_arm_writer_put_label(cw, loop); + + /* call instrument_prologue_func */ + instrument_afl_persistent_loop(cw); + + /* jz done */ + gconstpointer done = cw->code + 1; + gum_arm_writer_put_cmp_reg_imm(cw, ARM_REG_R0, 0); + gum_arm_writer_put_b_cond_label(cw, ARM_CC_EQ, done); + + /* Optionally call the persistent hook */ + persistent_prologue_hook(cw, &saved_regs); + + instrument_persitent_restore_regs(cw, &saved_regs); + gconstpointer original = cw->code + 1; + /* call original */ + + gum_arm_writer_put_bl_label(cw, original); + + /* jmp loop */ + gum_arm_writer_put_b_label(cw, loop); + + /* done: */ + gum_arm_writer_put_label(cw, done); + + instrument_exit(cw); + + /* original: */ + gum_arm_writer_put_label(cw, original); + + instrument_persitent_save_lr(cw); + + if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); } } void persistent_epilogue_arch(GumStalkerOutput *output) { - UNUSED_PARAMETER(output); - FFATAL("Persistent mode not supported on this architecture"); + GumArmWriter *cw = output->writer.arm; + + if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); } + + gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(&saved_lr)); + + gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_R0, 0); + + gum_arm_writer_put_bx_reg(cw, ARM_REG_R0); } diff --git a/frida_mode/src/prefetch.c b/frida_mode/src/prefetch.c index 5621a685..905e0ae9 100644 --- a/frida_mode/src/prefetch.c +++ b/frida_mode/src/prefetch.c @@ -1,12 +1,11 @@ #include <errno.h> -#include <sys/shm.h> -#include <sys/mman.h> #include "frida-gumjs.h" #include "entry.h" #include "intercept.h" #include "prefetch.h" +#include "shm.h" #include "stalker.h" #include "util.h" @@ -285,28 +284,7 @@ void prefetch_init(void) { * with the coverage bitmap region and fork will take care of ensuring both * the parent and child see the same consistent memory region. */ - prefetch_shm_id = - shmget(IPC_PRIVATE, sizeof(prefetch_data_t), IPC_CREAT | IPC_EXCL | 0600); - if (prefetch_shm_id < 0) { - - FFATAL("prefetch_shm_id < 0 - errno: %d\n", errno); - - } - - prefetch_data = shmat(prefetch_shm_id, NULL, 0); - g_assert(prefetch_data != MAP_FAILED); - - /* - * Configure the shared memory region to be removed once the process dies. - */ - if (shmctl(prefetch_shm_id, IPC_RMID, NULL) < 0) { - - FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); - - } - - /* Clear it, not sure it's necessary, just seems like good practice */ - memset(prefetch_data, '\0', sizeof(prefetch_data_t)); + prefetch_data = shm_create(sizeof(prefetch_data_t)); prefetch_hook_fork(); diff --git a/frida_mode/src/seccomp/seccomp.c b/frida_mode/src/seccomp/seccomp.c index 984a3990..12b58f4e 100644 --- a/frida_mode/src/seccomp/seccomp.c +++ b/frida_mode/src/seccomp/seccomp.c @@ -11,6 +11,8 @@ void seccomp_on_fork(void) { #ifdef __APPLE__ FFATAL("Seccomp not supported on OSX"); +#elif defined(__ANDROID__) + FFATAL("Seccomp not supported on Android"); #else seccomp_callback_parent(); #endif @@ -32,6 +34,8 @@ void seccomp_init(void) { #ifdef __APPLE__ FFATAL("Seccomp not supported on OSX"); +#elif defined(__ANDROID__) + FFATAL("Seccomp not supported on Android"); #else seccomp_callback_initialize(); #endif diff --git a/frida_mode/src/shm.c b/frida_mode/src/shm.c new file mode 100644 index 00000000..282526e8 --- /dev/null +++ b/frida_mode/src/shm.c @@ -0,0 +1,87 @@ +#include "shm.h" +#include "util.h" + +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <sys/ipc.h> +#include <sys/mman.h> +#include <sys/shm.h> +#ifdef __ANDROID__ + #include <linux/ashmem.h> + #include <sys/ioctl.h> +#endif + +#ifdef __ANDROID__ + #define ASHMEM_DEVICE "/dev/ashmem" + +void *shm_create(size_t size) { + + int fd = -1; + char ourkey[11] = {0}; + void *addr = MAP_FAILED; + struct ashmem_pin pin = {0, size}; + + fd = open(ASHMEM_DEVICE, O_RDWR); + if (fd < 0) { FFATAL("Failed open /dev/ashmem: %d", errno); } + + if (snprintf(ourkey, sizeof(ourkey) - 1, "%d", IPC_PRIVATE) < 0) { + + FFATAL("Failed to generate key: %d", errno); + + } + + if (ioctl(fd, ASHMEM_SET_NAME, ourkey) < 0) { + + FFATAL("ioctl(ASHMEM_SET_NAME) errno: %d\n", errno); + + } + + if (ioctl(fd, ASHMEM_SET_SIZE, size) < 0) { + + FFATAL("ioctl(ASHMEM_SET_SIZE) errno: %d\n", errno); + + } + + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { FFATAL("mmap failed: %d\n", errno); } + + /* Shared memory pinning has been deprecated. So if the ioctl fails, then + just assume we are running on a version where it has been. Worst case, we + will leak the shared memory region.*/ + ioctl(fd, ASHMEM_UNPIN, &pin); + close(fd); + + return addr; + +} + +#else +void *shm_create(size_t size) { + + int shm_id = + shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR); + if (shm_id < 0) { FFATAL("shm_id < 0 - errno: %d\n", errno); } + + void *addr = shmat(shm_id, NULL, 0); + if (addr == MAP_FAILED) { FFATAL("addr == MAP_FAILED - errno: %d\n", errno); } + + /* + * Configure the shared memory region to be removed once the process + * dies. + */ + if (shmctl(shm_id, IPC_RMID, NULL) < 0) { + + FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); + + } + + /* Clear it, not sure it's necessary, just seems like good practice */ + memset(addr, '\0', size); + + return addr; + +} + +#endif + diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c index af08cd71..1d3520bc 100644 --- a/frida_mode/src/stats/stats.c +++ b/frida_mode/src/stats/stats.c @@ -2,17 +2,16 @@ #include <fcntl.h> #include <stdio.h> #include <unistd.h> -#include <sys/shm.h> #include <sys/mman.h> #include "frida-gumjs.h" #include "config.h" -#include "util.h" - #include "entry.h" +#include "shm.h" #include "stalker.h" #include "stats.h" +#include "util.h" #define MICRO_TO_SEC 1000000 @@ -360,27 +359,10 @@ void stats_init(void) { g_free(path); - int shm_id = - shmget(IPC_PRIVATE, sizeof(stats_data_t), IPC_CREAT | IPC_EXCL | 0600); - if (shm_id < 0) { FFATAL("shm_id < 0 - errno: %d\n", errno); } - - stats_data = shmat(shm_id, NULL, 0); - g_assert(stats_data != MAP_FAILED); - GumStalkerObserver *observer = stalker_get_observer(); stats_observer_init(observer); - /* - * Configure the shared memory region to be removed once the process dies. - */ - if (shmctl(shm_id, IPC_RMID, NULL) < 0) { - - FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); - - } - - /* Clear it, not sure it's necessary, just seems like good practice */ - memset(stats_data, '\0', sizeof(stats_data_t)); + stats_data = shm_create(sizeof(stats_data_t)); starts_arch_init(); diff --git a/frida_mode/src/stats/stats_arm64.c b/frida_mode/src/stats/stats_arm64.c index 313ab47a..ea283dbe 100644 --- a/frida_mode/src/stats/stats_arm64.c +++ b/frida_mode/src/stats/stats_arm64.c @@ -1,9 +1,9 @@ -#include <sys/shm.h> #include <sys/mman.h> #include "frida-gumjs.h" #include "ranges.h" +#include "shm.h" #include "stats.h" #include "util.h" @@ -44,24 +44,7 @@ static stats_data_arch_t *stats_data_arch = NULL; void starts_arch_init(void) { - int shm_id = shmget(IPC_PRIVATE, sizeof(stats_data_arch_t), - IPC_CREAT | IPC_EXCL | 0600); - if (shm_id < 0) { FFATAL("shm_id < 0 - errno: %d\n", errno); } - - stats_data_arch = shmat(shm_id, NULL, 0); - g_assert(stats_data_arch != MAP_FAILED); - - /* - * Configure the shared memory region to be removed once the process dies. - */ - if (shmctl(shm_id, IPC_RMID, NULL) < 0) { - - FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); - - } - - /* Clear it, not sure it's necessary, just seems like good practice */ - memset(stats_data_arch, '\0', sizeof(stats_data_arch_t)); + stats_data_arch = shm_create(sizeof(stats_data_arch_t)); } diff --git a/frida_mode/src/stats/stats_x86_64.c b/frida_mode/src/stats/stats_x86_64.c index 761ca133..e2fb7b80 100644 --- a/frida_mode/src/stats/stats_x86_64.c +++ b/frida_mode/src/stats/stats_x86_64.c @@ -1,9 +1,9 @@ -#include <sys/shm.h> #include <sys/mman.h> #include "frida-gumjs.h" #include "ranges.h" +#include "shm.h" #include "stats.h" #include "util.h" @@ -46,24 +46,7 @@ static stats_data_arch_t *stats_data_arch = NULL; void starts_arch_init(void) { - int shm_id = shmget(IPC_PRIVATE, sizeof(stats_data_arch_t), - IPC_CREAT | IPC_EXCL | 0600); - if (shm_id < 0) { FFATAL("shm_id < 0 - errno: %d\n", errno); } - - stats_data_arch = shmat(shm_id, NULL, 0); - g_assert(stats_data_arch != MAP_FAILED); - - /* - * Configure the shared memory region to be removed once the process dies. - */ - if (shmctl(shm_id, IPC_RMID, NULL) < 0) { - - FFATAL("shmctl (IPC_RMID) < 0 - errno: %d\n", errno); - - } - - /* Clear it, not sure it's necessary, just seems like good practice */ - memset(stats_data_arch, '\0', sizeof(stats_data_arch_t)); + stats_data_arch = shm_create(sizeof(stats_data_arch_t)); } diff --git a/frida_mode/test/unstable/unstable.c b/frida_mode/test/unstable/unstable.c index 915e283f..7d16c26c 100644 --- a/frida_mode/test/unstable/unstable.c +++ b/frida_mode/test/unstable/unstable.c @@ -14,6 +14,7 @@ #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <sys/time.h> #ifdef __APPLE__ #define TESTINSTR_SECTION @@ -25,8 +26,10 @@ void LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size < 1) return; - int r = rand(); - if ((r % 2) == 0) { + struct timeval tv = {0}; + if (gettimeofday(&tv, NULL) < 0) return; + + if ((tv.tv_usec % 2) == 0) { printf ("Hooray all even\n"); } else { printf ("Hmm that's odd\n"); diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index 455d4305..7a83c0fb 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/frida_mode/ts/lib/afl.ts @@ -126,6 +126,13 @@ class Afl { } /** + * See `AFL_FRIDA_INST_COVERAGE_ABSOLUTE`. + */ + public static setInstrumentCoverageAbsolute(): void { + Afl.jsApiSetInstrumentCoverageAbsolute(); + } + + /** * See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string` * as an argument. */ @@ -398,6 +405,12 @@ class Afl { "void", ["size_t"]); + private static readonly jsApiSetInstrumentCoverageAbsolute = Afl.jsApiGetFunction( + "js_api_set_instrument_coverage_absolute", + "void", + [] + ); + private static readonly jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction( "js_api_set_instrument_coverage_file", "void", diff --git a/include/config.h b/include/config.h index 0ae6c271..d7a08428 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++4.02a" +#define VERSION "++4.02c" /****************************************************** * * diff --git a/include/envs.h b/include/envs.h index 853edbd9..52f2d09b 100644 --- a/include/envs.h +++ b/include/envs.h @@ -58,6 +58,7 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_DRIVER_NO_HOOK", "AFL_FRIDA_EXCLUDE_RANGES", "AFL_FRIDA_INST_CACHE_SIZE", + "AFL_FRIDA_INST_COVERAGE_ABSOLUTE", "AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE", "AFL_FRIDA_INST_INSN", |