mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-16 11:58:08 +00:00
Add global caching of block translation to instrumentation
This commit is contained in:
@ -151,25 +151,25 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
|
|||||||
* `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks
|
* `AFL_FRIDA_INST_DEBUG_FILE` - File to write raw assembly of original blocks
|
||||||
and their instrumented counterparts during block compilation.
|
and their instrumented counterparts during block compilation.
|
||||||
|
|
||||||
```
|
Creating block for 0x7ffff7953313:
|
||||||
***
|
0x7ffff7953313 mov qword ptr [rax], 0
|
||||||
|
0x7ffff795331a add rsp, 8
|
||||||
|
0x7ffff795331e ret
|
||||||
|
|
||||||
Creating block for 0x7ffff7953313:
|
Generated block 0x7ffff75e98e2
|
||||||
0x7ffff7953313 mov qword ptr [rax], 0
|
0x7ffff75e98e2 mov qword ptr [rax], 0
|
||||||
0x7ffff795331a add rsp, 8
|
0x7ffff75e98e9 add rsp, 8
|
||||||
0x7ffff795331e ret
|
0x7ffff75e98ed lea rsp, [rsp - 0x80]
|
||||||
|
0x7ffff75e98f5 push rcx
|
||||||
|
0x7ffff75e98f6 movabs rcx, 0x7ffff795331e
|
||||||
|
0x7ffff75e9900 jmp 0x7ffff75e9384
|
||||||
|
|
||||||
Generated block 0x7ffff75e98e2
|
|
||||||
0x7ffff75e98e2 mov qword ptr [rax], 0
|
|
||||||
0x7ffff75e98e9 add rsp, 8
|
|
||||||
0x7ffff75e98ed lea rsp, [rsp - 0x80]
|
|
||||||
0x7ffff75e98f5 push rcx
|
|
||||||
0x7ffff75e98f6 movabs rcx, 0x7ffff795331e
|
|
||||||
0x7ffff75e9900 jmp 0x7ffff75e9384
|
|
||||||
|
|
||||||
***
|
***
|
||||||
```
|
```
|
||||||
|
* `AFL_FRIDA_INST_CACHE_SIZE` - Set the size of the instrumentation cache used
|
||||||
|
as a look-up table to cache real to instrumented address block translations.
|
||||||
|
Default is 256Mb.
|
||||||
* `AFL_FRIDA_INST_INSN` - Generate instrumentation for conditional
|
* `AFL_FRIDA_INST_INSN` - Generate instrumentation for conditional
|
||||||
instructions (e.g. `CMOV` instructions on x64).
|
instructions (e.g. `CMOV` instructions on x64).
|
||||||
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
|
* `AFL_FRIDA_INST_JIT` - Enable the instrumentation of Just-In-Time compiled
|
||||||
@ -178,6 +178,8 @@ instances run CMPLOG mode and instrumentation of the binary is less frequent
|
|||||||
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
|
* `AFL_FRIDA_INST_NO_OPTIMIZE` - Don't use optimized inline assembly coverage
|
||||||
instrumentation (the default where available). Required to use
|
instrumentation (the default where available). Required to use
|
||||||
`AFL_FRIDA_INST_TRACE`.
|
`AFL_FRIDA_INST_TRACE`.
|
||||||
|
* `AFL_FRIDA_INST_NO_CACHE` - Don't use a look-up table to cache real to
|
||||||
|
instrumented address block translations.
|
||||||
* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default, the child will
|
* `AFL_FRIDA_INST_NO_PREFETCH` - Disable prefetching. By default, the child will
|
||||||
report instrumented blocks back to the parent so that it can also instrument
|
report instrumented blocks back to the parent so that it can also instrument
|
||||||
them and they be inherited by the next child on fork, implies
|
them and they be inherited by the next child on fork, implies
|
||||||
|
@ -9,8 +9,10 @@
|
|||||||
js_api_done;
|
js_api_done;
|
||||||
js_api_error;
|
js_api_error;
|
||||||
js_api_set_backpatch_disable;
|
js_api_set_backpatch_disable;
|
||||||
|
js_api_set_cache_disable;
|
||||||
js_api_set_debug_maps;
|
js_api_set_debug_maps;
|
||||||
js_api_set_entrypoint;
|
js_api_set_entrypoint;
|
||||||
|
js_api_set_instrument_cache_size;
|
||||||
js_api_set_instrument_coverage_file;
|
js_api_set_instrument_coverage_file;
|
||||||
js_api_set_instrument_debug_file;
|
js_api_set_instrument_debug_file;
|
||||||
js_api_set_instrument_jit;
|
js_api_set_instrument_jit;
|
||||||
|
@ -22,6 +22,9 @@ extern uint32_t __afl_map_size;
|
|||||||
|
|
||||||
extern __thread guint64 *instrument_previous_pc_addr;
|
extern __thread guint64 *instrument_previous_pc_addr;
|
||||||
|
|
||||||
|
extern gboolean instrument_cache_enabled;
|
||||||
|
extern gsize instrument_cache_size;
|
||||||
|
|
||||||
void instrument_config(void);
|
void instrument_config(void);
|
||||||
|
|
||||||
void instrument_init(void);
|
void instrument_init(void);
|
||||||
@ -59,5 +62,10 @@ void instrument_on_fork(void);
|
|||||||
|
|
||||||
guint64 instrument_get_offset_hash(GumAddress current_rip);
|
guint64 instrument_get_offset_hash(GumAddress current_rip);
|
||||||
|
|
||||||
|
void instrument_cache_config(void);
|
||||||
|
void instrument_cache_init(void);
|
||||||
|
void instrument_cache_insert(gpointer real_address, gpointer code_address);
|
||||||
|
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -5,6 +5,14 @@
|
|||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
#ifndef MAP_FIXED_NOREPLACE
|
||||||
|
#ifdef MAP_EXCL
|
||||||
|
#define MAP_FIXED_NOREPLACE MAP_EXCL | MAP_FIXED
|
||||||
|
#else
|
||||||
|
#define MAP_FIXED_NOREPLACE MAP_FIXED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#define UNUSED_PARAMETER(x) (void)(x)
|
#define UNUSED_PARAMETER(x) (void)(x)
|
||||||
#define IGNORED_RETURN(x) (void)!(x)
|
#define IGNORED_RETURN(x) (void)!(x)
|
||||||
|
|
||||||
|
@ -249,6 +249,8 @@ static void instrument_basic_block(GumStalkerIterator *iterator,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instrument_cache(instr, output);
|
||||||
|
|
||||||
if (js_stalker_callback(instr, begin, excluded, output)) {
|
if (js_stalker_callback(instr, begin, excluded, output)) {
|
||||||
|
|
||||||
gum_stalker_iterator_keep(iterator);
|
gum_stalker_iterator_keep(iterator);
|
||||||
@ -282,6 +284,7 @@ void instrument_config(void) {
|
|||||||
instrument_coverage_config();
|
instrument_coverage_config();
|
||||||
asan_config();
|
asan_config();
|
||||||
cmplog_config();
|
cmplog_config();
|
||||||
|
instrument_cache_config();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,6 +395,7 @@ void instrument_init(void) {
|
|||||||
instrument_coverage_init();
|
instrument_coverage_init();
|
||||||
instrument_coverage_optimize_init();
|
instrument_coverage_optimize_init();
|
||||||
instrument_debug_init();
|
instrument_debug_init();
|
||||||
|
instrument_cache_init();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
|
|
||||||
|
gboolean instrument_cache_enabled = FALSE;
|
||||||
|
gsize instrument_cache_size = 0;
|
||||||
|
|
||||||
gboolean instrument_is_coverage_optimize_supported(void) {
|
gboolean instrument_is_coverage_optimize_supported(void) {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -55,5 +58,27 @@ gpointer instrument_cur(GumStalkerOutput *output) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void instrument_cache_config(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_init(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(real_address);
|
||||||
|
UNUSED_PARAMETER(code_address);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(instr);
|
||||||
|
UNUSED_PARAMETER(output);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -379,5 +379,27 @@ gpointer instrument_cur(GumStalkerOutput *output) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void instrument_cache_config(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_init(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(real_address);
|
||||||
|
UNUSED_PARAMETER(code_address);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(instr);
|
||||||
|
UNUSED_PARAMETER(output);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -202,10 +202,17 @@ static void instrument_coverage_switch(GumStalkerObserver *self,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op[0].type != X86_OP_IMM) { return; }
|
if (op[0].type != X86_OP_IMM) {
|
||||||
|
|
||||||
|
instrument_cache_insert(start_address, *target);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case X86_INS_RET:
|
case X86_INS_RET:
|
||||||
|
instrument_cache_insert(start_address,
|
||||||
|
(guint8 *)*target + sizeof(afl_log_code));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
435
frida_mode/src/instrument/instrument_x64_cache.c
Normal file
435
frida_mode/src/instrument/instrument_x64_cache.c
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
#include "instrument.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
|
||||||
|
#define INVALID 1
|
||||||
|
#define DEFAULT_CACHE_SIZE (256ULL << 20)
|
||||||
|
|
||||||
|
gboolean instrument_cache_enabled = TRUE;
|
||||||
|
gsize instrument_cache_size = DEFAULT_CACHE_SIZE;
|
||||||
|
static gpointer *map_base = MAP_FAILED;
|
||||||
|
|
||||||
|
void instrument_cache_config(void) {
|
||||||
|
|
||||||
|
instrument_cache_enabled = (getenv("AFL_FRIDA_INST_NO_CACHE") == NULL);
|
||||||
|
|
||||||
|
if (getenv("AFL_FRIDA_INST_CACHE_SIZE") != NULL) {
|
||||||
|
|
||||||
|
if (!instrument_cache_enabled) {
|
||||||
|
|
||||||
|
FFATAL(
|
||||||
|
"AFL_FRIDA_INST_CACHE_SIZE incomatible with "
|
||||||
|
"AFL_FRIDA_INST_NO_CACHE");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
instrument_cache_size =
|
||||||
|
util_read_address("AFL_FRIDA_INST_CACHE_SIZE", DEFAULT_CACHE_SIZE);
|
||||||
|
util_log2(instrument_cache_size);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_init(void) {
|
||||||
|
|
||||||
|
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache:" cYEL " [%c]",
|
||||||
|
instrument_cache_enabled ? 'X' : ' ');
|
||||||
|
if (!instrument_cache_enabled) { return; }
|
||||||
|
|
||||||
|
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache size:" cYEL " [0x%016lX]",
|
||||||
|
instrument_cache_size);
|
||||||
|
|
||||||
|
const struct rlimit data_limit = {.rlim_cur = RLIM_INFINITY,
|
||||||
|
.rlim_max = RLIM_INFINITY};
|
||||||
|
|
||||||
|
if (setrlimit(RLIMIT_AS, &data_limit) != 0) {
|
||||||
|
|
||||||
|
FFATAL("Failed to setrlimit: %d", errno);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
map_base =
|
||||||
|
gum_memory_allocate(NULL, instrument_cache_size, instrument_cache_size,
|
||||||
|
GUM_PAGE_READ | GUM_PAGE_WRITE);
|
||||||
|
if (map_base == MAP_FAILED) { FFATAL("Failed to map segment: %d", errno); }
|
||||||
|
|
||||||
|
FOKF(cBLU "Instrumentation" cRST " - " cGRN "cache addr:" cYEL " [0x%016lX]",
|
||||||
|
GUM_ADDRESS(map_base));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer *instrument_cache_get_addr(gpointer addr) {
|
||||||
|
|
||||||
|
gsize mask = (instrument_cache_size / sizeof(gpointer)) - 1;
|
||||||
|
return &map_base[GPOINTER_TO_SIZE(addr) & mask];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
|
||||||
|
|
||||||
|
if (!instrument_cache_enabled) { return; }
|
||||||
|
|
||||||
|
gpointer *target = instrument_cache_get_addr(real_address);
|
||||||
|
if (*target == code_address) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if (*target == NULL) {
|
||||||
|
|
||||||
|
*target = code_address;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
*target = GSIZE_TO_POINTER(INVALID);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean instrument_cache_relocate(GumAddress old_pc, GumAddress new_pc,
|
||||||
|
gint32 old_offset,
|
||||||
|
gint32 *new_offset) {
|
||||||
|
|
||||||
|
guint64 old_target = old_pc + old_offset;
|
||||||
|
gint64 relocated = old_target - new_pc;
|
||||||
|
|
||||||
|
if (relocated > G_MAXINT32 || relocated < G_MININT32) { return FALSE; }
|
||||||
|
|
||||||
|
*new_offset = relocated;
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instrument_cache_rewrite_branch_insn(const cs_insn * instr,
|
||||||
|
GumStalkerOutput *output) {
|
||||||
|
|
||||||
|
GumX86Writer *cw = output->writer.x86;
|
||||||
|
cs_x86 * x86 = &instr->detail->x86;
|
||||||
|
guint8 modified[sizeof(instr->bytes)] = {0};
|
||||||
|
guint8 offset = 0;
|
||||||
|
guint8 skip = 0;
|
||||||
|
|
||||||
|
g_assert(sizeof(x86->prefix) == 4);
|
||||||
|
g_assert(sizeof(x86->opcode) == 4);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the target is simply RAX, we can skip writing the code to load the
|
||||||
|
* RIP
|
||||||
|
*/
|
||||||
|
if (x86->operands[0].type == X86_OP_REG ||
|
||||||
|
x86->operands[0].reg == X86_REG_RAX) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the prefix */
|
||||||
|
for (gsize i = 0; i < sizeof(x86->prefix); i++) {
|
||||||
|
|
||||||
|
if (x86->prefix[i] != 0) {
|
||||||
|
|
||||||
|
if (x86->prefix[i] == 0xf2) {
|
||||||
|
|
||||||
|
skip++;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
modified[offset++] = x86->prefix[i];
|
||||||
|
skip++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the REX */
|
||||||
|
if (x86->rex == 0) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CALL (near) and JMP (near) default to 64-bit operands, MOV does not,
|
||||||
|
* write REX.W
|
||||||
|
*/
|
||||||
|
modified[offset++] = 0x48;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if ((x86->rex & 0xF8) != 0x40) {
|
||||||
|
|
||||||
|
FATAL("Unexpected REX byte: 0x%02x", x86->rex);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
modified[offset++] = x86->rex | 0x08;
|
||||||
|
skip++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CALL is FF /2, JMP is FF /4. The remaining op-code fields should thus be
|
||||||
|
* unused
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (x86->opcode[0] != 0xFF || x86->opcode[1] != 0x00 ||
|
||||||
|
x86->opcode[2] != 0x00 || x86->opcode[3] != 0x00) {
|
||||||
|
|
||||||
|
FFATAL("Unexpected Op-code: 0x%02x 0x%02x 0x%02x 0x%02x", x86->opcode[0],
|
||||||
|
x86->opcode[1], x86->opcode[2], x86->opcode[3]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The reg field of the ModRM should be set to 2 for CALL and 4 for JMP */
|
||||||
|
guint8 reg = (x86->modrm >> 3) & 7;
|
||||||
|
if (reg != 0x4 && reg != 0x2) {
|
||||||
|
|
||||||
|
FFATAL("Unexpected Reg: 0x%02x, ModRM: 0x%02x", reg, x86->modrm);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MOV */
|
||||||
|
modified[offset++] = 0x8b;
|
||||||
|
skip++;
|
||||||
|
|
||||||
|
/* Clear the reg field (RAX) */
|
||||||
|
modified[offset++] = x86->modrm & 0xc7;
|
||||||
|
skip++;
|
||||||
|
|
||||||
|
/* Operands */
|
||||||
|
guint8 op_len = instr->size - skip;
|
||||||
|
|
||||||
|
/* If our branch was RIP relative, we'll need to fix-up the offset */
|
||||||
|
if (x86->operands[0].type == X86_OP_MEM &&
|
||||||
|
x86->operands[0].mem.base == X86_REG_RIP) {
|
||||||
|
|
||||||
|
/* RIP relative offsets should be 32-bits */
|
||||||
|
if (op_len != sizeof(gint32)) {
|
||||||
|
|
||||||
|
FFATAL("Unexpected operand length: %d\n", op_len);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
gint32 old_offset = *(gint32 *)&instr->bytes[skip];
|
||||||
|
gint32 new_offset = 0;
|
||||||
|
if (instrument_cache_relocate(instr->address, cw->pc, old_offset,
|
||||||
|
&new_offset)) {
|
||||||
|
|
||||||
|
gint32 *output = (gint32 *)&modified[offset];
|
||||||
|
*output = new_offset;
|
||||||
|
offset += sizeof(gint32);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
GumAddress target = instr->address + old_offset;
|
||||||
|
gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, target);
|
||||||
|
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_RAX, GUM_REG_RAX);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
for (int i = 0; i < op_len; i++) {
|
||||||
|
|
||||||
|
guint8 val = instr->bytes[i + skip];
|
||||||
|
modified[offset++] = val;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
gum_x86_writer_put_bytes(cw, modified, offset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instrument_cache_write_push_frame(GumX86Writer *cw) {
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||||
|
cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))),
|
||||||
|
GUM_REG_XAX);
|
||||||
|
gum_x86_writer_put_lahf(cw);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||||
|
cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (2 * sizeof(gpointer))),
|
||||||
|
GUM_REG_XAX);
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||||
|
cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (3 * sizeof(gpointer))),
|
||||||
|
GUM_REG_XBX);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instrument_cache_write_pop_frame(GumX86Writer *cw) {
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(
|
||||||
|
cw, GUM_REG_XBX, GUM_REG_XSP,
|
||||||
|
-(GUM_RED_ZONE_SIZE + (3 * sizeof(gpointer))));
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(
|
||||||
|
cw, GUM_REG_XAX, GUM_REG_XSP,
|
||||||
|
-(GUM_RED_ZONE_SIZE + (2 * sizeof(gpointer))));
|
||||||
|
gum_x86_writer_put_sahf(cw);
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(
|
||||||
|
cw, GUM_REG_XAX, GUM_REG_XSP,
|
||||||
|
-(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instrument_cache_write_lookup(GumX86Writer *cw) {
|
||||||
|
|
||||||
|
/* &map_base[GPOINTER_TO_SIZE(addr) & MAP_MASK]; */
|
||||||
|
|
||||||
|
gsize mask = (instrument_cache_size / sizeof(gpointer)) - 1;
|
||||||
|
gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_XBX, mask);
|
||||||
|
gum_x86_writer_put_and_reg_reg(cw, GUM_REG_XAX, GUM_REG_XBX);
|
||||||
|
gum_x86_writer_put_shl_reg_u8(cw, GUM_REG_XAX, util_log2(sizeof(gpointer)));
|
||||||
|
gum_x86_writer_put_mov_reg_u64(cw, GUM_REG_XBX, GPOINTER_TO_SIZE(map_base));
|
||||||
|
gum_x86_writer_put_add_reg_reg(cw, GUM_REG_XAX, GUM_REG_XBX);
|
||||||
|
|
||||||
|
/* Read the return address lookup */
|
||||||
|
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_XAX, GUM_REG_XAX);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_jmp_call(const cs_insn *instr, GumStalkerOutput *output) {
|
||||||
|
|
||||||
|
GumX86Writer *cw = output->writer.x86;
|
||||||
|
cs_x86 * x86 = &instr->detail->x86;
|
||||||
|
|
||||||
|
if (x86->op_count != 1) { FFATAL("Unexpected operand count"); }
|
||||||
|
|
||||||
|
if (x86->operands[0].type == X86_OP_IMM) { return; }
|
||||||
|
|
||||||
|
gconstpointer null = cw->code;
|
||||||
|
|
||||||
|
instrument_cache_write_push_frame(cw);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are about to re-write the CALL or JMP instruction, but replace the
|
||||||
|
* op-code with that for a MOV into RAX. Since we are keeping the operand from
|
||||||
|
* the JMP exactly the same, it is imperative that the target register state
|
||||||
|
* be exactly the same as how the target left it. Since `LAHF` spoils `RAX` we
|
||||||
|
* must restore it from the stack. We also must avoid adjusting `RSP`, so we
|
||||||
|
* use `MOV` instructions to store our context into the stack beyond the
|
||||||
|
* red-zone.
|
||||||
|
*/
|
||||||
|
gum_x86_writer_put_mov_reg_reg_offset_ptr(
|
||||||
|
cw, GUM_REG_XAX, GUM_REG_XSP,
|
||||||
|
-(GUM_RED_ZONE_SIZE + (1 * sizeof(gpointer))));
|
||||||
|
|
||||||
|
instrument_cache_rewrite_branch_insn(instr, output);
|
||||||
|
|
||||||
|
instrument_cache_write_lookup(cw);
|
||||||
|
|
||||||
|
/* Test if its set*/
|
||||||
|
gum_x86_writer_put_cmp_reg_i32(cw, GUM_REG_XAX, INVALID);
|
||||||
|
gum_x86_writer_put_jcc_short_label(cw, X86_INS_JLE, null, GUM_UNLIKELY);
|
||||||
|
|
||||||
|
/* If it's set, then stash the address beyond the red-zone */
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(
|
||||||
|
cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (4 * sizeof(gpointer))),
|
||||||
|
GUM_REG_XAX);
|
||||||
|
|
||||||
|
if (instr->id == X86_INS_JMP) {
|
||||||
|
|
||||||
|
instrument_cache_write_pop_frame(cw);
|
||||||
|
gum_x86_writer_put_jmp_reg_offset_ptr(
|
||||||
|
cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + (4 * sizeof(gpointer))));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_address(
|
||||||
|
cw, GUM_REG_XAX, GUM_ADDRESS(instr->address + instr->size));
|
||||||
|
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_XSP,
|
||||||
|
-sizeof(gpointer), GUM_REG_XAX);
|
||||||
|
|
||||||
|
instrument_cache_write_pop_frame(cw);
|
||||||
|
|
||||||
|
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_XSP, GUM_REG_XSP,
|
||||||
|
-sizeof(gpointer));
|
||||||
|
gum_x86_writer_put_jmp_reg_offset_ptr(
|
||||||
|
cw, GUM_REG_XSP, -(GUM_RED_ZONE_SIZE + ((4 - 1) * sizeof(gpointer))));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tidy up our mess and let FRIDA handle it */
|
||||||
|
gum_x86_writer_put_label(cw, null);
|
||||||
|
instrument_cache_write_pop_frame(cw);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_ret(const cs_insn *instr, GumStalkerOutput *output) {
|
||||||
|
|
||||||
|
GumX86Writer *cw = output->writer.x86;
|
||||||
|
cs_x86 * x86 = &instr->detail->x86;
|
||||||
|
guint16 n = 0;
|
||||||
|
|
||||||
|
if (x86->op_count != 0) {
|
||||||
|
|
||||||
|
if (x86->operands[0].type != X86_OP_IMM) {
|
||||||
|
|
||||||
|
FFATAL("Unexpected operand type");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
n = x86->operands[0].imm;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
gconstpointer null = cw->code;
|
||||||
|
|
||||||
|
instrument_cache_write_push_frame(cw);
|
||||||
|
|
||||||
|
gum_x86_writer_put_mov_reg_reg_ptr(cw, GUM_REG_XAX, GUM_REG_XSP);
|
||||||
|
|
||||||
|
instrument_cache_write_lookup(cw);
|
||||||
|
|
||||||
|
/* Test if its set*/
|
||||||
|
gum_x86_writer_put_cmp_reg_i32(cw, GUM_REG_XAX, INVALID);
|
||||||
|
gum_x86_writer_put_jcc_short_label(cw, X86_INS_JLE, null, GUM_UNLIKELY);
|
||||||
|
|
||||||
|
/* If it's set, then overwrite our return address and return */
|
||||||
|
gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_XSP, GUM_REG_XAX);
|
||||||
|
instrument_cache_write_pop_frame(cw);
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
|
||||||
|
gum_x86_writer_put_ret(cw);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
gum_x86_writer_put_ret_imm(cw, n);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tidy up our mess and let FRIDA handle it */
|
||||||
|
gum_x86_writer_put_label(cw, null);
|
||||||
|
instrument_cache_write_pop_frame(cw);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
|
||||||
|
|
||||||
|
if (!instrument_cache_enabled) { return; }
|
||||||
|
|
||||||
|
switch (instr->id) {
|
||||||
|
|
||||||
|
case X86_INS_RET:
|
||||||
|
instrument_cache_ret(instr, output);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case X86_INS_CALL:
|
||||||
|
case X86_INS_JMP:
|
||||||
|
instrument_cache_jmp_call(instr, output);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
|
|
||||||
|
gboolean instrument_cache_enabled = FALSE;
|
||||||
|
gsize instrument_cache_size = 0;
|
||||||
|
|
||||||
static GHashTable *coverage_blocks = NULL;
|
static GHashTable *coverage_blocks = NULL;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
@ -242,5 +245,27 @@ gpointer instrument_cur(GumStalkerOutput *output) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void instrument_cache_config(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_init(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache_insert(gpointer real_address, gpointer code_address) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(real_address);
|
||||||
|
UNUSED_PARAMETER(code_address);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void instrument_cache(const cs_insn *instr, GumStalkerOutput *output) {
|
||||||
|
|
||||||
|
UNUSED_PARAMETER(instr);
|
||||||
|
UNUSED_PARAMETER(output);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -68,6 +68,12 @@ class Afl {
|
|||||||
static setBackpatchDisable() {
|
static setBackpatchDisable() {
|
||||||
Afl.jsApiSetBackpatchDisable();
|
Afl.jsApiSetBackpatchDisable();
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* See `AFL_FRIDA_INST_NO_CACHE`.
|
||||||
|
*/
|
||||||
|
static setCacheDisable() {
|
||||||
|
Afl.jsApiSetCacheDisable();
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* See `AFL_FRIDA_DEBUG_MAPS`.
|
* See `AFL_FRIDA_DEBUG_MAPS`.
|
||||||
*/
|
*/
|
||||||
@ -91,6 +97,13 @@ class Afl {
|
|||||||
static setInMemoryFuzzing() {
|
static setInMemoryFuzzing() {
|
||||||
Afl.jsApiAflSharedMemFuzzing.writeInt(1);
|
Afl.jsApiAflSharedMemFuzzing.writeInt(1);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* See `AFL_FRIDA_INST_CACHE_SIZE`. This function takes a single `number`
|
||||||
|
* as an argument.
|
||||||
|
*/
|
||||||
|
static setInstrumentCacheSize(size) {
|
||||||
|
Afl.jsApiSetInstrumentCacheSize(size);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
|
* See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
|
||||||
* as an argument.
|
* as an argument.
|
||||||
@ -299,8 +312,10 @@ Afl.jsApiAflSharedMemFuzzing = Afl.jsApiGetSymbol("__afl_sharedmem_fuzzing");
|
|||||||
Afl.jsApiDone = Afl.jsApiGetFunction("js_api_done", "void", []);
|
Afl.jsApiDone = Afl.jsApiGetFunction("js_api_done", "void", []);
|
||||||
Afl.jsApiError = Afl.jsApiGetFunction("js_api_error", "void", ["pointer"]);
|
Afl.jsApiError = Afl.jsApiGetFunction("js_api_error", "void", ["pointer"]);
|
||||||
Afl.jsApiSetBackpatchDisable = Afl.jsApiGetFunction("js_api_set_backpatch_disable", "void", []);
|
Afl.jsApiSetBackpatchDisable = Afl.jsApiGetFunction("js_api_set_backpatch_disable", "void", []);
|
||||||
|
Afl.jsApiSetCacheDisable = Afl.jsApiGetFunction("js_api_set_cache_disable", "void", []);
|
||||||
Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []);
|
Afl.jsApiSetDebugMaps = Afl.jsApiGetFunction("js_api_set_debug_maps", "void", []);
|
||||||
Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
|
Afl.jsApiSetEntryPoint = Afl.jsApiGetFunction("js_api_set_entrypoint", "void", ["pointer"]);
|
||||||
|
Afl.jsApiSetInstrumentCacheSize = Afl.jsApiGetFunction("js_api_set_instrument_cache_size", "void", ["size_t"]);
|
||||||
Afl.jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction("js_api_set_instrument_coverage_file", "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.jsApiSetInstrumentDebugFile = Afl.jsApiGetFunction("js_api_set_instrument_debug_file", "void", ["pointer"]);
|
||||||
Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []);
|
Afl.jsApiSetInstrumentInstructions = Afl.jsApiGetFunction("js_api_set_instrument_instructions", "void", []);
|
||||||
|
@ -262,6 +262,19 @@ __attribute__((visibility("default"))) void js_api_set_stalker_adjacent_blocks(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((visibility("default"))) void js_api_set_cache_disable(void) {
|
||||||
|
|
||||||
|
instrument_cache_enabled = FALSE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((visibility("default"))) void js_api_set_instrument_cache_size(
|
||||||
|
gsize size) {
|
||||||
|
|
||||||
|
instrument_cache_size = size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__((visibility("default"))) void js_api_set_js_main_hook(
|
__attribute__((visibility("default"))) void js_api_set_js_main_hook(
|
||||||
const js_main_hook_t hook) {
|
const js_main_hook_t hook) {
|
||||||
|
|
||||||
|
97
frida_mode/test/cache/GNUmakefile
vendored
Normal file
97
frida_mode/test/cache/GNUmakefile
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
PWD:=$(shell pwd)/
|
||||||
|
ROOT:=$(PWD)../../../
|
||||||
|
BUILD_DIR:=$(PWD)build/
|
||||||
|
|
||||||
|
TEST_CACHE_SRC:=$(PWD)cache.c
|
||||||
|
TEST_CACHE_OBJ:=$(BUILD_DIR)cache
|
||||||
|
|
||||||
|
TEST_DATA_DIR:=$(BUILD_DIR)in/
|
||||||
|
CACHE_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_CACHE_OBJ) LLVMFuzzerTestOneInput $(AFL_FRIDA_BASE_ADDR))
|
||||||
|
|
||||||
|
DUMMY_DATA_FILE:=$(BUILD_DIR)dummy.dat
|
||||||
|
|
||||||
|
.PHONY: all 32 clean frida frida_noinst debug format
|
||||||
|
|
||||||
|
all: $(TEST_CACHE_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 $@
|
||||||
|
|
||||||
|
$(CACHE_INPUT): | $(TEST_DATA_DIR)
|
||||||
|
echo -n "ABC" > $@
|
||||||
|
|
||||||
|
$(TEST_CACHE_OBJ): $(TEST_CACHE_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_CACHE_OBJ) $(CACHE_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_CACHE_OBJ) $(DUMMY_DATA_FILE)
|
||||||
|
|
||||||
|
frida_nocache: $(TEST_CACHE_OBJ) $(CACHE_INPUT) $(DUMMY_DATA_FILE)
|
||||||
|
AFL_FRIDA_INST_NO_CACHE=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 \
|
||||||
|
-- \
|
||||||
|
$(TEST_CACHE_OBJ) $(DUMMY_DATA_FILE)
|
||||||
|
|
||||||
|
debug: $(TEST_CACHE_OBJ) $(CACHE_INPUT)
|
||||||
|
gdb \
|
||||||
|
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
|
||||||
|
--ex 'set disassembly-flavor intel' \
|
||||||
|
--ex 'r $(CACHE_INPUT)' \
|
||||||
|
--args $(TEST_CACHE_OBJ) $(CACHE_INPUT)
|
||||||
|
|
||||||
|
show: $(TEST_CACHE_OBJ) $(CACHE_INPUT)
|
||||||
|
gdb \
|
||||||
|
--ex "set disassembly-flavor intel" \
|
||||||
|
--ex "set confirm off" \
|
||||||
|
--ex "symbol-file $(TEST_CACHE_OBJ)" \
|
||||||
|
--ex "x/50i LLVMFuzzerTestOneInput" \
|
||||||
|
--ex "r" \
|
||||||
|
--args $(TEST_CACHE_OBJ) $(CACHE_INPUT)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILD_DIR)
|
||||||
|
|
||||||
|
format:
|
||||||
|
cd $(ROOT) && echo $(TEST_CACHE_SRC) | xargs -L1 ./.custom-format.py -i
|
22
frida_mode/test/cache/Makefile
vendored
Normal file
22
frida_mode/test/cache/Makefile
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
frida:
|
||||||
|
@gmake frida
|
||||||
|
|
||||||
|
frida_nocache:
|
||||||
|
@gmake frida_nocache
|
||||||
|
|
||||||
|
debug:
|
||||||
|
@gmake debug
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@gmake clean
|
||||||
|
|
||||||
|
format:
|
||||||
|
@gmake format
|
115
frida_mode/test/cache/cache.c
vendored
Normal file
115
frida_mode/test/cache/cache.c
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void LLVMFuzzerTestOneInput(char *buf, int len);
|
||||||
|
|
||||||
|
__asm__ (
|
||||||
|
"LLVMFuzzerTestOneInput:\n"
|
||||||
|
".func LLVMFuzzerTestOneInput\n"
|
||||||
|
".global LLVMFuzzerTestOneInput\n"
|
||||||
|
" jmpq *jmp_offset(%rip)\n"
|
||||||
|
" nop\n"
|
||||||
|
" nop\n"
|
||||||
|
"call_target:\n"
|
||||||
|
" ret\n"
|
||||||
|
" nop\n"
|
||||||
|
" nop\n"
|
||||||
|
"jmp_target:\n"
|
||||||
|
" callq *call_offset(%rip)\n"
|
||||||
|
" nop\n"
|
||||||
|
" nop\n"
|
||||||
|
" leaq rax_offset(%rip), %rax\n"
|
||||||
|
" jmp (%rax)\n"
|
||||||
|
" nop\n"
|
||||||
|
" ud2\n"
|
||||||
|
" nop\n"
|
||||||
|
"rax_target:\n"
|
||||||
|
" ret\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
".global jmp_offset\n"
|
||||||
|
".p2align 3\n"
|
||||||
|
"jmp_offset:\n"
|
||||||
|
" .quad jmp_target\n"
|
||||||
|
"call_offset:\n"
|
||||||
|
" .quad call_target\n"
|
||||||
|
"rax_offset:\n"
|
||||||
|
" .quad rax_target\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -125,7 +125,7 @@ vorbis: $(VORBIS_LIB)
|
|||||||
########## HARNESS #######
|
########## HARNESS #######
|
||||||
|
|
||||||
$(DECODE_SRC):
|
$(DECODE_SRC):
|
||||||
wget -O $@ $(DECODE_URL)
|
wget -O $@ $(DECODE_URL) || curl -L -o $@ $(DECODE_URL)
|
||||||
|
|
||||||
$(DECODE_OBJ): $(DECODE_SRC)
|
$(DECODE_OBJ): $(DECODE_SRC)
|
||||||
$(CXX) -o $@ -c $< -I$(VORBIS_DIR)include/ -I$(OGG_DIR)include/
|
$(CXX) -o $@ -c $< -I$(VORBIS_DIR)include/ -I$(OGG_DIR)include/
|
||||||
@ -135,7 +135,7 @@ decode: $(DECODE_OBJ)
|
|||||||
########## HARNESS #######
|
########## HARNESS #######
|
||||||
|
|
||||||
$(HARNESS_SRC):
|
$(HARNESS_SRC):
|
||||||
wget -O $@ $(HARNESS_URL)
|
wget -O $@ $(HARNESS_URL) || curl -L -o $@ $(HARNESS_URL)
|
||||||
|
|
||||||
$(HARNESS_OBJ): $(HARNESS_SRC)
|
$(HARNESS_OBJ): $(HARNESS_SRC)
|
||||||
$(CC) -o $@ -c $<
|
$(CC) -o $@ -c $<
|
||||||
@ -165,8 +165,8 @@ $(AFLPP_DRIVER_DUMMY_INPUT): | $(BUILD_DIR)
|
|||||||
|
|
||||||
###### TEST DATA #######
|
###### TEST DATA #######
|
||||||
|
|
||||||
$(TEST_DATA_FILE): $(TEST_DATA_DIR)
|
$(TEST_DATA_FILE): | $(TEST_DATA_DIR)
|
||||||
wget -O $@ $(TEST_DATA_SRC)
|
wget -O $@ $(TEST_DATA_SRC) || curl -L -o $@ $(TEST_DATA_SRC)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILD_DIR)
|
rm -rf $(BUILD_DIR)
|
||||||
|
@ -84,6 +84,13 @@ class Afl {
|
|||||||
Afl.jsApiSetBackpatchDisable();
|
Afl.jsApiSetBackpatchDisable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `AFL_FRIDA_INST_NO_CACHE`.
|
||||||
|
*/
|
||||||
|
public static setCacheDisable(): void {
|
||||||
|
Afl.jsApiSetCacheDisable();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See `AFL_FRIDA_DEBUG_MAPS`.
|
* See `AFL_FRIDA_DEBUG_MAPS`.
|
||||||
*/
|
*/
|
||||||
@ -110,6 +117,14 @@ class Afl {
|
|||||||
Afl.jsApiAflSharedMemFuzzing.writeInt(1);
|
Afl.jsApiAflSharedMemFuzzing.writeInt(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See `AFL_FRIDA_INST_CACHE_SIZE`. This function takes a single `number`
|
||||||
|
* as an argument.
|
||||||
|
*/
|
||||||
|
public static setInstrumentCacheSize(size: number): void {
|
||||||
|
Afl.jsApiSetInstrumentCacheSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
|
* See `AFL_FRIDA_INST_COVERAGE_FILE`. This function takes a single `string`
|
||||||
* as an argument.
|
* as an argument.
|
||||||
@ -354,6 +369,11 @@ class Afl {
|
|||||||
"void",
|
"void",
|
||||||
[]);
|
[]);
|
||||||
|
|
||||||
|
private static readonly jsApiSetCacheDisable = Afl.jsApiGetFunction(
|
||||||
|
"js_api_set_cache_disable",
|
||||||
|
"void",
|
||||||
|
[]);
|
||||||
|
|
||||||
private static readonly jsApiSetDebugMaps = Afl.jsApiGetFunction(
|
private static readonly jsApiSetDebugMaps = Afl.jsApiGetFunction(
|
||||||
"js_api_set_debug_maps",
|
"js_api_set_debug_maps",
|
||||||
"void",
|
"void",
|
||||||
@ -364,6 +384,11 @@ class Afl {
|
|||||||
"void",
|
"void",
|
||||||
["pointer"]);
|
["pointer"]);
|
||||||
|
|
||||||
|
private static readonly jsApiSetInstrumentCacheSize = Afl.jsApiGetFunction(
|
||||||
|
"js_api_set_instrument_cache_size",
|
||||||
|
"void",
|
||||||
|
["size_t"]);
|
||||||
|
|
||||||
private static readonly jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction(
|
private static readonly jsApiSetInstrumentCoverageFile = Afl.jsApiGetFunction(
|
||||||
"js_api_set_instrument_coverage_file",
|
"js_api_set_instrument_coverage_file",
|
||||||
"void",
|
"void",
|
||||||
|
@ -57,10 +57,12 @@ static char *afl_environment_variables[] = {
|
|||||||
"AFL_FRIDA_DEBUG_MAPS",
|
"AFL_FRIDA_DEBUG_MAPS",
|
||||||
"AFL_FRIDA_DRIVER_NO_HOOK",
|
"AFL_FRIDA_DRIVER_NO_HOOK",
|
||||||
"AFL_FRIDA_EXCLUDE_RANGES",
|
"AFL_FRIDA_EXCLUDE_RANGES",
|
||||||
|
"AFL_FRIDA_INST_CACHE_SIZE",
|
||||||
"AFL_FRIDA_INST_COVERAGE_FILE",
|
"AFL_FRIDA_INST_COVERAGE_FILE",
|
||||||
"AFL_FRIDA_INST_DEBUG_FILE",
|
"AFL_FRIDA_INST_DEBUG_FILE",
|
||||||
"AFL_FRIDA_INST_INSN",
|
"AFL_FRIDA_INST_INSN",
|
||||||
"AFL_FRIDA_INST_JIT",
|
"AFL_FRIDA_INST_JIT",
|
||||||
|
"AFL_FRIDA_INST_NO_CACHE",
|
||||||
"AFL_FRIDA_INST_NO_OPTIMIZE",
|
"AFL_FRIDA_INST_NO_OPTIMIZE",
|
||||||
"AFL_FRIDA_INST_NO_PREFETCH",
|
"AFL_FRIDA_INST_NO_PREFETCH",
|
||||||
"AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
|
"AFL_FRIDA_INST_NO_PREFETCH_BACKPATCH",
|
||||||
|
Reference in New Issue
Block a user