diff options
34 files changed, 384 insertions, 347 deletions
diff --git a/custom_mutators/grammar_mutator/grammar_mutator b/custom_mutators/grammar_mutator/grammar_mutator -Subproject eedf07ddb0fb1f437f5e76b77cfd4064cf6a5d6 +Subproject b79d51a8daccbd7a693f9b6765c81ead14f28e2 diff --git a/docs/Changelog.md b/docs/Changelog.md index dad5fee2..63896622 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,11 +16,16 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. - fix a regression introduced in 3.10 that resulted in less coverage being detected. thanks to Collin May for reporting! - fix -n dumb mode (nobody should use this) + - fix stability issue with LTO and cmplog + - better banner + - frida_mode: David Carlier added Android support :) - afl-showmap, afl-tmin and afl-analyze now honor persistent mode for more speed. thanks to dloffre-snl for reporting! + - Prevent accidently killing non-afl/fuzz services when aborting + afl-showmap and other tools. - afl-cc: - fix for shared linking on MacOS - - llvm and LTO mode verified to work with new llvm 14-dev + - llvm and LTO mode modified to work with new llvm 14-dev (again) - added the very good grammar mutator "GramaTron" to the custom_mutators - added optimin, a faster and better corpus minimizer by @@ -32,6 +37,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. - fix AFL_PRELOAD issues on MacOS - removed utils/afl_frida because frida_mode/ is now so much better - added uninstall target to makefile (todo: update new readme!) + - removed indirections in rust callbacks for unicornafl ### Version ++3.14c (release) diff --git a/docs/life_pro_tips.md b/docs/life_pro_tips.md deleted file mode 100644 index e79bcafa..00000000 --- a/docs/life_pro_tips.md +++ /dev/null @@ -1,87 +0,0 @@ -# AFL "Life Pro Tips" - -Bite-sized advice for those who understand the basics, but can't be bothered -to read or memorize every other piece of documentation for AFL. - -## Get more bang for your buck by using fuzzing dictionaries. - -See [dictionaries/README.md](../dictionaries/README.md) to learn how. - -## You can get the most out of your hardware by parallelizing AFL jobs. - -See [parallel_fuzzing.md](parallel_fuzzing.md) for step-by-step tips. - -## Improve the odds of spotting memory corruption bugs with libdislocator.so! - -It's easy. Consult [utils/libdislocator/README.md](../utils/libdislocator/README.md) for usage tips. - -## Want to understand how your target parses a particular input file? - -Try the bundled `afl-analyze` tool; it's got colors and all! - -## You can visually monitor the progress of your fuzzing jobs. - -Run the bundled `afl-plot` utility to generate browser-friendly graphs. - -## Need to monitor AFL jobs programmatically? -Check out the `fuzzer_stats` file in the AFL output dir or try `afl-whatsup`. - -## Puzzled by something showing up in red or purple in the AFL UI? -It could be important - consult [status_screen.md](status_screen.md) right away! - -## Know your target? Convert it to persistent mode for a huge performance gain! -Consult section #5 in [instrumentation/README.llvm.md](../instrumentation/README.llvm.md) for tips. - -## Using clang? -Check out [instrumentation/](../instrumentation/) for a faster alternative to afl-gcc! - -## Did you know that AFL can fuzz closed-source or cross-platform binaries? -Check out [qemu_mode/README.md](../qemu_mode/README.md) and [unicorn_mode/README.md](../unicorn_mode/README.md) for more. - -## Did you know that afl-fuzz can minimize any test case for you? -Try the bundled `afl-tmin` tool - and get small repro files fast! - -## Not sure if a crash is exploitable? AFL can help you figure it out. Specify -`-C` to enable the peruvian were-rabbit mode. - -## Trouble dealing with a machine uprising? Relax, we've all been there. - -Find essential survival tips at [http://lcamtuf.coredump.cx/prep/](http://lcamtuf.coredump.cx/prep/). - -## Want to automatically spot non-crashing memory handling bugs? - -Try running an AFL-generated corpus through ASAN, MSAN, or Valgrind. - -## Good selection of input files is critical to a successful fuzzing job. - -See [perf_tips.md](perf_tips.md) for pro tips. - -## You can improve the odds of automatically spotting stack corruption issues. - -Specify `AFL_HARDEN=1` in the environment to enable hardening flags. - -## Bumping into problems with non-reproducible crashes? -It happens, but usually -isn't hard to diagnose. See section #7 in README.md for tips. - -## Fuzzing is not just about memory corruption issues in the codebase. -Add some -sanity-checking `assert()` / `abort()` statements to effortlessly catch logic bugs. - -## Hey kid... pssst... want to figure out how AFL really works? - -Check out [technical_details.md](technical_details.md) for all the gory details in one place! - -## There's a ton of third-party helper tools designed to work with AFL! - -Be sure to check out [sister_projects.md](sister_projects.md) before writing your own. - -## Need to fuzz the command-line arguments of a particular program? - -You can find a simple solution in [utils/argv_fuzzing](../utils/argv_fuzzing/). - -## Attacking a format that uses checksums? - -Remove the checksum-checking code or use a postprocessor! -See `afl_custom_post_process` in [custom_mutators/examples/example.c](../custom_mutators/examples/example.c) for more. - diff --git a/frida_mode/GNUmakefile b/frida_mode/GNUmakefile index 3e35e2f6..ed35c9f6 100644 --- a/frida_mode/GNUmakefile +++ b/frida_mode/GNUmakefile @@ -30,8 +30,7 @@ AFL_CFLAGS:=-Wno-unused-parameter \ LDFLAGS+=-shared \ -lpthread \ - -lresolv \ - -ldl + -lresolv ifdef DEBUG CFLAGS+=-Werror \ @@ -71,7 +70,9 @@ ifdef DEBUG endif LDFLAGS+= -z noexecstack \ -Wl,--gc-sections \ - -Wl,--exclude-libs,ALL + -Wl,--exclude-libs,ALL \ + -ldl \ + -lrt LDSCRIPT:=-Wl,--version-script=$(PWD)frida.map endif @@ -79,6 +80,22 @@ ifeq "$(shell uname)" "Linux" OS:=linux endif +ifneq "$(findstring android, $(shell $(CC) --version 2>/dev/null))" "" + OS:=android + ifneq "$(findstring aarch64, $(shell $(CC) --version 2>/dev/null))" "" + ARCH:=arm64 + endif + ifneq "$(findstring arm, $(shell $(CC) --version 2>/dev/null))" "" + ARCH:=arm + endif + ifneq "$(findstring x86_64, $(shell $(CC) --version 2>/dev/null))" "" + ARCH:=x86_64 + endif + ifneq "$(findstring i686, $(shell $(CC) --version 2>/dev/null))" "" + ARCH:=x86 + endif +endif + ifndef OS $(error "Operating system unsupported") endif diff --git a/frida_mode/README.md b/frida_mode/README.md index 165f8089..df40c771 100644 --- a/frida_mode/README.md +++ b/frida_mode/README.md @@ -55,6 +55,20 @@ tests in 32-bit mode, run `make ARCH=x86 frida`. When switching between architectures it may be necessary to run `make clean` first for a given build target to remove previously generated binaries for a different architecture. +### Android + +In order to build, you need to download the Android SDK. + +``` +https://developer.android.com/ndk/downloads +``` + +Then creating locally a standalone chain as follow. + +``` +https://developer.android.com/ndk/guides/standalone_toolchain +``` + ## Usage FRIDA mode added some small modifications to `afl-fuzz` and similar tools diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h index 909b2a2c..cac5ee93 100644 --- a/frida_mode/include/instrument.h +++ b/frida_mode/include/instrument.h @@ -29,6 +29,7 @@ GumStalkerTransformer *instrument_get_transformer(void); /* Functions to be implemented by the different architectures */ gboolean instrument_is_coverage_optimize_supported(void); +void instrument_coverage_optimize_init(void); void instrument_coverage_optimize(const cs_insn * instr, GumStalkerOutput *output); diff --git a/frida_mode/include/ranges.h b/frida_mode/include/ranges.h index 0220a59d..3bd9eaa6 100644 --- a/frida_mode/include/ranges.h +++ b/frida_mode/include/ranges.h @@ -10,6 +10,8 @@ extern gboolean ranges_inst_jit; void ranges_config(void); void ranges_init(void); +void ranges_print_debug_maps(void); + gboolean range_is_excluded(GumAddress address); void ranges_exclude(); diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 71d9bdf6..81d85aa1 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -356,6 +356,7 @@ void instrument_init(void) { instrument_hash_seed); instrument_hash_zero = instrument_get_offset_hash(0); + instrument_coverage_optimize_init(); instrument_debug_init(); instrument_coverage_init(); asan_init(); diff --git a/frida_mode/src/instrument/instrument_arm32.c b/frida_mode/src/instrument/instrument_arm32.c index 0e15940a..4b0a648e 100644 --- a/frida_mode/src/instrument/instrument_arm32.c +++ b/frida_mode/src/instrument/instrument_arm32.c @@ -22,6 +22,10 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_coverage_optimize_init(void) { + WARNF("Optimized coverage not supported on this architecture"); +} + void instrument_flush(GumStalkerOutput *output) { gum_arm_writer_flush(output->writer.arm); diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c index cf37e048..80d1d845 100644 --- a/frida_mode/src/instrument/instrument_arm64.c +++ b/frida_mode/src/instrument/instrument_arm64.c @@ -95,6 +95,9 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_coverage_optimize_init(void) { +} + void instrument_flush(GumStalkerOutput *output) { gum_arm64_writer_flush(output->writer.arm64); diff --git a/frida_mode/src/instrument/instrument_x64.c b/frida_mode/src/instrument/instrument_x64.c index 1c2cf113..a7eb650a 100644 --- a/frida_mode/src/instrument/instrument_x64.c +++ b/frida_mode/src/instrument/instrument_x64.c @@ -1,4 +1,16 @@ +#include <fcntl.h> #include <stddef.h> +#include <sys/mman.h> +#include <sys/shm.h> + +#if defined(__linux__) +#if !defined(__ANDROID__) +#include <asm/prctl.h> +#include <sys/syscall.h> +#else +#include <linux/ashmem.h> +#endif +#endif #include "frida-gumjs.h" @@ -6,245 +18,290 @@ #include "debug.h" #include "instrument.h" +#include "ranges.h" #if defined(__x86_64__) -static GumAddress current_log_impl = GUM_ADDRESS(0); +#ifndef MAP_FIXED_NOREPLACE + #ifdef MAP_EXCL + #define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED + #else + #define MAP_FIXED_NOREPLACE MAP_FIXED + #endif +#endif - #pragma pack(push, 1) +gboolean instrument_is_coverage_optimize_supported(void) { + return true; + +} + +static gboolean instrument_coverage_in_range(gssize offset) { + + return (offset >= G_MININT32 && offset <= G_MAXINT32); + +} + + #pragma pack(push, 1) typedef struct { - /* - * pushfq - * push rdx - * mov rdx, [&previouspc] (rip relative addr) - * xor rdx, rdi (current_pc) - * shr rdi. 1 - * mov [&previouspc], rdi - * lea rsi, [&_afl_area_ptr] (rip relative) - * add rdx, rsi - * add byte ptr [rdx], 1 - * adc byte ptr [rdx], 0 - - * pop rdx - * popfq - */ + // cur_location = (block_address >> 4) ^ (block_address << 8); + // shared_mem[cur_location ^ prev_location]++; + // prev_location = cur_location >> 1; + + // => 0x7ffff6cfb086: lea rsp,[rsp-0x80] + // 0x7ffff6cfb08b: pushf + // 0x7ffff6cfb08c: push rsi + // 0x7ffff6cfb08d: mov rsi,0x228 + // 0x7ffff6cfb094: xchg QWORD PTR [rip+0x3136a5],rsi # 0x7ffff700e740 + // 0x7ffff6cfb09b: xor rsi,0x451 + // 0x7ffff6cfb0a2: add BYTE PTR [rsi+0x10000],0x1 + // 0x7ffff6cfb0a9: adc BYTE PTR [rsi+0x10000],0x0 + // 0x7ffff6cfb0b0: pop rsi + // 0x7ffff6cfb0b1: popf + // 0x7ffff6cfb0b2: lea rsp,[rsp+0x80] + + + uint8_t lea_rsp_rsp_sub_rz[5]; uint8_t push_fq; - uint8_t push_rdx; - uint8_t mov_rdx_rip_off[7]; - uint8_t xor_rdx_rdi[3]; - uint8_t shr_rdi[3]; - uint8_t mov_rip_off_rdi[7]; - - uint8_t lea_rdi_rip_off[7]; - uint8_t add_rdx_rdi[3]; - uint8_t add_byte_ptr_rdx[3]; - uint8_t adc_byte_ptr_rdx[3]; - - uint8_t pop_rdx; + uint8_t push_rsi; + + uint8_t mov_rsi_curr_loc_shr_1[7]; + uint8_t xchg_rsi_prev_loc_curr_loc[7]; + uint8_t xor_rsi_curr_loc[7]; + + uint8_t add_rsi_1[7]; + uint8_t adc_rsi_0[7]; + + uint8_t pop_rsi; uint8_t pop_fq; - uint8_t ret; + uint8_t lsa_rsp_rsp_add_rz[8]; } afl_log_code_asm_t; #pragma pack(pop) - #pragma pack(push, 8) -typedef struct { +typedef union { - afl_log_code_asm_t assembly; - uint64_t current_pc; + afl_log_code_asm_t code; + uint8_t bytes[0]; -} afl_log_code_t; +} afl_log_code; - #pragma pack(pop) +static const afl_log_code_asm_t template = + { -typedef union { + .lea_rsp_rsp_sub_rz = {0x48, 0x8D, 0x64, 0x24, 0x80}, + .push_fq = 0x9c, + .push_rsi = 0x56, - afl_log_code_t data; - uint8_t bytes[0]; + .mov_rsi_curr_loc_shr_1 = {0x48, 0xC7, 0xC6}, + .xchg_rsi_prev_loc_curr_loc = {0x48, 0x87, 0x35}, + .xor_rsi_curr_loc = {0x48, 0x81, 0xF6}, -} afl_log_code; + .add_rsi_1 = {0x80, 0x86, 0x00, 0x00, 0x00, 0x00, 0x01}, + .adc_rsi_0 = {0x80, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00}, -static const afl_log_code_asm_t template = { + .pop_rsi = 0x5E, + .pop_fq = 0x9D, + .lsa_rsp_rsp_add_rz = {0x48, 0x8D, 0xA4, 0x24, 0x80, 0x00, 0x00, 0x00}, - .push_fq = 0x9c, - .push_rdx = 0x52, - .mov_rdx_rip_off = - { +} - 0x48, 0x8b, 0x15, - /* TBC */ +; - }, +static gboolean instrument_coverage_find_low(const GumRangeDetails *details, + gpointer user_data) { - .xor_rdx_rdi = - { + static GumAddress last_limit = (64ULL << 10); + gpointer * address = (gpointer *)user_data; - 0x48, - 0x31, - 0xfa, + if ((details->range->base_address - last_limit) > __afl_map_size) { - }, + *address = GSIZE_TO_POINTER(last_limit); + return FALSE; - .shr_rdi = {0x48, 0xd1, 0xef}, - .mov_rip_off_rdi = {0x48, 0x89, 0x3d}, + } - .lea_rdi_rip_off = - { + if (details->range->base_address > ((2ULL << 20) - __afl_map_size)) { - 0x48, - 0x8d, - 0x3d, + return FALSE; - }, + } - .add_rdx_rdi = {0x48, 0x01, 0xfA}, + last_limit = details->range->base_address + details->range->size; + return TRUE; - .add_byte_ptr_rdx = - { +} - 0x80, - 0x02, - 0x01, +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) { - .adc_byte_ptr_rdx = - { + FATAL("Failed to map mmap __afl_area_ptr: %d", errno); - 0x80, - 0x12, - 0x00, + } - }, +} - .pop_rdx = 0x5a, - .pop_fq = 0x9d, - .ret = 0xc3}; +static void instrument_coverage_optimize_map_mmap(char * shm_file_path, + gpointer address) { -static guint8 align_pad[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + int shm_fd = -1; -gboolean instrument_is_coverage_optimize_supported(void) { + if (munmap(__afl_area_ptr, __afl_map_size) != 0) { - return true; + FATAL("Failed to unmap previous __afl_area_ptr"); -} + } -static gboolean instrument_coverage_in_range(gssize offset) { + __afl_area_ptr = NULL; - return (offset >= G_MININT32 && offset <= G_MAXINT32); +#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_coverate_write_function(GumStalkerOutput *output) { +static void instrument_coverage_optimize_map_shm(guint64 shm_env_val, + gpointer address) { - guint64 misalign = 0; - GumX86Writer *cw = output->writer.x86; - GumAddress code_addr = 0; - afl_log_code code = {0}; - /*guint64 instrument_hash_zero = 0;*/ + if (shmdt(__afl_area_ptr) != 0) { - if (current_log_impl == 0 || - !gum_x86_writer_can_branch_directly_between(cw->pc, current_log_impl) || - !gum_x86_writer_can_branch_directly_between(cw->pc + 128, - current_log_impl)) { + FATAL("Failed to detach previous __afl_area_ptr"); - gconstpointer after_log_impl = cw->code + 1; + } - gum_x86_writer_put_jmp_near_label(cw, after_log_impl); + __afl_area_ptr = shmat(shm_env_val, address, 0); + if (__afl_area_ptr != address) { - misalign = (cw->pc & 0x7); - if (misalign != 0) { + FATAL("Failed to map shm __afl_area_ptr: %d", errno); - gum_x86_writer_put_bytes(cw, align_pad, 8 - misalign); + } - } +} - current_log_impl = cw->pc; - // gum_x86_writer_put_breakpoint(cw); - code_addr = cw->pc; +void instrument_coverage_optimize_init(void) { - code.data.assembly = template; - code.data.current_pc = instrument_get_offset_hash(0); + gpointer low_address = NULL; - gssize current_pc_value1 = - GPOINTER_TO_SIZE(&instrument_previous_pc) - - (code_addr + offsetof(afl_log_code, data.assembly.mov_rdx_rip_off) + - sizeof(code.data.assembly.mov_rdx_rip_off)); - gssize patch_offset1 = - offsetof(afl_log_code, data.assembly.mov_rdx_rip_off) + - sizeof(code.data.assembly.mov_rdx_rip_off) - sizeof(gint); - if (!instrument_coverage_in_range(current_pc_value1)) { + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, instrument_coverage_find_low, + &low_address); - FATAL("Patch out of range (current_pc_value1): 0x%016lX", - current_pc_value1); + OKF("Low address: %p", low_address); - } + if (low_address == 0 || + GPOINTER_TO_SIZE(low_address) > ((2UL << 20) - __afl_map_size)) { - gint *dst_pc_value = (gint *)&code.bytes[patch_offset1]; - *dst_pc_value = (gint)current_pc_value1; + FATAL("Invalid low_address: %p", low_address); - gssize current_pc_value2 = - GPOINTER_TO_SIZE(&instrument_previous_pc) - - (code_addr + offsetof(afl_log_code, data.assembly.mov_rip_off_rdi) + - sizeof(code.data.assembly.mov_rip_off_rdi)); - gssize patch_offset2 = - offsetof(afl_log_code, data.assembly.mov_rip_off_rdi) + - sizeof(code.data.assembly.mov_rip_off_rdi) - sizeof(gint); + } - if (!instrument_coverage_in_range(current_pc_value2)) { + ranges_print_debug_maps(); - FATAL("Patch out of range (current_pc_value2): 0x%016lX", - current_pc_value2); + char *shm_env = getenv(SHM_ENV_VAR); + OKF("SHM_ENV_VAR: %s", shm_env); - } + if (shm_env == NULL) { - dst_pc_value = (gint *)&code.bytes[patch_offset2]; - *dst_pc_value = (gint)current_pc_value2; + WARNF("SHM_ENV_VAR not set, using anonymous map for debugging purposes"); - gsize afl_area_ptr_value = - GPOINTER_TO_SIZE(__afl_area_ptr) - - (code_addr + offsetof(afl_log_code, data.assembly.lea_rdi_rip_off) + - sizeof(code.data.assembly.lea_rdi_rip_off)); - gssize afl_area_ptr_offset = - offsetof(afl_log_code, data.assembly.lea_rdi_rip_off) + - sizeof(code.data.assembly.lea_rdi_rip_off) - sizeof(gint); + instrument_coverage_optimize_map_mmap_anon(low_address); - if (!instrument_coverage_in_range(afl_area_ptr_value)) { + } else { - FATAL("Patch out of range (afl_area_ptr_value): 0x%016lX", - afl_area_ptr_value); + guint64 shm_env_val = g_ascii_strtoull(shm_env, NULL, 10); - } + if (shm_env_val == 0) { - gint *dst_afl_area_ptr_value = (gint *)&code.bytes[afl_area_ptr_offset]; - *dst_afl_area_ptr_value = (gint)afl_area_ptr_value; + instrument_coverage_optimize_map_mmap(shm_env, low_address); - gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code)); + } else { - gum_x86_writer_put_label(cw, after_log_impl); + instrument_coverage_optimize_map_shm(shm_env_val, low_address); + + } } + OKF("__afl_area_ptr: %p", __afl_area_ptr); + OKF("instrument_previous_pc: %p", &instrument_previous_pc); + } 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)); - instrument_coverate_write_function(output); - - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - -GUM_RED_ZONE_SIZE); - gum_x86_writer_put_push_reg(cw, GUM_REG_RDI); - gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RDI, area_offset); - gum_x86_writer_put_call_address(cw, current_log_impl); - gum_x86_writer_put_pop_reg(cw, GUM_REG_RDI); - gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, - GUM_RED_ZONE_SIZE); + GumAddress code_addr = 0; + + // gum_x86_writer_put_breakpoint(cw); + code_addr = cw->pc; + code.code = template; + + gssize curr_loc_shr_1_offset = + offsetof(afl_log_code, code.mov_rsi_curr_loc_shr_1) + + sizeof(code.code.mov_rsi_curr_loc_shr_1) - sizeof(guint32); + + *((guint32 *)&code.bytes[curr_loc_shr_1_offset]) = + (guint32)(area_offset >> 1); + + gssize prev_loc_value = + GPOINTER_TO_SIZE(&instrument_previous_pc) - + (code_addr + offsetof(afl_log_code, code.xchg_rsi_prev_loc_curr_loc) + + sizeof(code.code.xchg_rsi_prev_loc_curr_loc)); + gssize prev_loc_value_offset = + offsetof(afl_log_code, code.xchg_rsi_prev_loc_curr_loc) + + sizeof(code.code.xchg_rsi_prev_loc_curr_loc) - sizeof(gint); + if (!instrument_coverage_in_range(prev_loc_value)) { + + FATAL("Patch out of range (current_pc_value1): 0x%016lX", prev_loc_value); + + } + + *((gint *)&code.bytes[prev_loc_value_offset]) = (gint)prev_loc_value; + + gssize xor_curr_loc_offset = offsetof(afl_log_code, code.xor_rsi_curr_loc) + + sizeof(code.code.xor_rsi_curr_loc) - + sizeof(guint32); + + *((guint32 *)&code.bytes[xor_curr_loc_offset]) = (guint32)(area_offset); + + gssize add_rsi_1_offset = offsetof(afl_log_code, code.add_rsi_1) + + sizeof(code.code.add_rsi_1) - sizeof(guint32) - 1; + + *((guint32 *)&code.bytes[add_rsi_1_offset]) = + (guint32)GPOINTER_TO_SIZE(__afl_area_ptr); + + gssize adc_rsi_0_ffset = offsetof(afl_log_code, code.adc_rsi_0) + + sizeof(code.code.adc_rsi_0) - sizeof(guint32) - 1; + + *((guint32 *)&code.bytes[adc_rsi_0_ffset]) = + (guint32)GPOINTER_TO_SIZE(__afl_area_ptr); + + gum_x86_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code)); } diff --git a/frida_mode/src/instrument/instrument_x86.c b/frida_mode/src/instrument/instrument_x86.c index 7bf48f96..1ff5c920 100644 --- a/frida_mode/src/instrument/instrument_x86.c +++ b/frida_mode/src/instrument/instrument_x86.c @@ -83,6 +83,9 @@ void instrument_coverage_optimize(const cs_insn * instr, } +void instrument_coverage_optimize_init(void) { +} + void instrument_flush(GumStalkerOutput *output) { gum_x86_writer_flush(output->writer.x86); diff --git a/frida_mode/src/ranges.c b/frida_mode/src/ranges.c index 5b6eb462..1b666fce 100644 --- a/frida_mode/src/ranges.c +++ b/frida_mode/src/ranges.c @@ -549,18 +549,19 @@ static GArray *merge_ranges(GArray *a) { } +void ranges_print_debug_maps(void) { + + gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges_callback, NULL); + +} + void ranges_config(void) { if (getenv("AFL_FRIDA_DEBUG_MAPS") != NULL) { ranges_debug_maps = TRUE; } if (getenv("AFL_INST_LIBS") != NULL) { ranges_inst_libs = TRUE; } if (getenv("AFL_FRIDA_INST_JIT") != NULL) { ranges_inst_jit = TRUE; } - if (ranges_debug_maps) { - - gum_process_enumerate_ranges(GUM_PAGE_NO_ACCESS, print_ranges_callback, - NULL); - - } + if (ranges_debug_maps) { ranges_print_debug_maps(); } include_ranges = collect_ranges("AFL_FRIDA_INST_RANGES"); exclude_ranges = collect_ranges("AFL_FRIDA_EXCLUDE_RANGES"); diff --git a/frida_mode/src/seccomp/seccomp_atomic.c b/frida_mode/src/seccomp/seccomp_atomic.c index 5097511a..c2042f97 100644 --- a/frida_mode/src/seccomp/seccomp_atomic.c +++ b/frida_mode/src/seccomp/seccomp_atomic.c @@ -1,4 +1,4 @@ -#ifndef __APPLE__ +#if defined(__linux__) && !defined(__ANDROID__) #include <stdbool.h> #include <stdio.h> diff --git a/frida_mode/src/seccomp/seccomp_callback.c b/frida_mode/src/seccomp/seccomp_callback.c index 7e1e2070..a88196ac 100644 --- a/frida_mode/src/seccomp/seccomp_callback.c +++ b/frida_mode/src/seccomp/seccomp_callback.c @@ -1,4 +1,4 @@ -#ifndef __APPLE__ +#if defined(__linux__) && !defined(__ANDROID__) #include <execinfo.h> #include <fcntl.h> diff --git a/frida_mode/src/seccomp/seccomp_child.c b/frida_mode/src/seccomp/seccomp_child.c index f665f472..43a79894 100644 --- a/frida_mode/src/seccomp/seccomp_child.c +++ b/frida_mode/src/seccomp/seccomp_child.c @@ -1,4 +1,4 @@ -#ifndef __APPLE__ +#if defined(__linux__) && !defined(__ANDROID__) #include <fcntl.h> #include <sched.h> diff --git a/frida_mode/src/seccomp/seccomp_event.c b/frida_mode/src/seccomp/seccomp_event.c index dd4abde7..e2f592ca 100644 --- a/frida_mode/src/seccomp/seccomp_event.c +++ b/frida_mode/src/seccomp/seccomp_event.c @@ -1,4 +1,4 @@ -#ifndef __APPLE__ +#if defined(__linux__) && !defined(__ANDROID__) #include <stdint.h> #include <stdio.h> diff --git a/frida_mode/src/seccomp/seccomp_filter.c b/frida_mode/src/seccomp/seccomp_filter.c index 13ff7522..8d56c367 100644 --- a/frida_mode/src/seccomp/seccomp_filter.c +++ b/frida_mode/src/seccomp/seccomp_filter.c @@ -1,4 +1,4 @@ -#ifndef __APPLE__ +#if defined(__linux__) && !defined(__ANDROID__) #include <alloca.h> #include <errno.h> diff --git a/frida_mode/src/seccomp/seccomp_print.c b/frida_mode/src/seccomp/seccomp_print.c index be4d80ce..3cea1239 100644 --- a/frida_mode/src/seccomp/seccomp_print.c +++ b/frida_mode/src/seccomp/seccomp_print.c @@ -1,4 +1,4 @@ -#ifndef __APPLE__ +#if defined(__linux__) && !defined(__ANDROID__) #include <stdarg.h> diff --git a/frida_mode/src/seccomp/seccomp_socket.c b/frida_mode/src/seccomp/seccomp_socket.c index fae95805..ef937420 100644 --- a/frida_mode/src/seccomp/seccomp_socket.c +++ b/frida_mode/src/seccomp/seccomp_socket.c @@ -1,4 +1,4 @@ -#ifndef __APPLE__ +#if defined(__linux__) && !defined(__ANDROID__) #include <stdio.h> #include <string.h> diff --git a/frida_mode/src/seccomp/seccomp_syscall.c b/frida_mode/src/seccomp/seccomp_syscall.c index e023c131..8335b93c 100644 --- a/frida_mode/src/seccomp/seccomp_syscall.c +++ b/frida_mode/src/seccomp/seccomp_syscall.c @@ -1,4 +1,4 @@ -#ifndef __APPLE__ +#if defined(__linux__) && !defined(__ANDROID__) #include <limits.h> #include <stdio.h> diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 4b19e698..eaf55fb8 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1130,7 +1130,6 @@ void get_core_count(afl_state_t *); void fix_up_sync(afl_state_t *); void check_asan_opts(afl_state_t *); void check_binary(afl_state_t *, u8 *); -void fix_up_banner(afl_state_t *, u8 *); void check_if_tty(afl_state_t *); void setup_signal_handlers(void); void save_cmdline(afl_state_t *, u32, char **); diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 48ad2d02..013492f9 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -881,8 +881,6 @@ void ModuleSanitizerCoverage::InjectCoverageForIndirectCalls( Function &F, ArrayRef<Instruction *> IndirCalls) { if (IndirCalls.empty()) return; - assert(Options.TracePC || Options.TracePCGuard || - Options.Inline8bitCounters /*|| Options.InlineBoolFlag*/); for (auto I : IndirCalls) { IRBuilder<> IRB(I); diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 73e41f60..4eb8424f 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -244,7 +244,11 @@ bool AFLLTOPass::runOnModule(Module &M) { // the instrument file list check AttributeList Attrs = F.getAttributes(); +#if LLVM_VERSION_MAJOR < 14 if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) { +#else + if (Attrs.hasFnAttr(StringRef("skipinstrument"))) { +#endif if (debug) fprintf(stderr, diff --git a/instrumentation/afl-llvm-lto-instrumentlist.so.cc b/instrumentation/afl-llvm-lto-instrumentlist.so.cc index 416dbb88..0ec0e427 100644 --- a/instrumentation/afl-llvm-lto-instrumentlist.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentlist.so.cc @@ -116,10 +116,15 @@ bool AFLcheckIfInstrument::runOnModule(Module &M) { auto & Ctx = F.getContext(); AttributeList Attrs = F.getAttributes(); +#if LLVM_VERSION_MAJOR < 14 AttrBuilder NewAttrs; NewAttrs.addAttribute("skipinstrument"); F.setAttributes( Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs)); +#else + AttributeList NewAttrs = Attrs.addFnAttribute(Ctx, "skipinstrument"); + F.setAttributes(NewAttrs); +#endif } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index c8c94c08..54f510c4 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -610,12 +610,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (!time_ms) { - kill(fsrv->fsrv_pid, fsrv->kill_signal); + if (fsrv->fsrv_pid > 0) { kill(fsrv->fsrv_pid, fsrv->kill_signal); } } else if (time_ms > fsrv->init_tmout) { fsrv->last_run_timed_out = 1; - kill(fsrv->fsrv_pid, fsrv->kill_signal); + if (fsrv->fsrv_pid > 0) { kill(fsrv->fsrv_pid, fsrv->kill_signal); } } else { @@ -1248,7 +1248,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout, /* If there was no response from forkserver after timeout seconds, we kill the child. The forkserver should inform us afterwards */ - kill(fsrv->child_pid, fsrv->kill_signal); + if (fsrv->child_pid > 0) { kill(fsrv->child_pid, fsrv->kill_signal); } fsrv->last_run_timed_out = 1; if (read(fsrv->fsrv_st_fd, &fsrv->child_status, 4) < 4) { exec_ms = 0; } diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 9bb25785..9c45f08a 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -2815,43 +2815,6 @@ void check_binary(afl_state_t *afl, u8 *fname) { } -/* Trim and possibly create a banner for the run. */ - -void fix_up_banner(afl_state_t *afl, u8 *name) { - - if (!afl->use_banner) { - - if (afl->sync_id) { - - afl->use_banner = afl->sync_id; - - } else { - - u8 *trim = strrchr(name, '/'); - if (!trim) { - - afl->use_banner = name; - - } else { - - afl->use_banner = trim + 1; - - } - - } - - } - - if (strlen(afl->use_banner) > 32) { - - u8 *tmp = ck_alloc(36); - sprintf(tmp, "%.32s...", afl->use_banner); - afl->use_banner = tmp; - - } - -} - /* Check if we're on TTY. */ void check_if_tty(afl_state_t *afl) { diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 4173f4e1..da6ba7d9 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -291,8 +291,6 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u32 handicap, u8 from_queue) { - if (unlikely(afl->shm.cmplog_mode)) { q->exec_cksum = 0; } - u8 fault = 0, new_bits = 0, var_detected = 0, hnb = 0, first_run = (q->exec_cksum == 0); u64 start_us, stop_us, diff_us; @@ -300,6 +298,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u32 use_tmout = afl->fsrv.exec_tmout; u8 *old_sn = afl->stage_name; + if (unlikely(afl->shm.cmplog_mode)) { q->exec_cksum = 0; } + /* Be a bit more generous about timeouts when resuming sessions, or when trying to calibrate already-added finds. This helps avoid trouble due to intermittent latency. */ @@ -343,6 +343,32 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } + /* we need a dummy run if this is LTO + cmplog */ + if (unlikely(afl->shm.cmplog_mode)) { + + write_to_testcase(afl, use_mem, q->len); + + fault = fuzz_run_target(afl, &afl->fsrv, use_tmout); + + /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed, + we want to bail out quickly. */ + + if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; } + + if (!afl->non_instrumented_mode && !afl->stage_cur && + !count_bytes(afl, afl->fsrv.trace_bits)) { + + fault = FSRV_RUN_NOINST; + goto abort_calibration; + + } + +#ifdef INTROSPECTION + if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size; +#endif + + } + if (q->exec_cksum) { memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 870ba69a..0c06232b 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -441,9 +441,10 @@ void show_stats(afl_state_t *afl) { u64 cur_ms; u32 t_bytes, t_bits; - u32 banner_len, banner_pad; - u8 tmp[256]; - u8 time_tmp[64]; + static u8 banner[128]; + u32 banner_len, banner_pad; + u8 tmp[256]; + u8 time_tmp[64]; u8 val_buf[8][STRINGIFY_VAL_SIZE_MAX]; #define IB(i) (val_buf[(i)]) @@ -656,26 +657,34 @@ void show_stats(afl_state_t *afl) { } /* Let's start by drawing a centered banner. */ + if (unlikely(!banner[0])) { - banner_len = (afl->crash_mode ? 24 : 22) + strlen(VERSION) + - strlen(afl->use_banner) + strlen(afl->power_name) + 3 + 5; - banner_pad = (79 - banner_len) / 2; - memset(tmp, ' ', banner_pad); + char *si = ""; + if (afl->sync_id) { si = afl->sync_id; } + memset(banner, 0, sizeof(banner)); + banner_len = (afl->crash_mode ? 20 : 18) + strlen(VERSION) + strlen(si) + + strlen(afl->power_name) + 4 + 6; -#ifdef HAVE_AFFINITY - sprintf( - tmp + banner_pad, - "%s " cLCY VERSION cLGN " (%s) " cPIN "[%s]" cBLU " {%d}", - afl->crash_mode ? cPIN "peruvian were-rabbit" : cYEL "american fuzzy lop", - afl->use_banner, afl->power_name, afl->cpu_aff); -#else - sprintf( - tmp + banner_pad, "%s " cLCY VERSION cLGN " (%s) " cPIN "[%s]", - afl->crash_mode ? cPIN "peruvian were-rabbit" : cYEL "american fuzzy lop", - afl->use_banner, afl->power_name); -#endif /* HAVE_AFFINITY */ + if (strlen(afl->use_banner) + banner_len > 75) { + + afl->use_banner += (strlen(afl->use_banner) + banner_len) - 76; + memset(afl->use_banner, '.', 3); + + } + + banner_len += strlen(afl->use_banner); + banner_pad = (79 - banner_len) / 2; + memset(banner, ' ', banner_pad); + + sprintf(banner + banner_pad, + "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]", + afl->crash_mode ? cPIN "peruvian were-rabbit" + : cYEL "american fuzzy lop", + si, afl->use_banner, afl->power_name); + + } - SAYF("\n%s\n", tmp); + SAYF("\n%s\n", banner); /* "Handy" shortcuts for drawing boxes... */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 92a37697..26886a4f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1189,7 +1189,17 @@ int main(int argc, char **argv_orig, char **envp) { } - if (afl->sync_id) { fix_up_sync(afl); } + if (afl->sync_id) { + + if (strlen(afl->sync_id) > 24) { + + FATAL("sync_id max length is 24 characters"); + + } + + fix_up_sync(afl); + + } if (!strcmp(afl->in_dir, afl->out_dir)) { @@ -1218,6 +1228,8 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->afl_env.afl_statsd)) { statsd_setup_format(afl); } + if (!afl->use_banner) { afl->use_banner = argv[optind]; } + if (strchr(argv[optind], '/') == NULL && !afl->unicorn_mode) { WARNF(cLRD @@ -1486,9 +1498,6 @@ int main(int argc, char **argv_orig, char **envp) { } save_cmdline(afl, argc, argv); - - fix_up_banner(afl, argv[optind]); - check_if_tty(afl); if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 75b0ff99..5df07bf2 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -242,9 +242,14 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { if (cmin_mode && (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) { - // create empty file to prevent error messages in afl-cmin - fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); - close(fd); + if (strcmp(outfile, "-")) { + + // create empty file to prevent error messages in afl-cmin + fd = open(outfile, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + close(fd); + + } + return ret; } diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index cbca63e5..cc8d5b34 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -f1c853648a74b0157d233a2ef9f1693cfee78c11 +d4915053d477dd827b3fe4b494173d3fbf9f456e diff --git a/unicorn_mode/samples/speedtest/rust/src/main.rs b/unicorn_mode/samples/speedtest/rust/src/main.rs index 77356a67..89e10833 100644 --- a/unicorn_mode/samples/speedtest/rust/src/main.rs +++ b/unicorn_mode/samples/speedtest/rust/src/main.rs @@ -12,11 +12,11 @@ use std::{ use unicornafl::{ unicorn_const::{uc_error, Arch, Mode, Permission}, - RegisterX86::{self, *}, - Unicorn, UnicornHandle, + RegisterX86::*, + Unicorn, }; -const BINARY: &str = &"../target"; +const BINARY: &str = "../target"; // Memory map for the code to be tested // Arbitrary address where code to test will be loaded @@ -47,7 +47,7 @@ fn read_file(filename: &str) -> Result<Vec<u8>, io::Error> { fn parse_locs(loc_name: &str) -> Result<Vec<u64>, io::Error> { let contents = &read_file(&format!("../target.offsets.{}", loc_name))?; //println!("Read: {:?}", contents); - Ok(str_from_u8_unchecked(&contents) + Ok(str_from_u8_unchecked(contents) .split('\n') .map(|x| { //println!("Trying to convert {}", &x[2..]); @@ -87,8 +87,7 @@ fn main() { } fn fuzz(input_file: &str) -> Result<(), uc_error> { - let mut unicorn = Unicorn::new(Arch::X86, Mode::MODE_64, 0)?; - let mut uc: UnicornHandle<'_, _> = unicorn.borrow(); + let mut uc = Unicorn::new(Arch::X86, Mode::MODE_64, 0)?; let binary = read_file(BINARY).unwrap_or_else(|_| panic!("Could not read modem image: {}", BINARY)); @@ -133,7 +132,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> { let already_allocated_malloc = already_allocated.clone(); // We use a very simple malloc/free stub here, // that only works for exactly one allocation at a time. - let hook_malloc = move |mut uc: UnicornHandle<'_, _>, addr: u64, size: u32| { + let hook_malloc = move |uc: &mut Unicorn<'_, _>, addr: u64, size: u32| { if already_allocated_malloc.get() { println!("Double malloc, not supported right now!"); abort(); @@ -154,7 +153,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> { let already_allocated_free = already_allocated; // No real free, just set the "used"-flag to false. - let hook_free = move |mut uc: UnicornHandle<'_, _>, addr, size| { + let hook_free = move |uc: &mut Unicorn<'_, _>, addr, size| { if already_allocated_free.get() { println!("Double free detected. Real bug?"); abort(); @@ -177,7 +176,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> { */ // This is a fancy print function that we're just going to skip for fuzzing. - let hook_magicfn = move |mut uc: UnicornHandle<'_, _>, addr, size| { + let hook_magicfn = move |uc: &mut Unicorn<'_, _>, addr, size| { uc.reg_write(RIP, addr + size as u64).unwrap(); }; @@ -195,7 +194,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> { } let place_input_callback = - |uc: &mut UnicornHandle<'_, _>, afl_input: &mut [u8], _persistent_round| { + |uc: &mut Unicorn<'_, _>, afl_input: &mut [u8], _persistent_round| { // apply constraints to the mutated input if afl_input.len() > INPUT_MAX as usize { //println!("Skipping testcase with leng {}", afl_input.len()); @@ -209,9 +208,7 @@ fn fuzz(input_file: &str) -> Result<(), uc_error> { // return true if the last run should be counted as crash let crash_validation_callback = - |_uc: &mut UnicornHandle<'_, _>, result, _input: &[u8], _persistent_round| { - result != uc_error::OK - }; + |_uc: &mut Unicorn<'_, _>, result, _input: &[u8], _persistent_round| result != uc_error::OK; let end_addrs = parse_locs("main_ends").unwrap(); diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl -Subproject f1c853648a74b0157d233a2ef9f1693cfee78c1 +Subproject d4915053d477dd827b3fe4b494173d3fbf9f456 |