about summary refs log tree commit diff
path: root/frida_mode/src/persistent/persistent_arm32.c
diff options
context:
space:
mode:
Diffstat (limited to 'frida_mode/src/persistent/persistent_arm32.c')
-rw-r--r--frida_mode/src/persistent/persistent_arm32.c285
1 files changed, 252 insertions, 33 deletions
diff --git a/frida_mode/src/persistent/persistent_arm32.c b/frida_mode/src/persistent/persistent_arm32.c
index b4e50897..dbe51eb5 100644
--- a/frida_mode/src/persistent/persistent_arm32.c
+++ b/frida_mode/src/persistent/persistent_arm32.c
@@ -1,75 +1,294 @@
 #include "frida-gumjs.h"
 
+#include "instrument.h"
 #include "persistent.h"
 #include "util.h"
 
 #if defined(__arm__)
 
-struct arm_regs {
+// struct _GumArmCpuContext {
 
-  uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10;
+//   guint32 pc;
+//   guint32 sp;
+//   guint32 cpsr;
 
-  union {
+//   guint32 r8;
+//   guint32 r9;
+//   guint32 r10;
+//   guint32 r11;
+//   guint32 r12;
 
-    uint32_t r11;
-    uint32_t fp;
+//   GumArmVectorReg v[16];
 
-  };
+//   guint32 _padding;
 
-  union {
+//   guint32 r[8];
+//   guint32 lr;
+// };
 
-    uint32_t r12;
-    uint32_t ip;
+// r11 - fp
+// r12 - ip
+// r13 - sp
+// r14 - lr
+// r15 - pc
 
-  };
+static GumCpuContext saved_regs = {0};
+static gpointer      saved_lr = NULL;
 
-  union {
+gboolean persistent_is_supported(void) {
 
-    uint32_t r13;
-    uint32_t sp;
+  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));
+
+  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]));
+
+  }
+
+  /* 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) {
 
-  union {
+  gum_arm_writer_put_ldr_reg_address(cw, ARM_REG_R0, GUM_ADDRESS(regs));
 
-    uint32_t r15;
-    uint32_t pc;
+  /* 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));
 
-  uint32_t cpsr;
+  /* 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));
 
-  uint8_t  vfp_zregs[32][16];
-  uint32_t vfp_xregs[16];
+  /* 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]));
 
-typedef struct arm_regs arch_api_regs;
+  }
 
-gboolean persistent_is_supported(void) {
+}
+
+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);
+
+}
+
+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");
+
+  }
 
-  return false;
+  *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);
+
+}
+
+static void persistent_prologue_hook(GumArmWriter *cw, GumCpuContext *regs) {
+
+  if (persistent_hook == NULL) return;
+
+  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);
+
+  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);
+
+  gum_arm_writer_put_add_reg_reg_imm(cw, ARM_REG_SP, ARM_REG_SP,
+                                     GUM_RED_ZONE_SIZE);
+
+}
+
+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) {
 
-  UNUSED_PARAMETER(output);
-  FFATAL("Persistent mode not supported on this architecture");
+  /*
+   *  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;
+
+  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) {
 
-  UNUSED_PARAMETER(output);
-  FFATAL("Persistent mode not supported on this architecture");
+  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));
+
+  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);
 
 }