FRIDA - Remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET
MODIFY
frida_mode/README.md
frida_mode/README.md
@@ -75,7 +75,6 @@ following options are currently supported:
* `AFL_FRIDA_PERSISTENT_CNT` - See `AFL_QEMU_PERSISTENT_CNT`
* `AFL_FRIDA_PERSISTENT_HOOK` - See `AFL_QEMU_PERSISTENT_HOOK`
* `AFL_FRIDA_PERSISTENT_RET` - See `AFL_QEMU_PERSISTENT_RET`
-* `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` - See `AFL_QEMU_PERSISTENT_RETADDR_OFFSET`
To enable the powerful CMPLOG mechanism, set `-c 0` for `afl-fuzz`.
@@ -164,8 +163,7 @@ application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`)
application to the named file (supersedes the setting of `AFL_DEBUG_CHILD`)
* `AFL_FRIDA_PERSISTENT_DEBUG` - Insert a Breakpoint into the instrumented code
at `AFL_FRIDA_PERSISTENT_HOOK` and `AFL_FRIDA_PERSISTENT_RET` to allow the user
-to determine the value of `AFL_FRIDA_PERSISTENT_RETADDR_OFFSET` using a
-debugger.
+to detect issues in the persistent loop using a debugger.
```

MODIFY
frida_mode/src/persistent/persistent.c
frida_mode/src/persistent/persistent.c
@@ -13,7 +13,6 @@ afl_persistent_hook_fn hook = NULL;
guint64 persistent_start = 0;
guint64 persistent_count = 0;
guint64 persistent_ret = 0;
-guint64 persistent_ret_offset = 0;
gboolean persistent_debug = FALSE;
void persistent_init(void) {
@@ -23,8 +22,6 @@ void persistent_init(void) {
persistent_start = util_read_address("AFL_FRIDA_PERSISTENT_ADDR");
persistent_count = util_read_num("AFL_FRIDA_PERSISTENT_CNT");
persistent_ret = util_read_address("AFL_FRIDA_PERSISTENT_RET");
- persistent_ret_offset =
- util_read_address("AFL_FRIDA_PERSISTENT_RETADDR_OFFSET");
if (getenv("AFL_FRIDA_PERSISTENT_DEBUG") != NULL) { persistent_debug = TRUE; }
@@ -44,14 +41,6 @@ void persistent_init(void) {
}
- if (persistent_ret_offset != 0 && persistent_ret == 0) {
-
- FATAL(
- "AFL_FRIDA_PERSISTENT_RET must be specified if "
- "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET is");
-
- }
-
if (persistent_start != 0 && persistent_count == 0) persistent_count = 1000;
if (persistent_count != 0 && persistent_count < 100)
@@ -68,8 +57,6 @@ void persistent_init(void) {
OKF("Instrumentation - persistent ret [%c] (0x%016" G_GINT64_MODIFIER "X)",
persistent_ret == 0 ? ' ' : 'X', persistent_ret);
- OKF("Instrumentation - persistent ret offset [%c] (%" G_GINT64_MODIFIER "d)",
- persistent_ret_offset == 0 ? ' ' : 'X', persistent_ret_offset);
if (hook_name != NULL) {

MODIFY
frida_mode/src/persistent/persistent_arm64.c
frida_mode/src/persistent/persistent_arm64.c
@@ -268,13 +268,15 @@ static void instrument_persitent_restore_regs(GumArm64Writer * cw,
ARM64_REG_X0, (16 * 14),
GUM_INDEX_SIGNED_OFFSET);
- /* Don't restore RIP or RSP, use x1-x3 as clobber */
-
- /* LR & Adjusted SP (clobber x1) */
+ /* LR & Adjusted SP (use x1 as clobber) */
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X1,
ARM64_REG_X0, (16 * 15),
GUM_INDEX_SIGNED_OFFSET);
+ gum_arm64_writer_put_mov_reg_reg(cw, ARM64_REG_SP, ARM64_REG_X1);
+
+ /* Don't restore RIP use x1-x3 as clobber */
+
/* PC (x2) & CPSR (x1) */
gum_arm64_writer_put_ldp_reg_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X1,
ARM64_REG_X0, (16 * 16),
@@ -404,7 +406,6 @@ void persistent_prologue(GumStalkerOutput *output) {
gconstpointer loop = cw->code + 1;
- /* Stack must be 16-byte aligned per ABI */
instrument_persitent_save_regs(cw, &saved_regs);
/* loop: */
@@ -450,9 +451,6 @@ void persistent_epilogue(GumStalkerOutput *output) {
if (persistent_debug) { gum_arm64_writer_put_brk_imm(cw, 0); }
- gum_arm64_writer_put_add_reg_reg_imm(cw, ARM64_REG_SP, ARM64_REG_SP,
- persistent_ret_offset);
-
gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X0,
GUM_ADDRESS(&saved_lr));

MODIFY
frida_mode/src/persistent/persistent_x64.c
frida_mode/src/persistent/persistent_x64.c
@@ -43,6 +43,7 @@ struct x86_64_regs {
typedef struct x86_64_regs arch_api_regs;
static arch_api_regs saved_regs = {0};
+static gpointer saved_ret = NULL;
gboolean persistent_is_supported(void) {
@@ -104,7 +105,7 @@ static void instrument_persitent_save_regs(GumX86Writer * cw,
/* RED_ZONE + Saved flags, RAX, alignment */
gum_x86_writer_put_add_reg_imm(cw, GUM_REG_RBX,
- GUM_RED_ZONE_SIZE + (0x8 * 3));
+ GUM_RED_ZONE_SIZE + (0x8 * 2));
gum_x86_writer_put_mov_reg_offset_ptr_reg(cw, GUM_REG_RAX, (0x8 * 16),
GUM_REG_RBX);
@@ -159,7 +160,9 @@ static void instrument_persitent_restore_regs(GumX86Writer * cw,
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_R15, GUM_REG_RAX,
(0x8 * 14));
- /* Don't restore RIP or RSP */
+ /* Don't restore RIP */
+ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RSP, GUM_REG_RAX,
+ (0x8 * 16));
/* Restore RBX, RAX & Flags */
gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
@@ -242,6 +245,31 @@ static void persistent_prologue_hook(GumX86Writer * cw,
}
+static void instrument_persitent_save_ret(GumX86Writer *cw) {
+
+ /* Stack usage by this function */
+ gssize offset = GUM_RED_ZONE_SIZE + (3 * 8);
+ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+ -(GUM_RED_ZONE_SIZE));
+
+ gum_x86_writer_put_pushfx(cw);
+ gum_x86_writer_put_push_reg(cw, GUM_REG_RAX);
+ gum_x86_writer_put_push_reg(cw, GUM_REG_RBX);
+
+ gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, GUM_ADDRESS(&saved_ret));
+ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_RBX, GUM_REG_RSP,
+ offset);
+ gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_RAX, GUM_REG_RBX);
+
+ gum_x86_writer_put_pop_reg(cw, GUM_REG_RBX);
+ gum_x86_writer_put_pop_reg(cw, GUM_REG_RAX);
+ gum_x86_writer_put_popfx(cw);
+
+ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
+ (GUM_RED_ZONE_SIZE));
+
+}
+
void persistent_prologue(GumStalkerOutput *output) {
/*
@@ -268,11 +296,10 @@ void persistent_prologue(GumStalkerOutput *output) {
gconstpointer loop = cw->code + 1;
- /* Stack must be 16-byte aligned per ABI */
- instrument_persitent_save_regs(cw, &saved_regs);
+ /* Pop the return value */
+ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, 8);
- /* pop the return value */
- gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, (8));
+ instrument_persitent_save_regs(cw, &saved_regs);
/* loop: */
gum_x86_writer_put_label(cw, loop);
@@ -304,6 +331,8 @@ void persistent_prologue(GumStalkerOutput *output) {
/* original: */
gum_x86_writer_put_label(cw, original);
+ instrument_persitent_save_ret(cw);
+
if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
}
@@ -314,9 +343,15 @@ void persistent_epilogue(GumStalkerOutput *output) {
if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
- gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP,
- persistent_ret_offset);
- gum_x86_writer_put_ret(cw);
+ /* The stack should be aligned when we re-enter our loop */
+ gconstpointer zero = cw->code + 1;
+ gum_x86_writer_put_test_reg_u32(cw, GUM_REG_RSP, 0xF);
+ gum_x86_writer_put_jcc_near_label(cw, X86_INS_JE, zero, GUM_NO_HINT);
+ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_RSP, GUM_REG_RSP, -8);
+ gum_x86_writer_put_label(cw, zero);
+
+ gum_x86_writer_put_mov_reg_address(cw, GUM_REG_RAX, GUM_ADDRESS(&saved_ret));
+ gum_x86_writer_put_jmp_reg_ptr(cw, GUM_REG_RAX);
}

