diff options
-rw-r--r-- | frida_mode/include/asan.h | 13 | ||||
-rw-r--r-- | frida_mode/include/ctx.h | 11 | ||||
-rw-r--r-- | frida_mode/src/asan/asan.c | 24 | ||||
-rw-r--r-- | frida_mode/src/asan/asan_arm.c | 22 | ||||
-rw-r--r-- | frida_mode/src/asan/asan_arm64.c | 22 | ||||
-rw-r--r-- | frida_mode/src/asan/asan_x64.c | 93 | ||||
-rw-r--r-- | frida_mode/src/asan/asan_x86.c | 22 | ||||
-rw-r--r-- | frida_mode/src/cmplog/cmplog_x64.c | 119 | ||||
-rw-r--r-- | frida_mode/src/ctx/ctx_x64.c | 114 | ||||
-rw-r--r-- | frida_mode/src/instrument/instrument.c | 3 | ||||
-rw-r--r-- | frida_mode/test/fasan/GNUmakefile | 156 | ||||
-rw-r--r-- | frida_mode/test/fasan/Makefile | 18 | ||||
-rw-r--r-- | frida_mode/test/fasan/test.c | 85 | ||||
-rw-r--r-- | include/envs.h | 1 | ||||
-rw-r--r-- | include/forkserver.h | 2 | ||||
-rw-r--r-- | src/afl-fuzz.c | 81 |
16 files changed, 664 insertions, 122 deletions
diff --git a/frida_mode/include/asan.h b/frida_mode/include/asan.h new file mode 100644 index 00000000..7a8726e0 --- /dev/null +++ b/frida_mode/include/asan.h @@ -0,0 +1,13 @@ +#ifndef _ASAN_H +#define _ASAN_H + +#include "frida-gum.h" + +extern gboolean asan_initialized; + +void asan_init(void); +void asan_arch_init(void); +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator); + +#endif + diff --git a/frida_mode/include/ctx.h b/frida_mode/include/ctx.h new file mode 100644 index 00000000..030d124a --- /dev/null +++ b/frida_mode/include/ctx.h @@ -0,0 +1,11 @@ +#ifndef _CTX_H +#define _CTX_H + +#include "frida-gum.h" + +#if defined(__x86_64__) +guint64 ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg); +#endif + +#endif + diff --git a/frida_mode/src/asan/asan.c b/frida_mode/src/asan/asan.c new file mode 100644 index 00000000..f78f690c --- /dev/null +++ b/frida_mode/src/asan/asan.c @@ -0,0 +1,24 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" + +gboolean asan_initialized = FALSE; + +void asan_init(void) { + + if (getenv("AFL_USE_FASAN") != NULL) { + + OKF("Frida ASAN mode enabled"); + asan_arch_init(); + asan_initialized = TRUE; + + } else { + + OKF("Frida ASAN mode disabled"); + + } + +} + diff --git a/frida_mode/src/asan/asan_arm.c b/frida_mode/src/asan/asan_arm.c new file mode 100644 index 00000000..526017be --- /dev/null +++ b/frida_mode/src/asan/asan_arm.c @@ -0,0 +1,22 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__arm__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +#endif + diff --git a/frida_mode/src/asan/asan_arm64.c b/frida_mode/src/asan/asan_arm64.c new file mode 100644 index 00000000..4e3fbafd --- /dev/null +++ b/frida_mode/src/asan/asan_arm64.c @@ -0,0 +1,22 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__aarch64__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +#endif + diff --git a/frida_mode/src/asan/asan_x64.c b/frida_mode/src/asan/asan_x64.c new file mode 100644 index 00000000..bdf4ac30 --- /dev/null +++ b/frida_mode/src/asan/asan_x64.c @@ -0,0 +1,93 @@ +#include <dlfcn.h> +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "ctx.h" +#include "util.h" + +typedef void (*asan_loadN_t)(uint64_t address, uint8_t size); +typedef void (*asan_storeN_t)(uint64_t address, uint8_t size); + +asan_loadN_t asan_loadN = NULL; +asan_storeN_t asan_storeN = NULL; + +#if defined(__x86_64__) + +static void asan_callout(GumCpuContext *ctx, gpointer user_data) { + + UNUSED_PARAMETER(user_data); + + cs_x86_op * operand = (cs_x86_op *)user_data; + x86_op_mem *mem = &operand->mem; + uint64_t base = 0; + uint64_t index = 0; + uint64_t address; + uint8_t size; + + if (mem->base != X86_REG_INVALID) { base = ctx_read_reg(ctx, mem->base); } + + if (mem->index != X86_REG_INVALID) { index = ctx_read_reg(ctx, mem->index); } + + address = base + (mem->scale * index) + mem->disp; + size = operand->size; + + if (operand->access == CS_AC_READ) { + + asan_loadN(address, size); + + } else if (operand->access == CS_AC_WRITE) { + + asan_storeN(address, size); + + } + +} + +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(iterator); + + cs_x86 x86 = instr->detail->x86; + cs_x86_op * operand; + x86_op_mem *mem; + cs_x86_op * ctx; + + if (!asan_initialized) return; + + if (instr->id == X86_INS_LEA) return; + + if (instr->id == X86_INS_NOP) return; + + for (uint8_t i = 0; i < x86.op_count; i++) { + + operand = &x86.operands[i]; + + if (operand->type != X86_OP_MEM) { continue; } + + mem = &operand->mem; + if (mem->segment != X86_REG_INVALID) { continue; } + + ctx = g_malloc0(sizeof(cs_x86_op)); + memcpy(ctx, operand, sizeof(cs_x86_op)); + gum_stalker_iterator_put_callout(iterator, asan_callout, ctx, g_free); + + } + +} + +void asan_arch_init(void) { + + asan_loadN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_loadN"); + asan_storeN = (asan_loadN_t)dlsym(RTLD_DEFAULT, "__asan_storeN"); + if (asan_loadN == NULL || asan_storeN == NULL) { + + FATAL("Frida ASAN failed to find '__asan_loadN' or '__asan_storeN'"); + + } + +} + +#endif + diff --git a/frida_mode/src/asan/asan_x86.c b/frida_mode/src/asan/asan_x86.c new file mode 100644 index 00000000..b946b3bf --- /dev/null +++ b/frida_mode/src/asan/asan_x86.c @@ -0,0 +1,22 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "asan.h" +#include "util.h" + +#if defined(__i386__) +void asan_instrument(const cs_insn *instr, GumStalkerIterator *iterator) { + + UNUSED_PARAMETER(instr); + UNUSED_PARAMETER(iterator); + if (asan_initialized) { + + FATAL("ASAN mode not supported on this architecture"); + + } + +} + +#endif + diff --git a/frida_mode/src/cmplog/cmplog_x64.c b/frida_mode/src/cmplog/cmplog_x64.c index 4d8f243a..c3621a29 100644 --- a/frida_mode/src/cmplog/cmplog_x64.c +++ b/frida_mode/src/cmplog/cmplog_x64.c @@ -3,46 +3,12 @@ #include "debug.h" #include "cmplog.h" +#include "ctx.h" #include "frida_cmplog.h" #include "util.h" #if defined(__x86_64__) - #define X86_REG_8L(LABEL, REG) \ - case LABEL: { \ - \ - return REG & GUM_INT8_MASK; \ - \ - } - - #define X86_REG_8H(LABEL, REG) \ - case LABEL: { \ - \ - return (REG & GUM_INT16_MASK) >> 8; \ - \ - } - - #define X86_REG_16(LABEL, REG) \ - case LABEL: { \ - \ - return (REG & GUM_INT16_MASK); \ - \ - } - - #define X86_REG_32(LABEL, REG) \ - case LABEL: { \ - \ - return (REG & GUM_INT32_MASK); \ - \ - } - - #define X86_REG_64(LABEL, REG) \ - case LABEL: { \ - \ - return (REG); \ - \ - } - typedef struct { x86_op_type type; @@ -65,75 +31,6 @@ typedef struct { } cmplog_pair_ctx_t; -static guint64 cmplog_read_reg(GumX64CpuContext *ctx, x86_reg reg) { - - switch (reg) { - - X86_REG_8L(X86_REG_AL, ctx->rax) - X86_REG_8L(X86_REG_BL, ctx->rbx) - X86_REG_8L(X86_REG_CL, ctx->rcx) - X86_REG_8L(X86_REG_DL, ctx->rdx) - X86_REG_8L(X86_REG_BPL, ctx->rbp) - X86_REG_8L(X86_REG_SIL, ctx->rsi) - X86_REG_8L(X86_REG_DIL, ctx->rdi) - - X86_REG_8H(X86_REG_AH, ctx->rax) - X86_REG_8H(X86_REG_BH, ctx->rbx) - X86_REG_8H(X86_REG_CH, ctx->rcx) - X86_REG_8H(X86_REG_DH, ctx->rdx) - - X86_REG_16(X86_REG_AX, ctx->rax) - X86_REG_16(X86_REG_BX, ctx->rbx) - X86_REG_16(X86_REG_CX, ctx->rcx) - X86_REG_16(X86_REG_DX, ctx->rdx) - X86_REG_16(X86_REG_DI, ctx->rdi) - X86_REG_16(X86_REG_SI, ctx->rsi) - X86_REG_16(X86_REG_BP, ctx->rbp) - - X86_REG_32(X86_REG_EAX, ctx->rax) - X86_REG_32(X86_REG_ECX, ctx->rcx) - X86_REG_32(X86_REG_EDX, ctx->rdx) - X86_REG_32(X86_REG_EBX, ctx->rbx) - X86_REG_32(X86_REG_ESP, ctx->rsp) - X86_REG_32(X86_REG_EBP, ctx->rbp) - X86_REG_32(X86_REG_ESI, ctx->rsi) - X86_REG_32(X86_REG_EDI, ctx->rdi) - X86_REG_32(X86_REG_R8D, ctx->r8) - X86_REG_32(X86_REG_R9D, ctx->r9) - X86_REG_32(X86_REG_R10D, ctx->r10) - X86_REG_32(X86_REG_R11D, ctx->r11) - X86_REG_32(X86_REG_R12D, ctx->r12) - X86_REG_32(X86_REG_R13D, ctx->r13) - X86_REG_32(X86_REG_R14D, ctx->r14) - X86_REG_32(X86_REG_R15D, ctx->r15) - X86_REG_32(X86_REG_EIP, ctx->rip) - - X86_REG_64(X86_REG_RAX, ctx->rax) - X86_REG_64(X86_REG_RCX, ctx->rcx) - X86_REG_64(X86_REG_RDX, ctx->rdx) - X86_REG_64(X86_REG_RBX, ctx->rbx) - X86_REG_64(X86_REG_RSP, ctx->rsp) - X86_REG_64(X86_REG_RBP, ctx->rbp) - X86_REG_64(X86_REG_RSI, ctx->rsi) - X86_REG_64(X86_REG_RDI, ctx->rdi) - X86_REG_64(X86_REG_R8, ctx->r8) - X86_REG_64(X86_REG_R9, ctx->r9) - X86_REG_64(X86_REG_R10, ctx->r10) - X86_REG_64(X86_REG_R11, ctx->r11) - X86_REG_64(X86_REG_R12, ctx->r12) - X86_REG_64(X86_REG_R13, ctx->r13) - X86_REG_64(X86_REG_R14, ctx->r14) - X86_REG_64(X86_REG_R15, ctx->r15) - X86_REG_64(X86_REG_RIP, ctx->rip) - - default: - FATAL("Failed to read register: %d", reg); - return 0; - - } - -} - static gboolean cmplog_read_mem(GumX64CpuContext *ctx, uint8_t size, x86_op_mem *mem, guint64 *val) { @@ -141,9 +38,9 @@ static gboolean cmplog_read_mem(GumX64CpuContext *ctx, uint8_t size, guint64 index = 0; guint64 address; - if (mem->base != X86_REG_INVALID) base = cmplog_read_reg(ctx, mem->base); + if (mem->base != X86_REG_INVALID) base = ctx_read_reg(ctx, mem->base); - if (mem->index != X86_REG_INVALID) index = cmplog_read_reg(ctx, mem->index); + if (mem->index != X86_REG_INVALID) index = ctx_read_reg(ctx, mem->index); address = base + (index * mem->scale) + mem->disp; @@ -178,7 +75,7 @@ static gboolean cmplog_get_operand_value(GumCpuContext *context, switch (ctx->type) { case X86_OP_REG: - *val = cmplog_read_reg(context, ctx->reg); + *val = ctx_read_reg(context, ctx->reg); return TRUE; case X86_OP_IMM: *val = ctx->imm; @@ -198,9 +95,9 @@ static void cmplog_call_callout(GumCpuContext *context, gpointer user_data) { UNUSED_PARAMETER(user_data); - guint64 address = cmplog_read_reg(context, X86_REG_RIP); - guint64 rdi = cmplog_read_reg(context, X86_REG_RDI); - guint64 rsi = cmplog_read_reg(context, X86_REG_RSI); + guint64 address = ctx_read_reg(context, X86_REG_RIP); + guint64 rdi = ctx_read_reg(context, X86_REG_RDI); + guint64 rsi = ctx_read_reg(context, X86_REG_RSI); if (((G_MAXULONG - rdi) < 32) || ((G_MAXULONG - rsi) < 32)) return; @@ -275,7 +172,7 @@ static void cmplog_instrument_call(const cs_insn * instr, static void cmplog_handle_cmp_sub(GumCpuContext *context, guint64 operand1, guint64 operand2, uint8_t size) { - guint64 address = cmplog_read_reg(context, X86_REG_RIP); + guint64 address = ctx_read_reg(context, X86_REG_RIP); register uintptr_t k = (uintptr_t)address; diff --git a/frida_mode/src/ctx/ctx_x64.c b/frida_mode/src/ctx/ctx_x64.c new file mode 100644 index 00000000..dec759f4 --- /dev/null +++ b/frida_mode/src/ctx/ctx_x64.c @@ -0,0 +1,114 @@ +#include "frida-gum.h" + +#include "debug.h" + +#include "ctx.h" + +#if defined(__x86_64__) + + #define X86_REG_8L(LABEL, REG) \ + case LABEL: { \ + \ + return REG & GUM_INT8_MASK; \ + \ + } + + #define X86_REG_8H(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK) >> 8; \ + \ + } + + #define X86_REG_16(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT16_MASK); \ + \ + } + + #define X86_REG_32(LABEL, REG) \ + case LABEL: { \ + \ + return (REG & GUM_INT32_MASK); \ + \ + } + + #define X86_REG_64(LABEL, REG) \ + case LABEL: { \ + \ + return (REG); \ + \ + } + +guint64 ctx_read_reg(GumX64CpuContext *ctx, x86_reg reg) { + + switch (reg) { + + X86_REG_8L(X86_REG_AL, ctx->rax) + X86_REG_8L(X86_REG_BL, ctx->rbx) + X86_REG_8L(X86_REG_CL, ctx->rcx) + X86_REG_8L(X86_REG_DL, ctx->rdx) + X86_REG_8L(X86_REG_BPL, ctx->rbp) + X86_REG_8L(X86_REG_SIL, ctx->rsi) + X86_REG_8L(X86_REG_DIL, ctx->rdi) + + X86_REG_8H(X86_REG_AH, ctx->rax) + X86_REG_8H(X86_REG_BH, ctx->rbx) + X86_REG_8H(X86_REG_CH, ctx->rcx) + X86_REG_8H(X86_REG_DH, ctx->rdx) + + X86_REG_16(X86_REG_AX, ctx->rax) + X86_REG_16(X86_REG_BX, ctx->rbx) + X86_REG_16(X86_REG_CX, ctx->rcx) + X86_REG_16(X86_REG_DX, ctx->rdx) + X86_REG_16(X86_REG_DI, ctx->rdi) + X86_REG_16(X86_REG_SI, ctx->rsi) + X86_REG_16(X86_REG_BP, ctx->rbp) + + X86_REG_32(X86_REG_EAX, ctx->rax) + X86_REG_32(X86_REG_ECX, ctx->rcx) + X86_REG_32(X86_REG_EDX, ctx->rdx) + X86_REG_32(X86_REG_EBX, ctx->rbx) + X86_REG_32(X86_REG_ESP, ctx->rsp) + X86_REG_32(X86_REG_EBP, ctx->rbp) + X86_REG_32(X86_REG_ESI, ctx->rsi) + X86_REG_32(X86_REG_EDI, ctx->rdi) + X86_REG_32(X86_REG_R8D, ctx->r8) + X86_REG_32(X86_REG_R9D, ctx->r9) + X86_REG_32(X86_REG_R10D, ctx->r10) + X86_REG_32(X86_REG_R11D, ctx->r11) + X86_REG_32(X86_REG_R12D, ctx->r12) + X86_REG_32(X86_REG_R13D, ctx->r13) + X86_REG_32(X86_REG_R14D, ctx->r14) + X86_REG_32(X86_REG_R15D, ctx->r15) + X86_REG_32(X86_REG_EIP, ctx->rip) + + X86_REG_64(X86_REG_RAX, ctx->rax) + X86_REG_64(X86_REG_RCX, ctx->rcx) + X86_REG_64(X86_REG_RDX, ctx->rdx) + X86_REG_64(X86_REG_RBX, ctx->rbx) + X86_REG_64(X86_REG_RSP, ctx->rsp) + X86_REG_64(X86_REG_RBP, ctx->rbp) + X86_REG_64(X86_REG_RSI, ctx->rsi) + X86_REG_64(X86_REG_RDI, ctx->rdi) + X86_REG_64(X86_REG_R8, ctx->r8) + X86_REG_64(X86_REG_R9, ctx->r9) + X86_REG_64(X86_REG_R10, ctx->r10) + X86_REG_64(X86_REG_R11, ctx->r11) + X86_REG_64(X86_REG_R12, ctx->r12) + X86_REG_64(X86_REG_R13, ctx->r13) + X86_REG_64(X86_REG_R14, ctx->r14) + X86_REG_64(X86_REG_R15, ctx->r15) + X86_REG_64(X86_REG_RIP, ctx->rip) + + default: + FATAL("Failed to read register: %d", reg); + return 0; + + } + +} + +#endif + diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 971f80c0..5c77ade6 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -5,6 +5,7 @@ #include "config.h" #include "debug.h" +#include "asan.h" #include "entry.h" #include "frida_cmplog.h" #include "instrument.h" @@ -107,6 +108,7 @@ static void instr_basic_block(GumStalkerIterator *iterator, if (!range_is_excluded((void *)instr->address)) { + asan_instrument(instr, iterator); cmplog_instrument(instr, iterator); } @@ -142,6 +144,7 @@ void instrument_init(void) { transformer = gum_stalker_transformer_make_from_callback(instr_basic_block, NULL, NULL); + asan_init(); cmplog_init(); } diff --git a/frida_mode/test/fasan/GNUmakefile b/frida_mode/test/fasan/GNUmakefile new file mode 100644 index 00000000..22689395 --- /dev/null +++ b/frida_mode/test/fasan/GNUmakefile @@ -0,0 +1,156 @@ +PWD:=$(shell pwd)/ +ROOT:=$(shell realpath $(PWD)../../..)/ +BUILD_DIR:=$(PWD)build/ + +TEST_DATA_DIR:=$(BUILD_DIR)in/ +TEST_DATA_FILE:=$(TEST_DATA_DIR)in +FRIDA_OUT:=$(BUILD_DIR)frida-out + +TEST_SRC:=$(PWD)/test.c +TEST_BIN:=$(BUILD_DIR)test + +CFLAGS+=-fPIC \ + -D_GNU_SOURCE \ + -g \ + -fno-omit-frame-pointer \ + -Wno-stringop-overflow \ + +LDFLAGS+=-ldl \ + +ifdef DEBUG +CFLAGS+=-Werror \ + -Wall \ + -Wextra \ + -Wpointer-arith +else +CFLAGS+=-Wno-pointer-arith +endif + +ifndef ARCH + +ARCH=$(shell uname -m) +ifeq "$(ARCH)" "aarch64" + ARCH:=arm64 +endif + +ifeq "$(ARCH)" "i686" + ARCH:=x86 +endif +endif + +ifeq "$(ARCH)" "x86" +LIBASAN_FILE:=libclang_rt.asan-i386.so +endif + +ifeq "$(ARCH)" "x64" +LIBASAN_FILE:=libclang_rt.asan-x86_64.so +endif + +ifeq "$(ARCH)" "aarch64" +LIBASAN_FILE:=libclang_rt.asan-aarch64.so +endif + +# LIBASAN:=/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.so +# LIBASAN:=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0 + +LLVM_CONFIG ?= llvm-config +ifeq "$(shell test -e '$(shell which $(LLVM_CONFIG))' && echo 1)" "1" + $(info Found llvm-config: '$(shell which $(LLVM_CONFIG))') +else + $(warning Cannot find llvm-config) +endif + +LLVM_BINDIR = $(shell $(LLVM_CONFIG) --bindir 2>/dev/null)/ +$(info LLVM_BINDIR: $(LLVM_BINDIR)) + +CLANG ?= $(LLVM_BINDIR)clang +ifeq "$(shell test -e '$(CLANG)' && echo 1)" "1" + $(info Found clang: '$(CLANG)') +else + $(warning Cannot find clang) +endif + +CLANGVER = $(shell $(CLANG) --version | sed -E -ne '/^.*version\ (1?[0-9]\.[0-9]\.[0-9]).*/s//\1/p') +$(info Clang version $(CLANGVER)) + +LLVM_LIBDIR = $(shell $(LLVM_CONFIG) --libdir 2>/dev/null) +$(info LLVM_LIBDIR: $(LLVM_LIBDIR)) + +LIBASAN:=$(LLVM_LIBDIR)/clang/$(CLANGVER)/lib/linux/$(LIBASAN_FILE) + +ifeq "$(shell test -e '$(LIBASAN)' && echo 1)" "1" + $(info Found Address Sanitizer DSO: '$(LIBASAN)') +else + $(error Error cannot find Address Sanitizer DSO) +endif + + +.PHONY: all clean format frida-noasan frida debug run + +############################## ALL ############################################# + +all: $(TEST_BIN) + +$(TEST_BIN): $(TEST_SRC) GNUmakefile | $(BUILD_DIR) + $(CC) \ + $(CFLAGS) \ + $(LDFLAGS) \ + -o $@ \ + $< + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +############################# TESTS ############################################ + +$(TEST_DATA_DIR): | $(BUILD_DIR) + mkdir -p $@ + +$(TEST_DATA_FILE): | $(TEST_DATA_DIR) + echo -n "TUODATM" > $@ + +frida-noasan: $(TEST_BIN) $(TEST_DATA_FILE) + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) + + +frida: $(TEST_BIN) $(TEST_DATA_FILE) + AFL_PRELOAD=/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux/libclang_rt.asan-x86_64.so \ + AFL_USE_FASAN=1 \ + $(ROOT)afl-fuzz \ + -D \ + -O \ + -i $(TEST_DATA_DIR) \ + -o $(FRIDA_OUT) \ + -- \ + $(TEST_BIN) + +debug: $(TEST_BIN) $(TEST_DATA_FILE) + gdb \ + --ex 'set environment LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so' \ + --ex 'set environment ASAN_OPTIONS=detect_leaks=false,halt_on_error=0' \ + --ex 'set environment AFL_USE_FASAN=1' \ + --ex 'set disassembly-flavor intel' \ + --ex 'r < $(TEST_DATA_FILE)' \ + --args $(TEST_BIN) \ + +run: $(TEST_BIN) $(TEST_DATA_FILE) + LD_PRELOAD=$(LIBASAN):$(ROOT)afl-frida-trace.so \ + ASAN_OPTIONS=detect_leaks=false \ + AFL_USE_FASAN=1 \ + $(TEST_BIN) < $(TEST_DATA_FILE) + +############################# CLEAN ############################################ +clean: + rm -rf $(BUILD_DIR) + +############################# FORMAT ########################################### +format: + cd $(ROOT) && echo $(TEST_SRC) | xargs -L1 ./.custom-format.py -i + +############################# RUN ############################################# diff --git a/frida_mode/test/fasan/Makefile b/frida_mode/test/fasan/Makefile new file mode 100644 index 00000000..a7bf44c7 --- /dev/null +++ b/frida_mode/test/fasan/Makefile @@ -0,0 +1,18 @@ +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +clean: + @gmake clean + +frida-noasan: + @gmake frida-noasan + +frida: + @gmake frida + +debug: + @gmake debug + +run: + @gmake run \ No newline at end of file diff --git a/frida_mode/test/fasan/test.c b/frida_mode/test/fasan/test.c new file mode 100644 index 00000000..a7d03017 --- /dev/null +++ b/frida_mode/test/fasan/test.c @@ -0,0 +1,85 @@ +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#define LOG(x) \ + do { \ + \ + char buf[] = x; \ + write(STDOUT_FILENO, buf, sizeof(buf)); \ + \ + } while (false); + +void test(char data) { + + char *buf = malloc(10); + + if (buf == NULL) return; + + switch (data) { + + /* Underflow */ + case 'U': + LOG("Underflow\n"); + buf[-1] = '\0'; + free(buf); + break; + /* Overflow */ + case 'O': + LOG("Overflow\n"); + buf[10] = '\0'; + free(buf); + break; + /* Double free */ + case 'D': + LOG("Double free\n"); + free(buf); + free(buf); + break; + /* Use after free */ + case 'A': + LOG("Use after free\n"); + free(buf); + buf[0] = '\0'; + break; + /* Test Limits (OK) */ + case 'T': + LOG("Test-Limits - No Error\n"); + buf[0] = 'A'; + buf[9] = 'I'; + free(buf); + break; + case 'M': + LOG("Memset too many\n"); + memset(buf, '\0', 11); + free(buf); + break; + default: + LOG("Nop - No Error\n"); + break; + + } + +} + +int main(int argc, char **argv) { + + char input = '\0'; + + if (read(STDIN_FILENO, &input, 1) < 0) { + + LOG("Failed to read stdin\n"); + return 1; + + } + + test(input); + + LOG("DONE\n"); + return 0; + +} + diff --git a/include/envs.h b/include/envs.h index 9175005e..4fff1e3a 100644 --- a/include/envs.h +++ b/include/envs.h @@ -191,6 +191,7 @@ static char *afl_environment_variables[] = { "AFL_WINE_PATH", "AFL_NO_SNAPSHOT", "AFL_EXPAND_HAVOC_NOW", + "AFL_USE_FASAN", "AFL_USE_QASAN", NULL diff --git a/include/forkserver.h b/include/forkserver.h index 48db94c7..2baa6f0a 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -79,6 +79,8 @@ typedef struct afl_forkserver { bool frida_mode; /* if running in frida mode or not */ + bool frida_asan; /* if running with asan in frida mode */ + bool use_stdin; /* use stdin for sending data */ bool no_unlink; /* do not unlink cur_input */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a4599b4a..903068b2 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -328,6 +328,50 @@ static int stricmp(char const *a, char const *b) { } +static void fasan_check_afl_preload(char *afl_preload) { + + char first_preload[PATH_MAX + 1] = {0}; + char * separator = strchr(afl_preload, ':'); + size_t first_preload_len = PATH_MAX; + char * basename; + char clang_runtime_prefix[] = "libclang_rt.asan-"; + + if (separator != NULL && (separator - afl_preload) < PATH_MAX) { + + first_preload_len = separator - afl_preload; + + } + + strncpy(first_preload, afl_preload, first_preload_len); + + basename = strrchr(first_preload, '/'); + if (basename == NULL) { + + basename = first_preload; + + } else { + + basename = basename + 1; + + } + + if (strncmp(basename, clang_runtime_prefix, + sizeof(clang_runtime_prefix) - 1) != 0) { + + FATAL("Address Sanitizer DSO must be the first DSO in AFL_PRELOAD"); + + } + + if (access(first_preload, R_OK) != 0) { + + FATAL("Address Sanitizer DSO not found"); + + } + + OKF("Found ASAN DSO: %s", first_preload); + +} + /* Main entry point */ int main(int argc, char **argv_orig, char **envp) { @@ -785,6 +829,7 @@ int main(int argc, char **argv_orig, char **envp) { } afl->fsrv.frida_mode = 1; + if (get_afl_env("AFL_USE_FASAN")) { afl->fsrv.frida_asan = 1; } break; @@ -1365,18 +1410,21 @@ int main(int argc, char **argv_orig, char **envp) { } else if (afl->fsrv.frida_mode) { afl_preload = getenv("AFL_PRELOAD"); - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - OKF("Injecting %s ...", frida_binary); - if (afl_preload) { - frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + if (afl->fsrv.frida_asan) { - } else { + OKF("Using Frida Address Sanitizer Mode"); + + fasan_check_afl_preload(afl_preload); - frida_afl_preload = alloc_printf("%s", frida_binary); + setenv("ASAN_OPTIONS", "detect_leaks=false", 1); } + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + ck_free(frida_binary); setenv("LD_PRELOAD", frida_afl_preload, 1); @@ -1391,11 +1439,22 @@ int main(int argc, char **argv_orig, char **envp) { } else if (afl->fsrv.frida_mode) { - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - OKF("Injecting %s ...", frida_binary); - setenv("LD_PRELOAD", frida_binary, 1); - setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); - ck_free(frida_binary); + if (afl->fsrv.frida_asan) { + + OKF("Using Frida Address Sanitizer Mode"); + FATAL( + "Address Sanitizer DSO must be loaded using AFL_PRELOAD in Frida " + "Address Sanitizer Mode"); + + } else { + + u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); + OKF("Injecting %s ...", frida_binary); + setenv("LD_PRELOAD", frida_binary, 1); + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); + ck_free(frida_binary); + + } } |