diff options
36 files changed, 1196 insertions, 367 deletions
diff --git a/docs/env_variables.md b/docs/env_variables.md index 4626a9b6..edd57fb6 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -518,7 +518,12 @@ checks or alter some of the more exotic semantics of the tool: the target binary. Example: `AFL_TARGET_ENV="VAR1=1 VAR2='a b c'" afl-fuzz ... `. This exists mostly for things like `LD_LIBRARY_PATH` but it would theoretically allow fuzzing of AFL++ itself (with 'target' AFL++ using some - AFL_ vars that would disrupt work of 'fuzzer' AFL++). + AFL_ vars that would disrupt work of 'fuzzer' AFL++). Note that when using + QEMU mode, the `AFL_TARGET_ENV` environment variables will apply to QEMU, as + well as the target binary. Therefore, in this case, you might want to use + QEMU's `QEMU_SET_ENV` environment variable (see QEMU's documentation because + the format is different from `AFL_TARGET_ENV`) to apply the environment + variables to the target and not QEMU. - `AFL_TESTCACHE_SIZE` allows you to override the size of `#define TESTCASE_CACHE` in config.h. Recommended values are 50-250MB - or more if diff --git a/frida_mode/README.md b/frida_mode/README.md index e5b46baf..50e3b8d7 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -170,6 +170,8 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent *** ``` +* `AFL_FRIDA_INST_INSN` - Generate instrumentation for conditional + instructions (e.g. `CMOV` instructions on x64). * `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled code. Code is considered to be JIT if the executable segment is not backed by a file. diff --git a/frida_mode/frida.map b/frida_mode/frida.map index d059bdb6..41220d4b 100644 --- a/frida_mode/frida.map +++ b/frida_mode/frida.map @@ -15,6 +15,7 @@ js_api_set_instrument_debug_file; js_api_set_instrument_jit; js_api_set_instrument_libraries; + js_api_set_instrument_instructions; js_api_set_instrument_no_optimize; js_api_set_instrument_seed; js_api_set_instrument_trace; diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index abb89c9f..20312a4b 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -12,6 +12,7 @@ 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 gboolean instrument_use_fixed_seed; extern guint64 instrument_fixed_seed; @@ -33,6 +34,8 @@ gboolean instrument_is_coverage_optimize_supported(void); void instrument_coverage_optimize_init(void); void instrument_coverage_optimize(const cs_insn * instr, GumStalkerOutput *output); +void instrument_coverage_optimize_insn(const cs_insn * instr, + GumStalkerOutput *output); void instrument_debug_config(void); void instrument_debug_init(void); diff --git a/frida_mode/include/module.h b/frida_mode/include/module.h new file mode 100644 index 00000000..b66f7feb --- /dev/null +++ b/frida_mode/include/module.h @@ -0,0 +1,11 @@ +#ifndef _MODULE_H +#define _MODULE_H + +#include "frida-gumjs.h" + +void module_config(void); + +void module_init(void); + +#endif + diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 418b35e8..43560478 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -29,6 +29,7 @@ guint64 instrument_hash_seed = 0; gboolean instrument_use_fixed_seed = FALSE; guint64 instrument_fixed_seed = 0; char * instrument_coverage_unstable_filename = NULL; +gboolean instrument_coverage_insn = FALSE; static GumStalkerTransformer *transformer = NULL; @@ -233,6 +234,12 @@ static void instrument_basic_block(GumStalkerIterator *iterator, } + if (instrument_coverage_insn) { + + instrument_coverage_optimize_insn(instr, output); + + } + instrument_debug_instruction(instr->address, instr->size, output); if (likely(!excluded)) { @@ -269,6 +276,7 @@ void instrument_config(void) { instrument_fixed_seed = util_read_num("AFL_FRIDA_INST_SEED", 0); instrument_coverage_unstable_filename = (getenv("AFL_FRIDA_INST_UNSTABLE_COVERAGE_FILE")); + instrument_coverage_insn = (getenv("AFL_FRIDA_INST_INSN") != NULL); instrument_debug_config(); instrument_coverage_config(); @@ -294,6 +302,8 @@ void instrument_init(void) { instrument_coverage_unstable_filename == NULL ? " " : instrument_coverage_unstable_filename); + FOKF(cBLU "Instrumentation" cRST " - " cGRN "instructions:" cYEL " [%c]", + instrument_coverage_insn ? 'X' : ' '); if (instrument_tracing && instrument_optimize) { diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c index 16e8eaab..705faa64 100644 --- a/frida_mode/src/instrument/instrument_arm32.c +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -20,6 +20,15 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_coverage_optimize_insn(const cs_insn * instr, + GumStalkerOutput *output) { + + 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"); diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c index 1a704585..4abc0625 100644 --- a/frida_mode/src/instrument/instrument_arm64.c +++ b/frida_mode/src/instrument/instrument_arm64.c @@ -341,6 +341,14 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_coverage_optimize_insn(const cs_insn * instr, + GumStalkerOutput *output) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(output); + +} + void instrument_coverage_optimize_init(void) { char *shm_env = getenv(SHM_ENV_VAR); diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c index fb84d6d2..4b1a2d68 100644 --- a/frida_mode/src/instrument/instrument_x64.c +++ b/frida_mode/src/instrument/instrument_x64.c @@ -23,13 +23,39 @@ #if defined(__x86_64__) - #ifndef MAP_FIXED_NOREPLACE - #ifdef MAP_EXCL - #define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED - #else - #define MAP_FIXED_NOREPLACE MAP_FIXED - #endif - #endif +enum jcc_opcodes { + + OPC_JO = 0x70, + OPC_JNO = 0x71, + OPC_JB = 0x72, + OPC_JAE = 0x73, + OPC_JE = 0x74, + OPC_JNE = 0x75, + OPC_JBE = 0x76, + OPC_JA = 0x77, + OPC_JS = 0x78, + OPC_JNS = 0x79, + OPC_JP = 0x7a, + OPC_JNP = 0x7b, + OPC_JL = 0x7c, + OPC_JGE = 0x7d, + OPC_JLE = 0x7e, + OPC_JG = 0x7f, + +}; + +typedef union { + + struct { + + uint8_t opcode; + uint8_t distance; + + }; + + uint8_t bytes[0]; + +} jcc_insn; static GHashTable *coverage_blocks = NULL; @@ -45,8 +71,7 @@ static gboolean instrument_coverage_in_range(gssize offset) { } - #ifdef __APPLE__ - #pragma pack(push, 1) + #pragma pack(push, 1) typedef struct { @@ -54,95 +79,28 @@ typedef struct { // shared_mem[cur_location ^ prev_location]++; // prev_location = cur_location >> 1; - // mov QWORD PTR [rsp-0x80],rax - // lahf - // mov QWORD PTR [rsp-0x88],rax - // mov QWORD PTR [rsp-0x90],rbx - // mov eax,DWORD PTR [rip+0x333d5a] # 0x7ffff6ff2740 - // mov DWORD PTR [rip+0x333d3c],0x9fbb # 0x7ffff6ff2740 - // lea rax,[rip + 0x103f77] - // mov bl,BYTE PTR [rax] - // add bl,0x1 - // adc bl,0x0 - // mov BYTE PTR [rax],bl - // mov rbx,QWORD PTR [rsp-0x90] - // mov rax,QWORD PTR [rsp-0x88] - // sahf - // mov rax,QWORD PTR [rsp-0x80] - - uint8_t mov_rax_rsp_88[8]; - uint8_t lahf; - uint8_t mov_rax_rsp_90[8]; - uint8_t mov_rbx_rsp_98[8]; - - uint8_t mov_eax_prev_loc[6]; - uint8_t mov_prev_loc_curr_loc_shr1[10]; - - uint8_t leax_eax_curr_loc[7]; + // mov QWORD PTR [rsp-0x88],rax + // lahf + // mov QWORD PTR [rsp-0x90],rax + // mov QWORD PTR [rsp-0x98],rbx - uint8_t mov_rbx_ptr_rax[2]; - uint8_t add_bl_1[3]; - uint8_t adc_bl_0[3]; - uint8_t mov_ptr_rax_rbx[2]; + // mov eax,DWORD PTR [rip+0x1312334] + // xor eax,0x3f77 - uint8_t mov_rsp_98_rbx[8]; - uint8_t mov_rsp_90_rax[8]; - uint8_t sahf; - uint8_t mov_rsp_88_rax[8]; + // lea rbx,[rip+0x132338] + // add rax,rbx -} afl_log_code_asm_t; + // mov bl,BYTE PTR [rax] + // add bl,0x1 + // adc bl,0x0 + // mov BYTE PTR [rax],bl - #pragma pack(pop) + // mov rbx,QWORD PTR [rsp-0x98] + // mov rax,QWORD PTR [rsp-0x90] + // sahf + // mov rax,QWORD PTR [rsp-0x88] -static const afl_log_code_asm_t template = - { - - .mov_rax_rsp_88 = {0x48, 0x89, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF}, - .lahf = 0x9f, - .mov_rax_rsp_90 = {0x48, 0x89, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF}, - .mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF}, - - .mov_eax_prev_loc = {0x8b, 0x05}, - .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05}, - - .leax_eax_curr_loc = {0x48, 0x8d, 0x05}, - .mov_rbx_ptr_rax = {0x8a, 0x18}, - .add_bl_1 = {0x80, 0xc3, 0x01}, - .adc_bl_0 = {0x80, 0xd3, 0x00}, - .mov_ptr_rax_rbx = {0x88, 0x18}, - - .mov_rsp_98_rbx = {0x48, 0x8B, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF}, - .mov_rsp_90_rax = {0x48, 0x8B, 0x84, 0x24, 0x70, 0xFF, 0xFF, 0xFF}, - .sahf = 0x9e, - .mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF}, - -} - -; - - #else - #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; - - // mov QWORD PTR [rsp-0x80],rax - // lahf - // mov QWORD PTR [rsp-0x88],rax - // mov QWORD PTR [rsp-0x90],rbx - // mov eax,DWORD PTR [rip+0x333d5a] # 0x7ffff6ff2740 - // mov DWORD PTR [rip+0x333d3c],0x9fbb # 0x7ffff6ff2740 - // xor eax,0x103f77 - // mov bl,BYTE PTR [rax] - // add bl,0x1 - // adc bl,0x0 - // mov BYTE PTR [rax],bl - // mov rbx,QWORD PTR [rsp-0x90] - // mov rax,QWORD PTR [rsp-0x88] - // sahf - // mov rax,QWORD PTR [rsp-0x80] + // mov DWORD PTR [rip+0x13122f8],0x9fbb uint8_t mov_rax_rsp_88[8]; uint8_t lahf; @@ -150,10 +108,11 @@ typedef struct { uint8_t mov_rbx_rsp_98[8]; uint8_t mov_eax_prev_loc[6]; - uint8_t mov_prev_loc_curr_loc_shr1[10]; - uint8_t xor_eax_curr_loc[5]; + uint8_t lea_rbx_area_ptr[7]; + uint8_t add_rax_rbx[3]; + uint8_t mov_rbx_ptr_rax[2]; uint8_t add_bl_1[3]; uint8_t adc_bl_0[3]; @@ -164,9 +123,11 @@ typedef struct { uint8_t sahf; uint8_t mov_rsp_88_rax[8]; + uint8_t mov_prev_loc_curr_loc_shr1[10]; + } afl_log_code_asm_t; - #pragma pack(pop) + #pragma pack(pop) static const afl_log_code_asm_t template = { @@ -177,9 +138,10 @@ static const afl_log_code_asm_t template = .mov_rbx_rsp_98 = {0x48, 0x89, 0x9C, 0x24, 0x68, 0xFF, 0xFF, 0xFF}, .mov_eax_prev_loc = {0x8b, 0x05}, - .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05}, - .xor_eax_curr_loc = {0x35}, + .lea_rbx_area_ptr = {0x48, 0x8d, 0x1d}, + .add_rax_rbx = {0x48, 0x01, 0xd8}, + .mov_rbx_ptr_rax = {0x8a, 0x18}, .add_bl_1 = {0x80, 0xc3, 0x01}, .adc_bl_0 = {0x80, 0xd3, 0x00}, @@ -190,10 +152,11 @@ static const afl_log_code_asm_t template = .sahf = 0x9e, .mov_rsp_88_rax = {0x48, 0x8B, 0x84, 0x24, 0x78, 0xFF, 0xFF, 0xFF}, + .mov_prev_loc_curr_loc_shr1 = {0xc7, 0x05}, + } ; - #endif typedef union { @@ -202,171 +165,12 @@ typedef union { } afl_log_code; - #ifdef __APPLE__ - -void instrument_coverage_optimize_init(void) { - -} - - #else - -static gboolean instrument_coverage_find_low(const GumRangeDetails *details, - gpointer user_data) { - - static GumAddress last_limit = (64ULL << 10); - gpointer * address = (gpointer *)user_data; - - last_limit = GUM_ALIGN_SIZE(last_limit, __afl_map_size); - - if ((details->range->base_address - last_limit) > __afl_map_size) { - - *address = GSIZE_TO_POINTER(last_limit); - return FALSE; - - } - - if (details->range->base_address > ((2ULL << 30) - __afl_map_size)) { - - return FALSE; - - } - - /* - * Align our buffer on a 64k boundary so that the low 16-bits of the address - * are zero, then we can just XOR the base address in, when we XOR with the - * current block ID. - */ - last_limit = GUM_ALIGN_SIZE( - details->range->base_address + details->range->size, __afl_map_size); - return TRUE; - -} - -static void instrument_coverage_optimize_map_mmap_anon(gpointer address) { - - __afl_area_ptr = - mmap(address, __afl_map_size, PROT_READ | PROT_WRITE, - MAP_FIXED_NOREPLACE | MAP_SHARED | MAP_ANONYMOUS, -1, 0); - if (__afl_area_ptr != address) { - - FATAL("Failed to map mmap __afl_area_ptr: %d", errno); - - } - -} - -static void instrument_coverage_optimize_map_mmap(char * shm_file_path, - gpointer address) { - - int shm_fd = -1; - - if (munmap(__afl_area_ptr, __afl_map_size) != 0) { - - FATAL("Failed to unmap previous __afl_area_ptr"); - - } - - __afl_area_ptr = NULL; - - #if !defined(__ANDROID__) - shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION); - if (shm_fd == -1) { FATAL("shm_open() failed\n"); } - #else - shm_fd = open("/dev/ashmem", O_RDWR); - if (shm_fd == -1) { FATAL("open() failed\n"); } - if (ioctl(shm_fd, ASHMEM_SET_NAME, shm_file_path) == -1) { - - FATAL("ioctl(ASHMEM_SET_NAME) failed"); - - } - - if (ioctl(shm_fd, ASHMEM_SET_SIZE, __afl_map_size) == -1) { - - FATAL("ioctl(ASHMEM_SET_SIZE) failed"); - - } - - #endif - - __afl_area_ptr = mmap(address, __afl_map_size, PROT_READ | PROT_WRITE, - MAP_FIXED_NOREPLACE | MAP_SHARED, shm_fd, 0); - if (__afl_area_ptr != address) { - - FATAL("Failed to map mmap __afl_area_ptr: %d", errno); - - } - - if (close(shm_fd) != 0) { FATAL("Failed to close shm_fd"); } - -} - -static void instrument_coverage_optimize_map_shm(guint64 shm_env_val, - gpointer address) { - - if (shmdt(__afl_area_ptr) != 0) { - - FATAL("Failed to detach previous __afl_area_ptr"); - - } - - __afl_area_ptr = shmat(shm_env_val, address, 0); - if (__afl_area_ptr != address) { - - FATAL("Failed to map shm __afl_area_ptr: %d", errno); - - } - -} - void instrument_coverage_optimize_init(void) { - gpointer low_address = NULL; - - gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, instrument_coverage_find_low, - &low_address); - - FVERBOSE("Low address: %p", low_address); - - if (low_address == 0 || - GPOINTER_TO_SIZE(low_address) > ((2UL << 30) - __afl_map_size)) { - - FATAL("Invalid low_address: %p", low_address); - - } - - ranges_print_debug_maps(); - - 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 anonymous map for debugging purposes"); - - instrument_coverage_optimize_map_mmap_anon(low_address); - - } else { - - guint64 shm_env_val = g_ascii_strtoull(shm_env, NULL, 10); - - if (shm_env_val == 0) { - - instrument_coverage_optimize_map_mmap(shm_env, low_address); - - } else { - - instrument_coverage_optimize_map_shm(shm_env_val, low_address); - - } - - } - FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr); } - #endif - static void instrument_coverage_switch(GumStalkerObserver *self, gpointer start_address, const cs_insn * from_insn, @@ -431,48 +235,19 @@ static void instrument_coverage_suppress_init(void) { } -void instrument_coverage_optimize(const cs_insn * instr, - GumStalkerOutput *output) { +static void instrument_coverage_write(GumAddress address, + 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; - GumAddress code_addr = 0; - if (instrument_previous_pc_addr == NULL) { - - GumAddressSpec spec = {.near_address = cw->code, - .max_distance = 1ULL << 30}; - - instrument_previous_pc_addr = gum_memory_allocate_near( - &spec, sizeof(guint64), 0x1000, 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); - - } - - instrument_coverage_suppress_init(); - - // gum_x86_writer_put_breakpoint(cw); - code_addr = cw->pc; - if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) { - - FATAL("Failed - g_hash_table_add"); - - } + guint64 area_offset = instrument_get_offset_hash(address); + gsize map_size_pow2; + gsize area_offset_ror; + GumAddress code_addr = cw->pc; code.code = template; - 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); + /* mov_prev_loc_curr_loc_shr1 */ gssize prev_loc_value = GPOINTER_TO_SIZE(instrument_previous_pc_addr) - @@ -490,6 +265,8 @@ void instrument_coverage_optimize(const cs_insn * instr, *((gint *)&code.bytes[prev_loc_value_offset]) = (gint)prev_loc_value; + /* mov_eax_prev_loc */ + gssize prev_loc_value2 = GPOINTER_TO_SIZE(instrument_previous_pc_addr) - (code_addr + offsetof(afl_log_code, code.mov_eax_prev_loc) + @@ -505,40 +282,172 @@ void instrument_coverage_optimize(const cs_insn * instr, *((gint *)&code.bytes[prev_loc_value_offset2]) = (gint)prev_loc_value2; - #ifdef __APPLE__ + /* xor_eax_curr_loc */ - gssize xor_curr_loc_offset = offsetof(afl_log_code, code.leax_eax_curr_loc) + - sizeof(code.code.leax_eax_curr_loc) - + gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) + + sizeof(code.code.xor_eax_curr_loc) - sizeof(guint32); - gssize xor_curr_loc_value = - ((GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset) - - (code_addr + offsetof(afl_log_code, code.mov_eax_prev_loc) + - sizeof(code.code.mov_eax_prev_loc))); + *((guint32 *)&code.bytes[xor_curr_loc_offset]) = area_offset; + + /* lea_rbx_area_ptr */ + + gssize lea_rbx_area_ptr_offset = + offsetof(afl_log_code, code.lea_rbx_area_ptr) + + sizeof(code.code.lea_rbx_area_ptr) - sizeof(guint32); + + gssize lea_rbx_area_ptr_value = + (GPOINTER_TO_SIZE(__afl_area_ptr) - + (code_addr + offsetof(afl_log_code, code.lea_rbx_area_ptr) + + sizeof(code.code.lea_rbx_area_ptr))); - if (!instrument_coverage_in_range(xor_curr_loc_value)) { + if (!instrument_coverage_in_range(lea_rbx_area_ptr_value)) { - FATAL("Patch out of range (xor_curr_loc_value): 0x%016lX", - xor_curr_loc_value); + FATAL("Patch out of range (lea_rbx_area_ptr_value): 0x%016lX", + lea_rbx_area_ptr_value); } - *((guint32 *)&code.bytes[xor_curr_loc_offset]) = xor_curr_loc_value; + *((guint32 *)&code.bytes[lea_rbx_area_ptr_offset]) = lea_rbx_area_ptr_value; - #else + /* mov_prev_loc_curr_loc_shr1 */ - gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_eax_curr_loc) + - sizeof(code.code.xor_eax_curr_loc) - - sizeof(guint32); + 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); - *((guint32 *)&code.bytes[xor_curr_loc_offset]) = - (guint32)(GPOINTER_TO_SIZE(__afl_area_ptr) | area_offset); - #endif + 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); gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code)); } +void instrument_coverage_optimize(const cs_insn * instr, + GumStalkerOutput *output) { + + GumX86Writer *cw = output->writer.x86; + guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address)); + if (instrument_previous_pc_addr == NULL) { + + GumAddressSpec spec = {.near_address = cw->code, + .max_distance = 1ULL << 30}; + + instrument_previous_pc_addr = gum_memory_allocate_near( + &spec, sizeof(guint64), 0x1000, 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); + + } + + instrument_coverage_suppress_init(); + + if (!g_hash_table_add(coverage_blocks, GSIZE_TO_POINTER(cw->code))) { + + FATAL("Failed - g_hash_table_add"); + + } + + instrument_coverage_write(GUM_ADDRESS(instr->address), output); + +} + +void instrument_coverage_optimize_insn(const cs_insn * instr, + GumStalkerOutput *output) { + + GumX86Writer *cw = output->writer.x86; + jcc_insn taken, not_taken; + + switch (instr->id) { + + case X86_INS_CMOVA: + taken.opcode = OPC_JA; + not_taken.opcode = OPC_JBE; + break; + case X86_INS_CMOVAE: + taken.opcode = OPC_JAE; + not_taken.opcode = OPC_JB; + break; + case X86_INS_CMOVB: + taken.opcode = OPC_JB; + not_taken.opcode = OPC_JAE; + break; + case X86_INS_CMOVBE: + taken.opcode = OPC_JBE; + not_taken.opcode = OPC_JA; + break; + case X86_INS_CMOVE: + taken.opcode = OPC_JE; + not_taken.opcode = OPC_JNE; + break; + case X86_INS_CMOVG: + taken.opcode = OPC_JG; + not_taken.opcode = OPC_JLE; + break; + case X86_INS_CMOVGE: + taken.opcode = OPC_JGE; + not_taken.opcode = OPC_JL; + break; + case X86_INS_CMOVL: + taken.opcode = OPC_JL; + not_taken.opcode = OPC_JGE; + break; + case X86_INS_CMOVLE: + taken.opcode = OPC_JLE; + not_taken.opcode = OPC_JG; + break; + case X86_INS_CMOVNE: + taken.opcode = OPC_JNE; + not_taken.opcode = OPC_JE; + break; + case X86_INS_CMOVNO: + taken.opcode = OPC_JNO; + not_taken.opcode = OPC_JO; + break; + case X86_INS_CMOVNP: + taken.opcode = OPC_JNP; + not_taken.opcode = OPC_JP; + break; + case X86_INS_CMOVNS: + taken.opcode = OPC_JNS; + not_taken.opcode = OPC_JS; + break; + case X86_INS_CMOVO: + taken.opcode = OPC_JO; + not_taken.opcode = OPC_JNO; + break; + case X86_INS_CMOVP: + taken.opcode = OPC_JP; + not_taken.opcode = OPC_JNP; + break; + case X86_INS_CMOVS: + taken.opcode = OPC_JS; + not_taken.opcode = OPC_JNS; + break; + default: + return; + + } + + taken.distance = sizeof(afl_log_code); + not_taken.distance = sizeof(afl_log_code); + + // gum_x86_writer_put_breakpoint(cw); + + gum_x86_writer_put_bytes(cw, taken.bytes, sizeof(jcc_insn)); + instrument_coverage_write(GUM_ADDRESS(instr->address), output); + + gum_x86_writer_put_bytes(cw, not_taken.bytes, sizeof(jcc_insn)); + instrument_coverage_write(GUM_ADDRESS(instr->address + instr->size), output); + + FVERBOSE("Instrument - 0x%016lx: %s %s", instr->address, instr->mnemonic, + instr->op_str); + +} + void instrument_flush(GumStalkerOutput *output) { gum_x86_writer_flush(output->writer.x86); diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c index c4e93324..916cd0e2 100644 --- a/frida_mode/src/instrument/instrument_x86.c +++ b/frida_mode/src/instrument/instrument_x86.c @@ -218,6 +218,14 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_coverage_optimize_insn(const cs_insn * instr, + GumStalkerOutput *output) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(output); + +} + void instrument_coverage_optimize_init(void) { } diff --git a/frida_mode/src/js/api.js b/frida_mode/src/js/api.js index 52e9e45c..82b8e63d 100644 --- a/frida_mode/src/js/api.js +++ b/frida_mode/src/js/api.js @@ -114,6 +114,12 @@ class Afl { Afl.jsApiSetInstrumentTrace(); } /** + * See `AFL_FRIDA_INST_INSN` + */ + static setInstrumentInstructions() { + Afl.jsApiSetInstrumentInstructions(); + } + /** * See `AFL_FRIDA_INST_JIT`. */ static setInstrumentJit() { @@ -297,6 +303,7 @@ Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", [] Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]); 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", []); Afl.jsApiSetInstrumentJit = Afl.jsApiGetFunction("js_api_set_instrument_jit", "void", []); Afl.jsApiSetInstrumentLibraries = Afl.jsApiGetFunction("js_api_set_instrument_libraries", "void", []); Afl.jsApiSetInstrumentNoOptimize = Afl.jsApiGetFunction("js_api_set_instrument_no_optimize", "void", []); diff --git a/frida_mode/src/js/js_api.c b/frida_mode/src/js/js_api.c index 94ec8842..89df7803 100644 --- a/frida_mode/src/js/js_api.c +++ b/frida_mode/src/js/js_api.c @@ -142,6 +142,13 @@ js_api_set_prefetch_backpatch_disable(void) { } +__attribute__((visibility("default"))) void js_api_set_instrument_instructions( + void) { + + instrument_coverage_insn = TRUE; + +} + __attribute__((visibility("default"))) void js_api_set_instrument_no_optimize( void) { diff --git a/frida_mode/src/main.c b/frida_mode/src/main.c index d8521300..bb6e4109 100644 --- a/frida_mode/src/main.c +++ b/frida_mode/src/main.c @@ -21,6 +21,7 @@ #include "intercept.h" #include "js.h" #include "lib.h" +#include "module.h" #include "output.h" #include "persistent.h" #include "prefetch.h" @@ -197,6 +198,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) { instrument_config(); js_config(); lib_config(); + module_config(); output_config(); persistent_config(); prefetch_config(); @@ -214,6 +216,7 @@ __attribute__((visibility("default"))) void afl_frida_start(void) { entry_init(); instrument_init(); lib_init(); + module_init(); persistent_init(); prefetch_init(); seccomp_init(); diff --git a/frida_mode/src/module.c b/frida_mode/src/module.c new file mode 100644 index 00000000..65b394cd --- /dev/null +++ b/frida_mode/src/module.c @@ -0,0 +1,106 @@ +#include "intercept.h" +#include "module.h" +#include "util.h" + +#if defined(__linux__) + #include <dlfcn.h> + #include <link.h> +#endif + +static guint page_size = 0; +static gboolean handle_dlclose = FALSE; + +void module_config(void) { + +#if defined(__linux__) + handle_dlclose = (getenv("AFL_FRIDA_NO_MODULE") == NULL); +#else + FWARNF("AFL_FRIDA_MODULE not supported"); +#endif + +} + +typedef struct { + + GumMemoryRange range; + GumPageProtection protection; + GumFileMapping file; + +} gum_range_t; + +gboolean found_range(const GumRangeDetails *details, gpointer user_data) { + + gum_range_t range = {0}; + GArray * ranges = (GArray *)user_data; + + range.range = *details->range; + range.protection = details->protection; + if (details->file != NULL) { range.file = *details->file; } + + g_array_append_val(ranges, range); + return FALSE; + +} + +#if defined(__linux__) +static int on_dlclose(void *handle) { + + GArray * ranges = NULL; + struct link_map *lm = NULL; + gum_range_t * range = NULL; + GumAddress base; + GumAddress limit; + gpointer mem; + + if (dlinfo(handle, RTLD_DI_LINKMAP, &lm) < 0) { + + FFATAL("Failed to dlinfo: %s", dlerror()); + + } + + FVERBOSE("on_dlclose: %s", lm->l_name); + + ranges = g_array_new(FALSE, TRUE, sizeof(gum_range_t)); + gum_module_enumerate_ranges(lm->l_name, GUM_PAGE_EXECUTE, found_range, + ranges); + + int ret = dlclose(handle); + if (ret != 0) { + + FWARNF("dlclose returned: %d (%s)", ret, dlerror()); + return ret; + + } + + for (guint i = 0; i < ranges->len; i++) { + + range = &g_array_index(ranges, gum_range_t, i); + base = range->range.base_address; + limit = base + range->range.size; + FVERBOSE("Reserving range: 0x%016lx, 0x%016lX", base, limit); + mem = gum_memory_allocate(GSIZE_TO_POINTER(base), range->range.size, + page_size, GUM_PAGE_NO_ACCESS); + if (mem == NULL) { FATAL("Failed to allocate %p (%d)", mem, errno); } + + } + + g_array_free(ranges, TRUE); + return 0; + +} + +#endif + +void module_init(void) { + + FOKF(cBLU "Module" cRST " - " cYEL " [%c]", handle_dlclose ? 'X' : ' '); + +#if defined(__linux__) + if (!handle_dlclose) { return; } + + page_size = gum_query_page_size(); + intercept_hook(dlclose, on_dlclose, NULL); +#endif + +} + diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index 84803453..d47d1c14 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -595,8 +595,6 @@ void ranges_init(void) { ranges_inst_jit ? 'X' : ' '); FOKF(cBLU "Ranges" cRST " - " cGRN "instrument libraries:" cYEL " [%c]", ranges_inst_libs ? 'X' : ' '); - FOKF(cBLU "Ranges" cRST " - " cGRN "instrument libraries:" cYEL " [%c]", - ranges_inst_libs ? 'X' : ' '); print_ranges("include", include_ranges); print_ranges("exclude", exclude_ranges); diff --git a/frida_mode/test/cmov/GNUmakefile b/frida_mode/test/cmov/GNUmakefile new file mode 100644 index 00000000..96f1ae5b --- /dev/null +++ b/frida_mode/test/cmov/GNUmakefile @@ -0,0 +1,87 @@ +PWD:=$(shell pwd)/ +ROOT:=$(PWD)../../../ +BUILD_DIR:=$(PWD)build/ + +TEST_CMOV_SRC:=$(PWD)cmov.c +TEST_CMOV_OBJ:=$(BUILD_DIR)cmov + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +CMP_LOG_INPUT:=$(TEST_DATA_DIR)in +QEMU_OUT:=$(BUILD_DIR)qemu-out +FRIDA_OUT:=$(BUILD_DIR)frida-out + +ADDR_BIN:=$(ROOT)frida_mode/build/addr +GET_SYMBOL_ADDR:=$(ROOT)frida_mode/util/get_symbol_addr.sh + +AFLPP_FRIDA_DRIVER_HOOK_OBJ=$(ROOT)frida_mode/build/frida_hook.so + +AFL_FRIDA_BASE_ADDR:=$(shell $(ADDR_BIN)) +AFL_FRIDA_PERSISTENT_ADDR=$(shell $(GET_SYMBOL_ADDR) $(TEST_CMOV_OBJ) LLVMFuzzerTestOneInput $(AFL_FRIDA_BASE_ADDR)) + +DUMMY_DATA_FILE:=$(BUILD_DIR)dummy.dat + +.PHONY: all 32 clean frida frida_noinst debug format + +all: $(TEST_CMOV_OBJ) + make -C $(ROOT)frida_mode/ + +32: + CFLAGS="-m32" LDFLAGS="-m32" ARCH="x86" make all + +$(BUILD_DIR): + mkdir -p $@ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(CMP_LOG_INPUT): | $(TEST_DATA_DIR) + echo -n "ABC" > $@ + +$(TEST_CMOV_OBJ): $(TEST_CMOV_SRC) | $(BUILD_DIR) + $(CC) -g $(CFLAGS) $(LDFLAGS) $< -o $@ + +########## DUMMY ####### + +$(DUMMY_DATA_FILE): | $(BUILD_DIR) + dd if=/dev/zero bs=1048576 count=1 of=$@ + +frida: $(TEST_CMOV_OBJ) $(CMP_LOG_INPUT) $(DUMMY_DATA_FILE) + AFL_FRIDA_INST_INSN=1 \ + AFL_FRIDA_PERSISTENT_CNT=1000000 \ + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -Z \ + -t 10000+ \ + -- \ + $(TEST_CMOV_OBJ) $(DUMMY_DATA_FILE) + +frida_noinst: $(TEST_CMOV_OBJ) $(CMP_LOG_INPUT) $(DUMMY_DATA_FILE) + AFL_FRIDA_PERSISTENT_CNT=1000000 \ + AFL_FRIDA_PERSISTENT_HOOK=$(AFLPP_FRIDA_DRIVER_HOOK_OBJ) \ + AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \ + AFL_ENTRYPOINT=$(AFL_FRIDA_PERSISTENT_ADDR) \ + $(ROOT)afl-fuzz \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -Z \ + -- \ + $(TEST_CMOV_OBJ) $(DUMMY_DATA_FILE) + +debug: $(TEST_CMOV_OBJ) $(CMP_LOG_INPUT) + gdb \ + --ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \ + --ex 'set disassembly-flavor intel' \ + --ex 'r $(CMP_LOG_INPUT)' \ + --args $(TEST_CMOV_OBJ) $(CMP_LOG_INPUT) + +clean: + rm -rf $(BUILD_DIR) + +format: + cd $(ROOT) && echo $(TEST_CMOV_SRC) | xargs -L1 ./.custom-format.py -i diff --git a/frida_mode/test/cmov/Makefile b/frida_mode/test/cmov/Makefile new file mode 100644 index 00000000..9ef6fc8f --- /dev/null +++ b/frida_mode/test/cmov/Makefile @@ -0,0 +1,19 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +32: + @echo trying to use GNU make... + @gmake 32 || echo please install GNUmake + +clean: + @gmake clean + +frida: + @gmake frida + +format: + @gmake format + +debug: + @gmake debug diff --git a/frida_mode/test/cmov/cmov.c b/frida_mode/test/cmov/cmov.c new file mode 100644 index 00000000..08c7c132 --- /dev/null +++ b/frida_mode/test/cmov/cmov.c @@ -0,0 +1,122 @@ +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static bool cmov_test(char *x, char *y, size_t len) { + + register char * __rdi __asm__("rdi") = x; + register char * __rsi __asm__("rsi") = y; + register size_t __rcx __asm__("rcx") = len; + + register long __rax __asm__("rax"); + + __asm__ __volatile__( + "mov $0x1, %%rax\n" + "mov $0x0, %%r8\n" + "1:\n" + "mov (%%rsi), %%bl\n" + "mov (%%rdi), %%dl\n" + "cmp %%bl, %%dl\n" + "cmovne %%r8, %%rax\n" + "inc %%rsi\n" + "inc %%rdi\n" + "dec %%rcx\n" + "jnz 1b\n" + : "=r"(__rax) + : "r"(__rdi), "r"(__rsi) + : "r8", "bl", "dl", "memory"); + + return __rax; + +} + +void LLVMFuzzerTestOneInput(char *buf, int len) { + + char match[] = "CBAABC"; + + if (len > sizeof(match)) { return; } + + if (cmov_test(buf, match, sizeof(buf)) != 0) { + + printf("Puzzle solved, congrats!\n"); + abort(); + + } + +} + +int main(int argc, char **argv) { + + char * file; + int fd = -1; + off_t len; + char * buf = NULL; + size_t n_read; + int result = -1; + + if (argc != 2) { return 1; } + + do { + + file = argv[1]; + + dprintf(STDERR_FILENO, "Running: %s\n", file); + + fd = open(file, O_RDONLY); + if (fd < 0) { + + perror("open"); + break; + + } + + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + + perror("lseek (SEEK_END)"); + break; + + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + + perror("lseek (SEEK_SET)"); + break; + + } + + buf = (char *)malloc(len); + if (buf == NULL) { + + perror("malloc"); + break; + + } + + n_read = read(fd, buf, len); + if (n_read != len) { + + perror("read"); + break; + + } + + dprintf(STDERR_FILENO, "Running: %s: (%zd bytes)\n", file, n_read); + + LLVMFuzzerTestOneInput(buf, len); + dprintf(STDERR_FILENO, "Done: %s: (%zd bytes)\n", file, n_read); + + result = 0; + + } while (false); + + if (buf != NULL) { free(buf); } + + if (fd != -1) { close(fd); } + + return result; + +} + diff --git a/frida_mode/test/python/GNUmakefile b/frida_mode/test/python/GNUmakefile new file mode 100644 index 00000000..e4f7857b --- /dev/null +++ b/frida_mode/test/python/GNUmakefile @@ -0,0 +1,37 @@ +PWD:=$(shell pwd)/ +ROOT:=$(PWD)../../../ +BUILD_DIR:=$(PWD)build/ +TESTINSTR_DATA_DIR:=$(BUILD_DIR)in/ +FRIDA_OUT:=$(BUILD_DIR)frida-out +QEMU_OUT:=$(BUILD_DIR)qemu-out + +.PHONY: all clean run qemu frida + +all: + make -C $(ROOT)frida_mode/ + +clean: + rm -rf $(BUILD_DIR) + +$(BUILD_DIR): + mkdir -p $@ + +$(TESTINSTR_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +run: + date + /usr/bin/python -c 'print("hi");' + date + +qemu: + date + $(ROOT)afl-qemu-trace \ + /usr/bin/python -c 'print("hi");' + date + +frida: + date + LD_PRELOAD=$(ROOT)afl-frida-trace.so \ + python -c 'print("hi");' + date diff --git a/frida_mode/test/python/Makefile b/frida_mode/test/python/Makefile new file mode 100644 index 00000000..e66cfdef --- /dev/null +++ b/frida_mode/test/python/Makefile @@ -0,0 +1,17 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +run: + @gmake run + +qemu: + @gmake qemu + +frida: + @gmake frida + + diff --git a/frida_mode/ts/lib/afl.ts b/frida_mode/ts/lib/afl.ts index 57d7b5b5..7999b661 100644 --- a/frida_mode/ts/lib/afl.ts +++ b/frida_mode/ts/lib/afl.ts @@ -136,6 +136,13 @@ class Afl { } /** + * See `AFL_FRIDA_INST_INSN` + */ + public static setInstrumentInstructions(): void { + Afl.jsApiSetInstrumentInstructions(); + } + + /** * See `AFL_FRIDA_INST_JIT`. */ public static setInstrumentJit(): void { @@ -367,6 +374,11 @@ class Afl { "void", ["pointer"]); + private static readonly jsApiSetInstrumentInstructions = Afl.jsApiGetFunction( + "js_api_set_instrument_instructions", + "void", + []); + private static readonly jsApiSetInstrumentJit = Afl.jsApiGetFunction( "js_api_set_instrument_jit", "void", diff --git a/include/envs.h b/include/envs.h index f4327d8c..1f6d33e6 100644 --- a/include/envs.h +++ b/include/envs.h @@ -59,6 +59,7 @@ static char *afl_environment_variables[] = { "AFL_FRIDA_EXCLUDE_RANGES", "AFL_FRIDA_INST_COVERAGE_FILE", "AFL_FRIDA_INST_DEBUG_FILE", + "AFL_FRIDA_INST_INSN", "AFL_FRIDA_INST_JIT", "AFL_FRIDA_INST_NO_OPTIMIZE", "AFL_FRIDA_INST_NO_PREFETCH", diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 6a4a071f..1bdc5376 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -17,6 +17,7 @@ #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/ValueTracking.h" @@ -757,7 +758,7 @@ bool ModuleSanitizerCoverage::instrumentModule( if (!HasStr2) { auto *Ptr = dyn_cast<ConstantExpr>(Str2P); - if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) { if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { @@ -838,7 +839,7 @@ bool ModuleSanitizerCoverage::instrumentModule( auto Ptr = dyn_cast<ConstantExpr>(Str1P); - if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) { if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index e4ffeb50..48bb5a2c 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -13,6 +13,7 @@ #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/CFG.h" diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index 39124660..a554c40e 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -435,7 +435,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { if (!HasStr2) { auto *Ptr = dyn_cast<ConstantExpr>(Str2P); - if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) { if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { @@ -519,7 +519,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { auto Ptr = dyn_cast<ConstantExpr>(Str1P); - if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) { if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { @@ -589,7 +589,6 @@ bool AFLdict2filePass::runOnModule(Module &M) { if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte - thestring.append("\0", 1); } @@ -612,11 +611,17 @@ bool AFLdict2filePass::runOnModule(Module &M) { } */ - if (!isStdString && thestring.find('\0', 0) != std::string::npos) { + + if (!isStdString) { // ensure we do not have garbage size_t offset = thestring.find('\0', 0); - if (offset + 1 < optLen) optLen = offset + 1; + if (offset && offset < optLen && offset + 1 < optLen) { + + optLen = offset + 1; + + } + thestring = thestring.substr(0, optLen); } diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc index 35ba9c5a..2ddbc725 100644 --- a/instrumentation/afl-llvm-lto-instrumentlist.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc @@ -43,6 +43,7 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/IR/CFG.h" diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 5246ba08..be8099bb 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -45,12 +45,22 @@ typedef long double max_align_t; #endif #include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Pass.h" +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ + #include "llvm/Passes/PassPlugin.h" + #include "llvm/Passes/PassBuilder.h" + #include "llvm/IR/PassManager.h" +#else + #include "llvm/IR/LegacyPassManager.h" + #include "llvm/Transforms/IPO/PassManagerBuilder.h" +#endif #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */ + #include "llvm/Passes/OptimizationLevel.h" +#endif #if LLVM_VERSION_MAJOR >= 4 || \ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4) @@ -68,17 +78,30 @@ using namespace llvm; namespace { +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ +class AFLCoverage : public PassInfoMixin<AFLCoverage> { + + public: + AFLCoverage() { + +#else class AFLCoverage : public ModulePass { public: static char ID; AFLCoverage() : ModulePass(ID) { +#endif + initInstrumentList(); } +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); +#else bool runOnModule(Module &M) override; +#endif protected: uint32_t ngram_size = 0; @@ -92,7 +115,55 @@ class AFLCoverage : public ModulePass { } // namespace +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ +extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK +llvmGetPassPluginInfo() { + + return {LLVM_PLUGIN_API_VERSION, "AFLCoverage", "v0.1", + /* lambda to insert our pass into the pass pipeline. */ + [](PassBuilder &PB) { + + #if 1 + #if LLVM_VERSION_MAJOR <= 13 + using OptimizationLevel = typename PassBuilder::OptimizationLevel; + #endif + PB.registerOptimizerLastEPCallback( + [](ModulePassManager &MPM, OptimizationLevel OL) { + + MPM.addPass(AFLCoverage()); + + }); + + /* TODO LTO registration */ + #else + using PipelineElement = typename PassBuilder::PipelineElement; + PB.registerPipelineParsingCallback([](StringRef Name, + ModulePassManager &MPM, + ArrayRef<PipelineElement>) { + + if (Name == "AFLCoverage") { + + MPM.addPass(AFLCoverage()); + return true; + + } else { + + return false; + + } + + }); + + #endif + + }}; + +} + +#else + char AFLCoverage::ID = 0; +#endif /* needed up to 3.9.0 */ #if LLVM_VERSION_MAJOR == 3 && \ @@ -118,8 +189,15 @@ uint64_t PowerOf2Ceil(unsigned in) { (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1) #define AFL_HAVE_VECTOR_INTRINSICS 1 #endif + +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ +PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) { + +#else bool AFLCoverage::runOnModule(Module &M) { +#endif + LLVMContext &C = M.getContext(); IntegerType *Int8Ty = IntegerType::getInt8Ty(C); @@ -133,6 +211,10 @@ bool AFLCoverage::runOnModule(Module &M) { u32 rand_seed; unsigned int cur_loc = 0; +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ + auto PA = PreservedAnalyses::all(); +#endif + /* Setup random() so we get Actually Random(TM) outputs from AFL_R() */ gettimeofday(&tv, &tz); rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid(); @@ -997,10 +1079,15 @@ bool AFLCoverage::runOnModule(Module &M) { } +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ + return PA; +#else return true; +#endif } +#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */ static void registerAFLPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) { @@ -1013,4 +1100,5 @@ static RegisterStandardPasses RegisterAFLPass( static RegisterStandardPasses RegisterAFLPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass); +#endif diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index 310f5585..b6d51ef3 100644 --- a/instrumentation/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc @@ -28,11 +28,16 @@ #include "llvm/Config/llvm-config.h" #include "llvm/ADT/Statistic.h" #include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#if LLVM_MAJOR >= 11 +// #include "llvm/Passes/PassPlugin.h" +// #include "llvm/Passes/PassBuilder.h" + #include "llvm/IR/PassManager.h" +#else + #include "llvm/IR/LegacyPassManager.h" +#endif #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Pass.h" #include "llvm/Analysis/ValueTracking.h" @@ -55,6 +60,15 @@ using namespace llvm; namespace { +#if LLVM_MAJOR >= 11 /* use new pass manager */ +class CmpLogInstructions : public PassInfoMixin<CmpLogInstructions> { + public: + CmpLogInstructions() { + + initInstrumentList(); + + } +#else class CmpLogInstructions : public ModulePass { public: @@ -64,7 +78,11 @@ class CmpLogInstructions : public ModulePass { initInstrumentList(); } +#endif +#if LLVM_MAJOR >= 11 /* use new pass manager */ + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); +#else bool runOnModule(Module &M) override; #if LLVM_VERSION_MAJOR >= 4 @@ -77,6 +95,7 @@ class CmpLogInstructions : public ModulePass { return "cmplog instructions"; } +#endif private: bool hookInstrs(Module &M); @@ -85,7 +104,9 @@ class CmpLogInstructions : public ModulePass { } // namespace +#if LLVM_MAJOR <= 10 /* use old pass manager */ char CmpLogInstructions::ID = 0; +#endif template <class Iterator> Iterator Unique(Iterator first, Iterator last) { @@ -613,7 +634,12 @@ bool CmpLogInstructions::hookInstrs(Module &M) { } +#if LLVM_MAJOR >= 11 /* use new pass manager */ +PreservedAnalyses CmpLogInstructions::run(Module & M, + ModuleAnalysisManager &MAM) { +#else bool CmpLogInstructions::runOnModule(Module &M) { +#endif if (getenv("AFL_QUIET") == NULL) printf("Running cmplog-instructions-pass by andreafioraldi@gmail.com\n"); @@ -622,10 +648,15 @@ bool CmpLogInstructions::runOnModule(Module &M) { hookInstrs(M); verifyModule(M); +#if LLVM_MAJOR >= 11 /* use new pass manager */ + return PreservedAnalyses::all(); +#else return true; +#endif } +#if LLVM_MAJOR < 11 /* use old pass manager */ static void registerCmpLogInstructionsPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) { @@ -645,4 +676,4 @@ static RegisterStandardPasses RegisterCmpLogInstructionsPassLTO( PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerCmpLogInstructionsPass); #endif - +#endif diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index c3a4ee34..cd3f0e6f 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -26,14 +26,23 @@ #include "llvm/ADT/Statistic.h" #include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LegacyPassManager.h" +#if LLVM_MAJOR >= 11 /* use new pass manager */ + #include "llvm/Passes/PassPlugin.h" + #include "llvm/Passes/PassBuilder.h" + #include "llvm/IR/PassManager.h" +#else + #include "llvm/IR/LegacyPassManager.h" + #include "llvm/Transforms/IPO/PassManagerBuilder.h" +#endif #include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Pass.h" #include "llvm/Analysis/ValueTracking.h" +#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */ + #include "llvm/Passes/OptimizationLevel.h" +#endif #if LLVM_VERSION_MAJOR >= 4 || \ (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4) @@ -52,28 +61,39 @@ using namespace llvm; namespace { +#if LLVM_MAJOR >= 11 /* use new pass manager */ +class CompareTransform : public PassInfoMixin<CompareTransform> { + + public: + CompareTransform() { + +#else class CompareTransform : public ModulePass { public: static char ID; CompareTransform() : ModulePass(ID) { +#endif + initInstrumentList(); } - bool runOnModule(Module &M) override; - +#if LLVM_MAJOR < 11 #if LLVM_VERSION_MAJOR >= 4 StringRef getPassName() const override { #else const char *getPassName() const override { - #endif - return "transforms compare functions"; +#endif - } +#if LLVM_MAJOR >= 11 /* use new pass manager */ + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); +#else + bool runOnModule(Module &M) override; +#endif private: bool transformCmps(Module &M, const bool processStrcmp, @@ -85,7 +105,54 @@ class CompareTransform : public ModulePass { } // namespace +#if LLVM_MAJOR >= 11 /* use new pass manager */ +extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK +llvmGetPassPluginInfo() { + + return {LLVM_PLUGIN_API_VERSION, "comparetransform", "v0.1", + /* lambda to insert our pass into the pass pipeline. */ + [](PassBuilder &PB) { + + #if 1 + #if LLVM_VERSION_MAJOR <= 13 + using OptimizationLevel = typename PassBuilder::OptimizationLevel; + #endif + PB.registerOptimizerLastEPCallback( + [](ModulePassManager &MPM, OptimizationLevel OL) { + + MPM.addPass(CompareTransform()); + + }); + + /* TODO LTO registration */ + #else + using PipelineElement = typename PassBuilder::PipelineElement; + PB.registerPipelineParsingCallback([](StringRef Name, + ModulePassManager &MPM, + ArrayRef<PipelineElement>) { + + if (Name == "comparetransform") { + + MPM.addPass(CompareTransform()); + return true; + + } else { + + return false; + + } + + }); + + #endif + + }}; + +} + +#else char CompareTransform::ID = 0; +#endif bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, const bool processMemcmp, @@ -246,7 +313,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, if (!(HasStr1 || HasStr2)) { auto *Ptr = dyn_cast<ConstantExpr>(Str2P); - if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) { if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { @@ -271,7 +338,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, if (!HasStr2) { Ptr = dyn_cast<ConstantExpr>(Str1P); - if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) { if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) { @@ -385,6 +452,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, bool isCaseInsensitive = false; bool needs_null = false; Function * Callee = callInst->getCalledFunction(); + if (Callee) { if (!Callee->getName().compare("memcmp") || @@ -642,8 +710,14 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } +#if LLVM_MAJOR >= 11 /* use new pass manager */ +PreservedAnalyses CompareTransform::run(Module &M, ModuleAnalysisManager &MAM) { + +#else bool CompareTransform::runOnModule(Module &M) { +#endif + if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL) printf( "Running compare-transform-pass by laf.intel@gmail.com, extended by " @@ -651,13 +725,28 @@ bool CompareTransform::runOnModule(Module &M) { else be_quiet = 1; +#if LLVM_MAJOR >= 11 /* use new pass manager */ + auto PA = PreservedAnalyses::all(); +#endif + transformCmps(M, true, true, true, true, true); verifyModule(M); +#if LLVM_MAJOR >= 11 /* use new pass manager */ + /* if (modified) { + + PA.abandon<XX_Manager>(); + + }*/ + + return PA; +#else return true; +#endif } +#if LLVM_MAJOR < 11 /* use old pass manager */ static void registerCompTransPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) { @@ -672,8 +761,9 @@ static RegisterStandardPasses RegisterCompTransPass( static RegisterStandardPasses RegisterCompTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerCompTransPass); -#if LLVM_VERSION_MAJOR >= 11 + #if LLVM_VERSION_MAJOR >= 11 static RegisterStandardPasses RegisterCompTransPassLTO( PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerCompTransPass); + #endif #endif diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 0f00fa96..d7bb7aba 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -1,6 +1,7 @@ /* * Copyright 2016 laf-intel * extended for floating point by Heiko Eißfeldt + * adapted to new pass manager by Heiko Eißfeldt * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,10 +29,20 @@ #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" + +#if LLVM_MAJOR >= 11 + #include "llvm/Passes/PassPlugin.h" + #include "llvm/Passes/PassBuilder.h" + #include "llvm/IR/PassManager.h" +#else + #include "llvm/IR/LegacyPassManager.h" + #include "llvm/Transforms/IPO/PassManagerBuilder.h" +#endif #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/IR/Module.h" +#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */ + #include "llvm/Passes/OptimizationLevel.h" +#endif #include "llvm/IR/IRBuilder.h" #if LLVM_VERSION_MAJOR >= 4 || \ @@ -53,27 +64,31 @@ using namespace llvm; namespace { +#if LLVM_MAJOR >= 11 +class SplitComparesTransform : public PassInfoMixin<SplitComparesTransform> { + + public: + // static char ID; + SplitComparesTransform() : enableFPSplit(0) { + +#else class SplitComparesTransform : public ModulePass { public: static char ID; SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) { +#endif + initInstrumentList(); } - bool runOnModule(Module &M) override; -#if LLVM_VERSION_MAJOR >= 4 - StringRef getPassName() const override { - +#if LLVM_MAJOR >= 11 + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); #else - const char *getPassName() const override { - + bool runOnModule(Module &M) override; #endif - return "AFL_SplitComparesTransform"; - - } private: int enableFPSplit; @@ -162,7 +177,54 @@ class SplitComparesTransform : public ModulePass { } // namespace +#if LLVM_MAJOR >= 11 +extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK +llvmGetPassPluginInfo() { + + return {LLVM_PLUGIN_API_VERSION, "splitcompares", "v0.1", + /* lambda to insert our pass into the pass pipeline. */ + [](PassBuilder &PB) { + + #if 1 + #if LLVM_VERSION_MAJOR <= 13 + using OptimizationLevel = typename PassBuilder::OptimizationLevel; + #endif + PB.registerOptimizerLastEPCallback( + [](ModulePassManager &MPM, OptimizationLevel OL) { + + MPM.addPass(SplitComparesTransform()); + + }); + + /* TODO LTO registration */ + #else + using PipelineElement = typename PassBuilder::PipelineElement; + PB.registerPipelineParsingCallback([](StringRef Name, + ModulePassManager &MPM, + ArrayRef<PipelineElement>) { + + if (Name == "splitcompares") { + + MPM.addPass(SplitComparesTransform()); + return true; + + } else { + + return false; + + } + + }); + + #endif + + }}; + +} + +#else char SplitComparesTransform::ID = 0; +#endif /// This function splits FCMP instructions with xGE or xLE predicates into two /// FCMP instructions with predicate xGT or xLT and EQ @@ -1421,8 +1483,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } +#if LLVM_MAJOR >= 11 +PreservedAnalyses SplitComparesTransform::run(Module & M, + ModuleAnalysisManager &MAM) { + +#else bool SplitComparesTransform::runOnModule(Module &M) { +#endif + char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW"); if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW"); if (bitw_env) { target_bitwidth = atoi(bitw_env); } @@ -1432,7 +1501,7 @@ bool SplitComparesTransform::runOnModule(Module &M) { if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL) { - errs() << "Split-compare-pass by laf.intel@gmail.com, extended by " + errs() << "Split-compare-newpass by laf.intel@gmail.com, extended by " "heiko@hexco.de (splitting icmp to " << target_bitwidth << " bit)\n"; @@ -1444,6 +1513,10 @@ bool SplitComparesTransform::runOnModule(Module &M) { } +#if LLVM_MAJOR >= 11 + auto PA = PreservedAnalyses::all(); +#endif + if (enableFPSplit) { simplifyFPCompares(M); @@ -1473,7 +1546,16 @@ bool SplitComparesTransform::runOnModule(Module &M) { auto op0 = CI->getOperand(0); auto op1 = CI->getOperand(1); - if (!op0 || !op1) { return false; } + if (!op0 || !op1) { + +#if LLVM_MAJOR >= 11 + return PA; +#else + return false; +#endif + + } + auto iTy1 = dyn_cast<IntegerType>(op0->getType()); if (iTy1 && isa<IntegerType>(op1->getType())) { @@ -1522,10 +1604,29 @@ bool SplitComparesTransform::runOnModule(Module &M) { } + if ((isatty(2) && getenv("AFL_QUIET") == NULL) || + getenv("AFL_DEBUG") != NULL) { + + errs() << count << " comparisons found\n"; + + } + +#if LLVM_MAJOR >= 11 + /* if (modified) { + + PA.abandon<XX_Manager>(); + + }*/ + + return PA; +#else return true; +#endif } +#if LLVM_MAJOR < 11 /* use old pass manager */ + static void registerSplitComparesPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) { @@ -1539,14 +1640,15 @@ static RegisterStandardPasses RegisterSplitComparesPass( static RegisterStandardPasses RegisterSplitComparesTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass); -#if LLVM_VERSION_MAJOR >= 11 + #if LLVM_VERSION_MAJOR >= 11 static RegisterStandardPasses RegisterSplitComparesTransPassLTO( PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerSplitComparesPass); -#endif + #endif static RegisterPass<SplitComparesTransform> X("splitcompares", "AFL++ split compares", true /* Only looks at CFG */, true /* Analysis Pass */); +#endif diff --git a/instrumentation/split-switches-pass.so.cc b/instrumentation/split-switches-pass.so.cc index 9f9e7eca..96e01a8b 100644 --- a/instrumentation/split-switches-pass.so.cc +++ b/instrumentation/split-switches-pass.so.cc @@ -27,14 +27,23 @@ #include "llvm/ADT/Statistic.h" #include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LegacyPassManager.h" +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ + #include "llvm/Passes/PassPlugin.h" + #include "llvm/Passes/PassBuilder.h" + #include "llvm/IR/PassManager.h" +#else + #include "llvm/IR/LegacyPassManager.h" + #include "llvm/Transforms/IPO/PassManagerBuilder.h" +#endif #include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Pass.h" #include "llvm/Analysis/ValueTracking.h" +#if LLVM_VERSION_MAJOR >= 14 /* how about stable interfaces? */ + #include "llvm/Passes/OptimizationLevel.h" +#endif #include "llvm/IR/IRBuilder.h" #if LLVM_VERSION_MAJOR >= 4 || \ @@ -54,29 +63,42 @@ using namespace llvm; namespace { +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ +class SplitSwitchesTransform : public PassInfoMixin<SplitSwitchesTransform> { + + public: + SplitSwitchesTransform() { + +#else class SplitSwitchesTransform : public ModulePass { public: static char ID; SplitSwitchesTransform() : ModulePass(ID) { +#endif initInstrumentList(); } - bool runOnModule(Module &M) override; +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); +#else + bool runOnModule(Module &M) override; -#if LLVM_VERSION_MAJOR >= 4 + #if LLVM_VERSION_MAJOR >= 4 StringRef getPassName() const override { -#else + #else const char *getPassName() const override { -#endif + #endif return "splits switch constructs"; } +#endif + struct CaseExpr { ConstantInt *Val; @@ -103,7 +125,54 @@ class SplitSwitchesTransform : public ModulePass { } // namespace +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ +extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK +llvmGetPassPluginInfo() { + + return {LLVM_PLUGIN_API_VERSION, "splitswitches", "v0.1", + /* lambda to insert our pass into the pass pipeline. */ + [](PassBuilder &PB) { + + #if 1 + #if LLVM_VERSION_MAJOR <= 13 + using OptimizationLevel = typename PassBuilder::OptimizationLevel; + #endif + PB.registerOptimizerLastEPCallback( + [](ModulePassManager &MPM, OptimizationLevel OL) { + + MPM.addPass(SplitSwitchesTransform()); + + }); + + /* TODO LTO registration */ + #else + using PipelineElement = typename PassBuilder::PipelineElement; + PB.registerPipelineParsingCallback([](StringRef Name, + ModulePassManager &MPM, + ArrayRef<PipelineElement>) { + + if (Name == "splitswitches") { + + MPM.addPass(SplitSwitchesTransform()); + return true; + + } else { + + return false; + + } + + }); + + #endif + + }}; + +} + +#else char SplitSwitchesTransform::ID = 0; +#endif /* switchConvert - Transform simple list of Cases into list of CaseRange's */ BasicBlock *SplitSwitchesTransform::switchConvert( @@ -413,19 +482,42 @@ bool SplitSwitchesTransform::splitSwitches(Module &M) { } +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ +PreservedAnalyses SplitSwitchesTransform::run(Module & M, + ModuleAnalysisManager &MAM) { + +#else bool SplitSwitchesTransform::runOnModule(Module &M) { +#endif + if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL) printf("Running split-switches-pass by laf.intel@gmail.com\n"); else be_quiet = 1; + +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ + auto PA = PreservedAnalyses::all(); +#endif + splitSwitches(M); verifyModule(M); +#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ + /* if (modified) { + + PA.abandon<XX_Manager>(); + + }*/ + + return PA; +#else return true; +#endif } +#if LLVM_VERSION_MAJOR < 11 /* use old pass manager */ static void registerSplitSwitchesTransPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) { @@ -440,9 +532,10 @@ static RegisterStandardPasses RegisterSplitSwitchesTransPass( static RegisterStandardPasses RegisterSplitSwitchesTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass); -#if LLVM_VERSION_MAJOR >= 11 + #if LLVM_VERSION_MAJOR >= 11 static RegisterStandardPasses RegisterSplitSwitchesTransPassLTO( PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerSplitSwitchesTransPass); + #endif #endif diff --git a/src/afl-cc.c b/src/afl-cc.c index ed57ca1e..3e67085e 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -462,11 +462,17 @@ static void edit_params(u32 argc, char **argv, char **envp) { } else { +#if LLVM_MAJOR >= 11 /* use new pass manager */ + cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager"; + cc_params[cc_par_cnt++] = + alloc_printf("-fpass-plugin=%s/split-switches-pass.so", obj_path); +#else cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = alloc_printf("%s/split-switches-pass.so", obj_path); +#endif } @@ -482,11 +488,17 @@ static void edit_params(u32 argc, char **argv, char **envp) { } else { +#if LLVM_MAJOR >= 11 /* use new pass manager */ + cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager"; + cc_params[cc_par_cnt++] = alloc_printf( + "-fpass-plugin=%s/compare-transform-pass.so", obj_path); +#else cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = alloc_printf("%s/compare-transform-pass.so", obj_path); +#endif } @@ -502,11 +514,16 @@ static void edit_params(u32 argc, char **argv, char **envp) { } else { +#if LLVM_MAJOR >= 11 + cc_params[cc_par_cnt++] = + alloc_printf("-fpass-plugin=%s/split-compares-pass.so", obj_path); +#else cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = alloc_printf("%s/split-compares-pass.so", obj_path); +#endif } @@ -536,11 +553,17 @@ static void edit_params(u32 argc, char **argv, char **envp) { alloc_printf("%s/cmplog-switches-pass.so", obj_path); // reuse split switches from laf +#if LLVM_MAJOR >= 11 + cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager"; + cc_params[cc_par_cnt++] = + alloc_printf("-fpass-plugin=%s/split-switches-pass.so", obj_path); +#else cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = alloc_printf("%s/split-switches-pass.so", obj_path); +#endif } @@ -548,9 +571,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { } -#if LLVM_MAJOR >= 13 - // fuck you llvm 13 - cc_params[cc_par_cnt++] = "-fno-experimental-new-pass-manager"; +#if LLVM_MAJOR == 13 // TODO: set to 14 when done FIXME + // Use the old pass manager in LLVM 13 which the afl++ passes still use. + cc_params[cc_par_cnt++] = "-flegacy-pass-manager"; #endif if (lto_mode && !have_c) { @@ -633,10 +656,16 @@ static void edit_params(u32 argc, char **argv, char **envp) { } else { +#if LLVM_MAJOR >= 11 + cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager"; + cc_params[cc_par_cnt++] = + alloc_printf("-fpass-plugin=%s/afl-llvm-pass.so", obj_path); +#else cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path); +#endif } @@ -653,11 +682,17 @@ static void edit_params(u32 argc, char **argv, char **envp) { } else { +#if LLVM_MAJOR >= 11 + cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager"; + cc_params[cc_par_cnt++] = + alloc_printf("-fpass-plugin=%s/cmplog-instructions-pass.so", obj_path); +#else cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = alloc_printf("%s/cmplog-instructions-pass.so", obj_path); +#endif cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index 4697a492..fe7be8e1 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -46879845 +a44fa94488d01aba60401ccf81f8bebcce685bf2 diff --git a/unicorn_mode/samples/compcov_x64/compcov_test_harness.py b/unicorn_mode/samples/compcov_x64/compcov_test_harness.py index 52f0a286..ce96b882 100644 --- a/unicorn_mode/samples/compcov_x64/compcov_test_harness.py +++ b/unicorn_mode/samples/compcov_x64/compcov_test_harness.py @@ -19,7 +19,7 @@ import os import signal from unicornafl import * -from unicornafl.x86_const import * +from unicorn.x86_const import * # Path to the file containing the binary to emulate BINARY_FILE = os.path.join( @@ -160,7 +160,7 @@ def main(): # Emulate the code, allowing it to process the mutated input print("Starting the AFL fuzz") - uc.afl_fuzz( + uc_afl_fuzz(uc, input_file=args.input_file, place_input_callback=place_input_callback, exits=[end_address], diff --git a/unicorn_mode/samples/speedtest/python/harness.py b/unicorn_mode/samples/speedtest/python/harness.py index 801ef4d1..604adf39 100644 --- a/unicorn_mode/samples/speedtest/python/harness.py +++ b/unicorn_mode/samples/speedtest/python/harness.py @@ -20,8 +20,8 @@ import os import struct from unicornafl import * -from unicornafl.unicorn_const import UC_ARCH_X86, UC_HOOK_CODE, UC_MODE_64 -from unicornafl.x86_const import ( +from unicorn.unicorn_const import UC_ARCH_X86, UC_HOOK_CODE, UC_MODE_64 +from unicorn.x86_const import ( UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RIP, diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl -Subproject 468798455a9f9790d2da369a18ed49fda3a64e8 +Subproject a44fa94488d01aba60401ccf81f8bebcce685bf |