MODIFY
frida_mode/src/persistent/persistent_x86.c
frida_mode/src/persistent/persistent_x86.c
@@ -39,6 +39,7 @@ struct x86_regs {
typedef struct x86_regs arch_api_regs;
static arch_api_regs saved_regs = {0};
+static gpointer saved_ret = NULL;
gboolean persistent_is_supported(void) {
@@ -117,7 +118,9 @@ static void instrument_persitent_restore_regs(GumX86Writer * cw,
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBP, GUM_REG_EAX,
(0x4 * 6));
- /* Don't restore RIP or RSP */
+ /* Don't restore RIP */
+ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_ESP, GUM_REG_EAX,
+ (0x4 * 8));
/* Restore RBX, RAX & Flags */
gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_EAX,
@@ -184,6 +187,26 @@ static void persistent_prologue_hook(GumX86Writer *cw, struct x86_regs *regs) {
}
+static void instrument_persitent_save_ret(GumX86Writer *cw) {
+
+ /* Stack usage by this function */
+ gssize offset = (3 * 4);
+
+ gum_x86_writer_put_pushfx(cw);
+ gum_x86_writer_put_push_reg(cw, GUM_REG_EAX);
+ gum_x86_writer_put_push_reg(cw, GUM_REG_EBX);
+
+ gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(&saved_ret));
+ gum_x86_writer_put_mov_reg_reg_offset_ptr(cw, GUM_REG_EBX, GUM_REG_ESP,
+ offset);
+ gum_x86_writer_put_mov_reg_ptr_reg(cw, GUM_REG_EAX, GUM_REG_EBX);
+
+ gum_x86_writer_put_pop_reg(cw, GUM_REG_EBX);
+ gum_x86_writer_put_pop_reg(cw, GUM_REG_EAX);
+ gum_x86_writer_put_popfx(cw);
+
+}
+
void persistent_prologue(GumStalkerOutput *output) {
/*
@@ -210,11 +233,10 @@ void persistent_prologue(GumStalkerOutput *output) {
gconstpointer loop = cw->code + 1;
- /* Stack must be 16-byte aligned per ABI */
- instrument_persitent_save_regs(cw, &saved_regs);
-
/* Pop the return value */
- gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, (4));
+ gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP, 4);
+
+ instrument_persitent_save_regs(cw, &saved_regs);
/* loop: */
gum_x86_writer_put_label(cw, loop);
@@ -244,6 +266,8 @@ void persistent_prologue(GumStalkerOutput *output) {
/* original: */
gum_x86_writer_put_label(cw, original);
+ instrument_persitent_save_ret(cw);
+
if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
}
@@ -254,10 +278,8 @@ void persistent_epilogue(GumStalkerOutput *output) {
if (persistent_debug) { gum_x86_writer_put_breakpoint(cw); }
- gum_x86_writer_put_lea_reg_reg_offset(cw, GUM_REG_ESP, GUM_REG_ESP,
- persistent_ret_offset);
-
- gum_x86_writer_put_ret(cw);
+ gum_x86_writer_put_mov_reg_address(cw, GUM_REG_EAX, GUM_ADDRESS(&saved_ret));
+ gum_x86_writer_put_jmp_reg_ptr(cw, GUM_REG_EAX);
}

