diff options
author | van Hauser <vh@thc.org> | 2022-08-04 21:36:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-04 21:36:59 +0200 |
commit | 4b9c560b07e1ea42633b59e0eb94f7a3f0fe0c58 (patch) | |
tree | a00dcc353fd4add31a2c1e75bc2a4ac79419570c | |
parent | 6056d4b140f0665c6a701cada9166379be3435ac (diff) | |
parent | 9d5a2d1b8e6f4ead25a857d106b37fd85950aff3 (diff) | |
download | afl++-4b9c560b07e1ea42633b59e0eb94f7a3f0fe0c58.tar.gz |
Merge pull request #1486 from WorksButNotTested/be8
Be8
-rw-r--r-- | frida_mode/GNUmakefile | 14 | ||||
-rw-r--r-- | frida_mode/README.md | 2 | ||||
-rw-r--r-- | frida_mode/frida.map | 1 | ||||
-rw-r--r-- | frida_mode/hook/frida_hook.c | 12 | ||||
-rw-r--r-- | frida_mode/include/instrument.h | 3 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument.c | 11 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument_arm32.c | 158 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument_arm64.c | 2 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument_coverage.c | 150 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument_debug.c | 2 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument_x64.c | 2 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument_x86.c | 2 | ||||
-rw-r--r-- | frida_mode/src/js/api.js | 7 | ||||
-rw-r--r-- | frida_mode/src/js/js_api.c | 9 | ||||
-rw-r--r-- | frida_mode/src/persistent/persistent_arm32.c | 262 | ||||
-rw-r--r-- | frida_mode/test/unstable/unstable.c | 7 | ||||
-rw-r--r-- | frida_mode/ts/lib/afl.ts | 13 | ||||
-rw-r--r-- | include/envs.h | 1 |
18 files changed, 581 insertions, 77 deletions
diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index bc7df6c0..256bea02 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -43,10 +43,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) @@ -110,6 +112,7 @@ 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 +160,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 @@ -353,6 +356,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) 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/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 93c498e8..0e286eab 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -33,7 +33,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 +237,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 +277,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) { @@ -404,6 +408,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 +420,7 @@ void instrument_init(void) { if (regs_fd < 0) { FFATAL("Failed to open regs file '%s'", path); } g_free(path); + } asan_init(); @@ -444,6 +450,7 @@ void instrument_on_fork() { } void instrument_regs_format(int fd, char *format, ...) { + va_list ap; char buffer[4096] = {0}; int ret; @@ -458,4 +465,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..0ff69952 100644 --- a/frida_mode/src/instrument/instrument_arm32.c +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -5,22 +5,150 @@ #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; -gboolean instrument_is_coverage_optimize_supported(void) { +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] */ - return false; + /* 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 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) { + 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; - UNUSED_PARAMETER(instr); - UNUSED_PARAMETER(output); - FFATAL("Optimized coverage not supported on this architecture"); + // 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)); } void instrument_coverage_optimize_insn(const cs_insn *instr, @@ -28,14 +156,26 @@ 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) { + 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"); - FWARNF("Optimized coverage not supported on this architecture"); + __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); + } } void instrument_flush(GumStalkerOutput *output) { @@ -81,6 +221,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 +238,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..25913585 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/persistent/persistent_arm32.c b/frida_mode/src/persistent/persistent_arm32.c index b4e50897..a2b63652 100644 --- a/frida_mode/src/persistent/persistent_arm32.c +++ b/frida_mode/src/persistent/persistent_arm32.c @@ -1,76 +1,268 @@ #include "frida-gumjs.h" +#include "instrument.h" #include "persistent.h" #include "util.h" #if defined(__arm__) -struct arm_regs { +// struct _GumArmCpuContext { +// guint32 pc; +// guint32 sp; +// guint32 cpsr; - uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; +// guint32 r8; +// guint32 r9; +// guint32 r10; +// guint32 r11; +// guint32 r12; - union { +// GumArmVectorReg v[16]; - uint32_t r11; - uint32_t fp; +// guint32 _padding; - }; +// guint32 r[8]; +// guint32 lr; +// }; - union { +// r11 - fp +// r12 - ip +// r13 - sp +// r14 - lr +// r15 - pc - uint32_t r12; - uint32_t ip; +static GumCpuContext saved_regs = {0}; +static gpointer saved_lr = NULL; - }; - - union { - - uint32_t r13; - uint32_t sp; +gboolean persistent_is_supported(void) { + return true; +} - }; +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); +} - union { +static void instrument_persitent_restore_regs(GumArmWriter * cw, + GumCpuContext *regs) { + gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(regs)); + + /* 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)); + + /* 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)); + + /* 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])); + } +} - uint32_t r14; - uint32_t lr; +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"); + } - union { + *instrument_previous_pc_addr = instrument_hash_zero; + return ret; +} - uint32_t r15; - uint32_t pc; +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; - uint32_t cpsr; + 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); - uint8_t vfp_zregs[32][16]; - uint32_t vfp_xregs[16]; + 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); -typedef struct arm_regs arch_api_regs; + gum_arm_writer_put_add_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP, + GUM_RED_ZONE_SIZE); +} -gboolean persistent_is_supported(void) { +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); - return false; + 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) { + /* + * 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"); - UNUSED_PARAMETER(output); - FFATAL("Persistent mode not supported on this architecture"); + 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) { + 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)); - UNUSED_PARAMETER(output); - FFATAL("Persistent mode not supported on this architecture"); + 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); } #endif 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/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", |