#include "frida-gumjs.h" #include "instrument.h" #include "stalker.h" #include "util.h" #if defined(__i386__) gboolean instrument_cache_enabled = FALSE; gsize instrument_cache_size = 0; static GHashTable *coverage_blocks = NULL; #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; uint8_t mov_eax_esp_4[4]; uint8_t lahf; uint8_t mov_eax_esp_8[4]; uint8_t mov_ebx_esp_c[4]; uint8_t mov_eax_prev_loc[5]; uint8_t mov_prev_loc_curr_loc_shr1[10]; uint8_t xor_eax_curr_loc[5]; uint8_t add_eax_area_ptr[5]; uint8_t mov_ebx_ptr_eax[2]; uint8_t add_bl_1[3]; uint8_t adc_bl_0[3]; uint8_t mov_ptr_eax_ebx[2]; uint8_t mov_esp_c_ebx[4]; uint8_t mov_esp_8_eax[4]; uint8_t sahf; uint8_t mov_esp_4_eax[4]; } afl_log_code_asm_t; #pragma pack(pop) typedef union { afl_log_code_asm_t code; uint8_t bytes[0]; } afl_log_code; static const afl_log_code_asm_t template = { .mov_eax_esp_4 = {0x89, 0x44, 0x24, 0xFC}, .lahf = 0x9f, .mov_eax_esp_8 = {0x89, 0x44, 0x24, 0xF8}, .mov_ebx_esp_c = {0x89, 0x5C, 0x24, 0xF4}, .mov_eax_prev_loc = {0xA1}, .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05}, .xor_eax_curr_loc = {0x35}, .add_eax_area_ptr = {0x05}, .mov_ebx_ptr_eax = {0x8a, 0x18}, .add_bl_1 = {0x80, 0xc3, 0x01}, .adc_bl_0 = {0x80, 0xd3, 0x00}, .mov_ptr_eax_ebx = {0x88, 0x18}, .mov_esp_c_ebx = {0x8B, 0x5C, 0x24, 0xF4}, .mov_esp_8_eax = {0x8B, 0x44, 0x24, 0xF8}, .sahf = 0x9e, .mov_esp_4_eax = {0x8B, 0x44, 0x24, 0xFC}, } ; gboolean instrument_is_coverage_optimize_supported(void) { return true; } static void instrument_coverage_switch(GumStalkerObserver *self, gpointer from_address, gpointer start_address, const cs_insn *from_insn, gpointer *target) { UNUSED_PARAMETER(self); UNUSED_PARAMETER(from_address); UNUSED_PARAMETER(start_address); cs_x86 *x86; cs_x86_op *op; if (from_insn == NULL) { return; } x86 = &from_insn->detail->x86; op = x86->operands; if (!g_hash_table_contains(coverage_blocks, GSIZE_TO_POINTER(*target))) { return; } switch (from_insn->id) { case X86_INS_CALL: case X86_INS_JMP: if (x86->op_count != 1) { FATAL("Unexpected operand count: %d", x86->op_count); } if (op[0].type != X86_OP_IMM) { return; } break; case X86_INS_RET: break; default: return; } *target = (guint8 *)*target + sizeof(afl_log_code); } static void instrument_coverage_suppress_init(void) { static gboolean initialized = false; if (initialized) { return; } initialized = true; GumStalkerObserver *observer = stalker_get_observer(); GumStalkerObserverInterface *iface = GUM_STALKER_OBSERVER_GET_IFACE(observer); iface->switch_callback = instrument_coverage_switch; coverage_blocks = g_hash_table_new(g_direct_hash, g_direct_equal); if (coverage_blocks == NULL) { FATAL("Failed to g_hash_table_new, errno: %d", errno); } } void instrument_coverage_optimize(const cs_insn *instr, GumStalkerOutput *output) { afl_log_code code = {0}; GumX86Writer *cw = output->writer.x86; guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address)); gsize map_size_pow2; gsize area_offset_ror; if (instrument_previous_pc_addr == NULL) { GumAddressSpec spec = {.near_address = cw->code, .max_distance = 1ULL << 30}; guint page_size = gum_query_page_size(); instrument_previous_pc_addr = gum_memory_allocate_near( &spec, sizeof(guint64), page_size, GUM_PAGE_READ | GUM_PAGE_WRITE); *instrument_previous_pc_addr = instrument_hash_zero; FVERBOSE("instrument_previous_pc_addr: %p", instrument_previous_pc_addr); FVERBOSE("code_addr: %p", cw->code); } code.code = template; instrument_coverage_suppress_init(); // gum_x86_writer_put_breakpoint(cw); if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) { FATAL("Failed - g_hash_table_add"); } gssize prev_loc_value_offset2 = offsetof(afl_log_code, code.mov_eax_prev_loc) + sizeof(code.code.mov_eax_prev_loc) - sizeof(gint); *((gint *)&code.bytes[prev_loc_value_offset2]) = (gint)GPOINTER_TO_SIZE(instrument_previous_pc_addr); gssize curr_loc_shr_1_offset = offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) + sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(guint32); map_size_pow2 = util_log2(__afl_map_size); area_offset_ror = util_rotate(area_offset, 1, map_size_pow2); *((guint32 *)&code.bytes[curr_loc_shr_1_offset]) = (guint32)(area_offset_ror); gssize prev_loc_value_offset = offsetof(afl_log_code, code.mov_prev_loc_curr_loc_shr1) + sizeof(code.code.mov_prev_loc_curr_loc_shr1) - sizeof(gint) - sizeof(guint32); *((gint *)&code.bytes[prev_loc_value_offset]) = (gint)GPOINTER_TO_SIZE(instrument_previous_pc_addr); gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) + sizeof(code.code.xor_eax_curr_loc) - sizeof(guint32); *((guint32 *)&code.bytes[xor_curr_loc_offset]) = (guint32)area_offset; gssize add_area_ptr_offset = offsetof(afl_log_code, code.add_eax_area_ptr) + sizeof(code.code.add_eax_area_ptr) - sizeof(guint32); *((guint32 *)&code.bytes[add_area_ptr_offset]) = (guint32)__afl_area_ptr; gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code)); } void instrument_coverage_optimize_insn(const cs_insn *instr, GumStalkerOutput *output) { UNUSED_PARAMETER(instr); UNUSED_PARAMETER(output); } void instrument_coverage_optimize_init(void) { } void instrument_flush(GumStalkerOutput *output) { gum_x86_writer_flush(output->writer.x86); } gpointer instrument_cur(GumStalkerOutput *output) { return gum_x86_writer_cur(output->writer.x86); } void instrument_cache_config(void) { } void instrument_cache_init(void) { } void instrument_cache_insert(gpointer real_address, gpointer code_address) { UNUSED_PARAMETER(real_address); UNUSED_PARAMETER(code_address); } void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) { UNUSED_PARAMETER(instr); UNUSED_PARAMETER(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", cpu_context->eax, cpu_context->ebx, cpu_context->ecx, cpu_context->edx); instrument_regs_format( 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