MODIFY
frida_mode/test/persistent_ret/GNUmakefile
frida_mode/test/persistent_ret/GNUmakefile
@@ -38,8 +38,6 @@ ifeq "$(ARCH)" "x86"
AFL_FRIDA_PERSISTENT_RET=$(shell $(PWD)get_symbol_addr.py -f $(TESTINSTBIN) -s slow -b 0x56555000)
endif
-AFL_FRIDA_PERSISTENT_RETADDR_OFFSET:=0x50
-
.PHONY: all 32 clean qemu frida
all: $(TESTINSTBIN)
@@ -76,7 +74,6 @@ frida: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
frida_ret: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \
- AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \
$(ROOT)afl-fuzz \
-D \
-O \
@@ -89,7 +86,6 @@ debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
gdb \
--ex 'set environment AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR)' \
--ex 'set environment AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET)' \
- --ex 'set environment AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET)' \
--ex 'set environment AFL_FRIDA_PERSISTENT_DEBUG=1' \
--ex 'set environment AFL_DEBUG_CHILD=1' \
--ex 'set environment LD_PRELOAD=$(ROOT)afl-frida-trace.so' \
@@ -99,7 +95,6 @@ debug: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
run: $(TESTINSTBIN) $(TESTINSTR_DATA_FILE)
AFL_FRIDA_PERSISTENT_ADDR=$(AFL_FRIDA_PERSISTENT_ADDR) \
AFL_FRIDA_PERSISTENT_RET=$(AFL_FRIDA_PERSISTENT_RET) \
- AFL_FRIDA_PERSISTENT_RETADDR_OFFSET=$(AFL_FRIDA_PERSISTENT_RETADDR_OFFSET) \
AFL_DEBUG_CHILD=1 \
LD_PRELOAD=$(ROOT)afl-frida-trace.so \
$(TESTINSTBIN) $(TESTINSTR_DATA_FILE)

MODIFY
include/envs.h
include/envs.h
@@ -67,7 +67,6 @@ static char *afl_environment_variables[] = {
"AFL_FRIDA_PERSISTENT_DEBUG",
"AFL_FRIDA_PERSISTENT_HOOK",
"AFL_FRIDA_PERSISTENT_RET",
- "AFL_FRIDA_PERSISTENT_RETADDR_OFFSET",
"AFL_FRIDA_STATS_FILE",
"AFL_FRIDA_STATS_INTERVAL",
"AFL_FRIDA_STATS_TRANSITIONS",

FRIDA - Remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET (#970)

Co-authored-by: Your Name <you@example.com>