mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-15 19:38:09 +00:00
FASAN Support (#918)
* FASAN Support * Fix handling of Address Sanitizer DSO * Changes to identification of Address Sanitizer DSO Co-authored-by: Your Name <you@example.com>
This commit is contained in:
committed by
GitHub
parent
9d50ae7468
commit
e40c0c2da1
13
frida_mode/include/asan.h
Normal file
13
frida_mode/include/asan.h
Normal file
@ -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
|
||||
|
11
frida_mode/include/ctx.h
Normal file
11
frida_mode/include/ctx.h
Normal file
@ -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
|
||||
|
24
frida_mode/src/asan/asan.c
Normal file
24
frida_mode/src/asan/asan.c
Normal file
@ -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");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
22
frida_mode/src/asan/asan_arm.c
Normal file
22
frida_mode/src/asan/asan_arm.c
Normal file
@ -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
|
||||
|
22
frida_mode/src/asan/asan_arm64.c
Normal file
22
frida_mode/src/asan/asan_arm64.c
Normal file
@ -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
|
||||
|
93
frida_mode/src/asan/asan_x64.c
Normal file
93
frida_mode/src/asan/asan_x64.c
Normal file
@ -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
|
||||
|
22
frida_mode/src/asan/asan_x86.c
Normal file
22
frida_mode/src/asan/asan_x86.c
Normal file
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
114
frida_mode/src/ctx/ctx_x64.c
Normal file
114
frida_mode/src/ctx/ctx_x64.c
Normal file
@ -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
|
||||
|
@ -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();
|
||||
|
||||
}
|
||||
|
156
frida_mode/test/fasan/GNUmakefile
Normal file
156
frida_mode/test/fasan/GNUmakefile
Normal file
@ -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 #############################################
|
18
frida_mode/test/fasan/Makefile
Normal file
18
frida_mode/test/fasan/Makefile
Normal file
@ -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
|
85
frida_mode/test/fasan/test.c
Normal file
85
frida_mode/test/fasan/test.c
Normal file
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
||||
|
||||
frida_afl_preload = alloc_printf("%s", frida_binary);
|
||||
fasan_check_afl_preload(afl_preload);
|
||||
|
||||
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,6 +1439,15 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
} else if (afl->fsrv.frida_mode) {
|
||||
|
||||
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);
|
||||
@ -1399,6 +1456,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (getenv("AFL_LD_PRELOAD")) {
|
||||
|
||||
FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD");
|
||||
|
Reference in New Issue
Block a user