Added support for ARM32 persistent mode
MODIFY
frida_mode/src/persistent/persistent_arm32.c
frida_mode/src/persistent/persistent_arm32.c
#include "frida-gumjs.h"
+#include "instrument.h"
#include "persistent.h"
#include "util.h"
#if defined(__arm__)
-struct arm_regs {
+// struct _GumArmCpuContext {
+// guint32 pc;
+// guint32 sp;
+// guint32 cpsr;
- uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10;
+// guint32 r8;
+// guint32 r9;
+// guint32 r10;
+// guint32 r11;
+// guint32 r12;
- union {
+// GumArmVectorReg v[16];
- uint32_t r11;
- uint32_t fp;
+// guint32 _padding;
- };
+// guint32 r[8];
+// guint32 lr;
+// };
- union {
+// r11 - fp
+// r12 - ip
+// r13 - sp
+// r14 - lr
+// r15 - pc
- uint32_t r12;
- uint32_t ip;
+static GumCpuContext saved_regs = {0};
+static gpointer saved_lr = NULL;
- };
+gboolean persistent_is_supported(void) {
+ return true;
+}
- union {
+static void instrument_persitent_save_regs(GumArmWriter * cw,
+ GumCpuContext *regs) {
+ /* Save Regs */
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE);
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE + sizeof(guint32));
- uint32_t r13;
- uint32_t sp;
+ gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(regs));
- };
+ /* Save r1-r7 */
+ for (size_t i = ARM_REG_R1; i < ARM_REG_R8; i++) {
+ gum_arm_writer_put_str_reg_reg_offset(
+ cw, i, ARM_REG_R0, offsetof(GumCpuContext, r[i - ARM_REG_R0]));
+ }
- union {
+ /* Save r8-r12 */
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R8, ARM_REG_R0,
+ offsetof(GumCpuContext, r8));
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R9, ARM_REG_R0,
+ offsetof(GumCpuContext, r9));
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R10, ARM_REG_R0,
+ offsetof(GumCpuContext, r10));
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R11, ARM_REG_R0,
+ offsetof(GumCpuContext, r11));
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R12, ARM_REG_R0,
+ offsetof(GumCpuContext, r12));
+
+ /* Save sp & lr */
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_SP, ARM_REG_R0,
+ offsetof(GumCpuContext, sp));
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0,
+ offsetof(GumCpuContext, lr));
+
+ /* Save r0 (load from stack into r1) */
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE);
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0,
+ offsetof(GumCpuContext, r[0]));
+
+ /* Save CPSR */
+ gum_arm_writer_put_mov_reg_cpsr(cw, ARM_REG_R1);
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0,
+ offsetof(GumCpuContext, cpsr));
+
+ /* Save PC */
+ gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R1,
+ GUM_ADDRESS(persistent_start));
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0,
+ offsetof(GumCpuContext, pc));
+
+ /* Restore Regs */
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE + sizeof(guint32));
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE);
+}
- uint32_t r14;
- uint32_t lr;
+static void instrument_persitent_restore_regs(GumArmWriter * cw,
+ GumCpuContext *regs) {
+ gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(regs));
+
+ /* Restore CPSR */
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R0,
+ offsetof(GumCpuContext, cpsr));
+ gum_arm_writer_put_mov_cpsr_reg(cw, ARM_REG_R1);
+
+ /* Restore sp & lr */
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_SP, ARM_REG_R0,
+ offsetof(GumCpuContext, sp));
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0,
+ offsetof(GumCpuContext, lr));
+
+ /* Restore r8-r12 */
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R8, ARM_REG_R0,
+ offsetof(GumCpuContext, r8));
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R9, ARM_REG_R0,
+ offsetof(GumCpuContext, r9));
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R10, ARM_REG_R0,
+ offsetof(GumCpuContext, r10));
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R11, ARM_REG_R0,
+ offsetof(GumCpuContext, r11));
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R12, ARM_REG_R0,
+ offsetof(GumCpuContext, r12));
+
+ /* Restore r7-r0 */
+ for (size_t i = ARM_REG_R7; i >= ARM_REG_R0; i--) {
+ gum_arm_writer_put_ldr_reg_reg_offset(
+ cw, i, ARM_REG_R0, offsetof(GumCpuContext, r[i - ARM_REG_R0]));
+ }
+}
- };
+static void instrument_exit(GumArmWriter *cw) {
+ gum_arm_writer_put_sub_reg_reg_reg(cw, ARM_REG_R0, ARM_REG_R0, ARM_REG_R0);
+ gum_arm_writer_put_call_address_with_arguments(cw, GUM_ADDRESS(_exit), 1,
+ GUM_ARG_REGISTER, ARM_REG_R0);
+}
- union {
+static int instrument_afl_persistent_loop_func(void) {
+ int ret = __afl_persistent_loop(persistent_count);
+ if (instrument_previous_pc_addr == NULL) {
+ FATAL("instrument_previous_pc_addr uninitialized");
+ }
- uint32_t r15;
- uint32_t pc;
+ *instrument_previous_pc_addr = instrument_hash_zero;
+ return ret;
+}
- };
+static void instrument_afl_persistent_loop(GumArmWriter *cw) {
+ gum_arm_writer_put_sub_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE);
+ gum_arm_writer_put_call_address_with_arguments(
+ cw, GUM_ADDRESS(instrument_afl_persistent_loop_func), 0);
+ gum_arm_writer_put_add_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE);
+}
- uint32_t cpsr;
+static void persistent_prologue_hook(GumArmWriter *cw, GumCpuContext *regs) {
+ if (persistent_hook == NULL) return;
- uint8_t vfp_zregs[32][16];
- uint32_t vfp_xregs[16];
+ gum_arm_writer_put_sub_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE);
+ gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R2,
+ GUM_ADDRESS(&__afl_fuzz_len));
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R2, ARM_REG_R2, 0);
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R2, ARM_REG_R2, 0);
-};
+ gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R1,
+ GUM_ADDRESS(&__afl_fuzz_ptr));
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R1, ARM_REG_R1, 0);
-typedef struct arm_regs arch_api_regs;
+ gum_arm_writer_put_call_address_with_arguments(
+ cw, GUM_ADDRESS(persistent_hook), 3, GUM_ARG_ADDRESS, GUM_ADDRESS(regs),
+ GUM_ARG_REGISTER, ARM_REG_R1, GUM_ARG_REGISTER, ARM_REG_R2);
-gboolean persistent_is_supported(void) {
+ gum_arm_writer_put_add_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE);
+}
- return false;
+static void instrument_persitent_save_lr(GumArmWriter *cw) {
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE);
+ gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(&saved_lr));
+ gum_arm_writer_put_str_reg_reg_offset(cw, ARM_REG_LR, ARM_REG_R0, 0);
+
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_SP,
+ GUM_RED_ZONE_SIZE);
}
void persistent_prologue_arch(GumStalkerOutput *output) {
+ /*
+ * SAVE REGS
+ * SAVE RET
+ * POP RET
+ * loop:
+ * CALL instrument_afl_persistent_loop
+ * TEST EAX, EAX
+ * JZ end:
+ * call hook (optionally)
+ * RESTORE REGS
+ * call original
+ * jmp loop:
+ *
+ * end:
+ * JMP SAVED RET
+ *
+ * original:
+ * INSTRUMENTED PERSISTENT FUNC
+ */
+
+ GumArmWriter *cw = output->writer.arm;
+
+ gconstpointer loop = cw->code + 1;
- UNUSED_PARAMETER(output);
- FFATAL("Persistent mode not supported on this architecture");
+ FVERBOSE("Persistent loop reached");
+ instrument_persitent_save_regs(cw, &saved_regs);
+
+ /* loop: */
+ gum_arm_writer_put_label(cw, loop);
+
+ /* call instrument_prologue_func */
+ instrument_afl_persistent_loop(cw);
+
+ /* jz done */
+ gconstpointer done = cw->code + 1;
+ gum_arm_writer_put_cmp_reg_imm(cw, ARM_REG_R0, 0);
+ gum_arm_writer_put_b_cond_label(cw, ARM_CC_EQ, done);
+
+ /* Optionally call the persistent hook */
+ persistent_prologue_hook(cw, &saved_regs);
+
+ instrument_persitent_restore_regs(cw, &saved_regs);
+ gconstpointer original = cw->code + 1;
+ /* call original */
+
+ gum_arm_writer_put_bl_label(cw, original);
+
+ /* jmp loop */
+ gum_arm_writer_put_b_label(cw, loop);
+
+ /* done: */
+ gum_arm_writer_put_label(cw, done);
+
+ instrument_exit(cw);
+
+ /* original: */
+ gum_arm_writer_put_label(cw, original);
+
+ instrument_persitent_save_lr(cw);
+
+ if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); }
}
void persistent_epilogue_arch(GumStalkerOutput *output) {
+ GumArmWriter *cw = output->writer.arm;
+
+ if (persistent_debug) { gum_arm_writer_put_breakpoint(cw); }
+
+ gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(&saved_lr));
- UNUSED_PARAMETER(output);
- FFATAL("Persistent mode not supported on this architecture");
+ gum_arm_writer_put_ldr_reg_reg_offset(cw, ARM_REG_R0, ARM_REG_R0, 0);
+ gum_arm_writer_put_bx_reg(cw, ARM_REG_R0);
}
#endif

Added support for ARM32 persistent mode