about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--frida_mode/include/instrument.h2
-rw-r--r--frida_mode/src/instrument/instrument.c2
-rw-r--r--frida_mode/src/instrument/instrument_arm64.c232
-rw-r--r--frida_mode/src/instrument/instrument_debug.c4
-rw-r--r--frida_mode/src/persistent/persistent_arm64.c7
-rw-r--r--frida_mode/src/util.c2
6 files changed, 186 insertions, 63 deletions
diff --git a/frida_mode/include/instrument.h b/frida_mode/include/instrument.h
index a5d52616..63f12181 100644
--- a/frida_mode/include/instrument.h
+++ b/frida_mode/include/instrument.h
@@ -51,7 +51,7 @@ void instrument_coverage_unstable(guint64 edge, guint64 previous_rip,
                                   guint64 previous_end, guint64 current_rip,
                                   guint64 current_end);
 
-void instrument_on_fork();
+void instrument_on_fork(void);
 
 guint64 instrument_get_offset_hash(GumAddress current_rip);
 
diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c
index e3f3717e..bf102a82 100644
--- a/frida_mode/src/instrument/instrument.c
+++ b/frida_mode/src/instrument/instrument.c
@@ -32,7 +32,7 @@ char *   instrument_coverage_unstable_filename = NULL;
 
 static GumStalkerTransformer *transformer = NULL;
 
-__thread guint64 instrument_previous_pc = 0;
+__attribute__((aligned(0x1000))) __thread guint64 instrument_previous_pc = 0;
 
 static GumAddress previous_rip = 0;
 static GumAddress previous_end = 0;
diff --git a/frida_mode/src/instrument/instrument_arm64.c b/frida_mode/src/instrument/instrument_arm64.c
index 0f635458..27142f1f 100644
--- a/frida_mode/src/instrument/instrument_arm64.c
+++ b/frida_mode/src/instrument/instrument_arm64.c
@@ -1,50 +1,121 @@
+#include <stddef.h>
+
 #include "frida-gumjs.h"
 
 #include "config.h"
 
 #include "instrument.h"
+#include "ranges.h"
+#include "stalker.h"
+#include "util.h"
+
+#define G_MININT33 ((gssize)0xffffffff00000000)
+#define G_MAXINT33 ((gssize)0x00000000ffffffff)
+
+#define PAGE_MASK (~(GUM_ADDRESS(0xfff)))
+#define PAGE_ALIGNED(x) ((GUM_ADDRESS(x) & PAGE_MASK) == GUM_ADDRESS(x))
 
 #if defined(__aarch64__)
 
-static GumAddress current_log_impl = GUM_ADDRESS(0);
+__attribute__((aligned(0x1000))) static guint8 area_ptr_dummy[MAP_SIZE];
+
+  #pragma pack(push, 1)
+typedef struct {
+
+  // cur_location = (block_address >> 4) ^ (block_address << 8);
+  // shared_mem[cur_location ^ prev_location]++;
+  // prev_location = cur_location >> 1;
+
+  // stp     x0, x1, [sp, #-160]
+  // adrp    x0, 0x7fb7ff4000
+  // ldr     x1, [x0]
+  // mov     x0, #0x18b8
+  // eor     x0, x1, x0
+  // adrp    x1, 0x7fb7d73000
+  // add     x0, x1, x0
+  // ldrb    w1, [x0]
+  // add     w1, w1, #0x1
+  // tbz     w1, #8, 0x7fb6f0dec8
+  // mov     w1, #0x1
+  // strb    w1, [x0]
+  // adrp    x0, 0x7fb7ff4000
+  // mov     x1, #0xc5c
+  // str     x1, [x0]
+  // ldp     x0, x1, [sp, #-160]
+  // b       0x7fb6f0dee4
+  // ldp     x16, x17, [sp], #144
+
+  uint32_t stp_x0_x1;                           /* stp x0, x1, [sp, #-0xa0] */
+
+  uint32_t adrp_x0_prev_loc1;                           /* adrp x0, #0xXXXX */
+  uint32_t ldr_x1_ptr_x0;                                   /* ldr x1, [x0] */
+
+  uint32_t mov_x0_curr_loc;                             /* movz x0, #0xXXXX */
+  uint32_t eor_x0_x1_x0;                                  /* eor x0, x1, x0 */
+  uint32_t adrp_x1_area_ptr;                            /* adrp x1, #0xXXXX */
+  uint32_t add_x0_x1_x0;                                  /* add x0, x1, x0 */
+
+  uint32_t ldrb_w1_x0;                                     /* ldrb w1, [x0] */
+  uint32_t add_w1_w1_1;                                   /* add w1, w1, #1 */
+  uint32_t tbz_w1_8_8;                                    /* tbz w1, #8, #8 */
+  uint32_t mov_w1_1;                                          /* mov w1, #1 */
+
+  uint32_t strb_w1_ptr_x0;                                 /* strb w1, [x0] */
+
+  uint32_t adrp_x0_prev_loc2;                           /* adrp x0, #0xXXXX */
+  uint32_t mov_x1_curr_loc_shr_1;                       /* movz x1, #0xXXXX */
+  uint32_t str_x1_ptr_x0;                                   /* str x1, [x0] */
+
+  uint32_t ldp_x0_x1;                           /* ldp x0, x1, [sp, #-0xa0] */
 
-static const guint8 afl_log_code[] = {
+  uint32_t b_imm8;                                                 /* br #8 */
+  uint32_t restoration_prolog;                 /* ldp x16, x17, [sp], #0x90 */
 
-    // __afl_area_ptr[current_pc ^ previous_pc]++;
-    // previous_pc = current_pc ROR 1;
-    0xE1, 0x0B, 0xBF, 0xA9,  // stp x1, x2, [sp, -0x10]!
-    0xE3, 0x13, 0xBF, 0xA9,  // stp x3, x4, [sp, -0x10]!
+} afl_log_code_asm_t;
 
-    // x0 = current_pc
-    0x21, 0x02, 0x00, 0x58,  // ldr x1, #0x44, =&__afl_area_ptr
-    0x21, 0x00, 0x40, 0xf9,  // ldr x1, [x1] (=__afl_area_ptr)
+  #pragma pack(pop)
 
-    0x22, 0x02, 0x00, 0x58,  // ldr x2, #0x44, =&previous_pc
-    0x42, 0x00, 0x40, 0xf9,  // ldr x2, [x2] (=previous_pc)
+typedef union {
 
-    // __afl_area_ptr[current_pc ^ previous_pc]++;
-    0x42, 0x00, 0x00, 0xca,  // eor x2, x2, x0
-    0x23, 0x68, 0x62, 0xf8,  // ldr x3, [x1, x2]
-    0x63, 0x04, 0x00, 0x91,  // add x3, x3, #1
-    0x63, 0x00, 0x1f, 0x9a,  // adc x3, x3, xzr
-    0x23, 0x68, 0x22, 0xf8,  // str x3, [x1, x2]
+  afl_log_code_asm_t code;
+  uint8_t            bytes[0];
 
-    // previous_pc = current_pc ROR 1;
-    0xe4, 0x07, 0x40, 0x8b,  // add x4, xzr, x0, LSR #1
-    0xe0, 0xff, 0x00, 0x8b,  // add x0, xzr, x0, LSL #63
-    0x80, 0xc0, 0x40, 0x8b,  // add x0, x4, x0, LSR #48
+} afl_log_code;
 
-    0xe2, 0x00, 0x00, 0x58,  // ldr x2, #0x1c, =&previous_pc
-    0x40, 0x00, 0x00, 0xf9,  // str x0, [x2]
+static const afl_log_code_asm_t template =
+    {
 
-    0xE3, 0x13, 0xc1, 0xA8,  // ldp x3, x4, [sp], #0x10
-    0xE1, 0x0B, 0xc1, 0xA8,  // ldp x1, x2, [sp], #0x10
-    0xC0, 0x03, 0x5F, 0xD6,  // ret
+        .stp_x0_x1 = 0xa93607e0,
 
-    // &afl_area_ptr_ptr
-    // &afl_prev_loc_ptr
+        .adrp_x0_prev_loc1 = 0xb0000000,
+        .ldr_x1_ptr_x0 = 0xf9400001,
 
-};
+        .mov_x0_curr_loc = 0xd2800000,
+        .eor_x0_x1_x0 = 0xca000020,
+
+        .adrp_x1_area_ptr = 0x90000001,
+        .add_x0_x1_x0 = 0x8b000020,
+
+        .ldrb_w1_x0 = 0x39400001,
+
+        .add_w1_w1_1 = 0x11000421,
+        .tbz_w1_8_8 = 0x36400041,
+        .mov_w1_1 = 0x52800021,
+
+        .strb_w1_ptr_x0 = 0x39000001,
+
+        .adrp_x0_prev_loc2 = 0xb0000000,
+        .mov_x1_curr_loc_shr_1 = 0xd2800001,
+        .str_x1_ptr_x0 = 0xf9000001,
+
+        .ldp_x0_x1 = 0xa97607e0,
+
+        .b_imm8 = 0x14000002,
+        .restoration_prolog = 0xa8c947f0,
+
+}
+
+;
 
 gboolean instrument_is_coverage_optimize_supported(void) {
 
@@ -52,50 +123,99 @@ gboolean instrument_is_coverage_optimize_supported(void) {
 
 }
 
+static gboolean instrument_coverage_in_range(gssize offset) {
+
+  return (offset >= G_MININT33 && offset <= G_MAXINT33);
+
+}
+
+static void instrument_patch_ardp(guint32 *patch, GumAddress insn,
+                                  GumAddress target) {
+
+  if (!PAGE_ALIGNED(target)) { FATAL("Target not page aligned"); }
+
+  gssize distance = target - (GUM_ADDRESS(insn) & PAGE_MASK);
+  if (!instrument_coverage_in_range(distance)) {
+
+    FATAL("Patch out of range 0x%016lX->0x%016lX = 0x%016lX", insn, target,
+          distance);
+
+  }
+
+  guint32 imm_low = ((distance >> 12) & 0x3) << 29;
+  guint32 imm_high = ((distance >> 14) & 0x7FFFF) << 5;
+  *patch |= imm_low;
+  *patch |= imm_high;
+
+}
+
 void instrument_coverage_optimize(const cs_insn *   instr,
                                   GumStalkerOutput *output) {
 
-  guint64 current_pc = instr->address;
-  guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
+  afl_log_code    code = {0};
   GumArm64Writer *cw = output->writer.arm64;
+  guint64 area_offset = instrument_get_offset_hash(GUM_ADDRESS(instr->address));
+  gsize      map_size_pow2;
+  gsize      area_offset_ror;
+  GumAddress code_addr = 0;
 
-  if (current_log_impl == 0 ||
-      !gum_arm64_writer_can_branch_directly_between(cw, cw->pc,
-                                                    current_log_impl) ||
-      !gum_arm64_writer_can_branch_directly_between(cw, cw->pc + 128,
-                                                    current_log_impl)) {
+  // gum_arm64_writer_put_brk_imm(cw, 0x0);
 
-    gconstpointer after_log_impl = cw->code + 1;
+  code_addr = cw->pc;
 
-    gum_arm64_writer_put_b_label(cw, after_log_impl);
+  code.code = template;
 
-    current_log_impl = cw->pc;
-    gum_arm64_writer_put_bytes(cw, afl_log_code, sizeof(afl_log_code));
+  /*
+   * Given our map is allocated on a 64KB boundary and our map is a multiple of
+   * 64KB in size, then it should also end on a 64 KB boundary. It is followed
+   * by our previous_pc, so this too should be 64KB aligned.
+   */
+  g_assert(PAGE_ALIGNED(&instrument_previous_pc));
+  g_assert(PAGE_ALIGNED(__afl_area_ptr));
 
-    uint8_t **afl_area_ptr_ptr = &__afl_area_ptr;
-    uint64_t *afl_prev_loc_ptr = &instrument_previous_pc;
-    gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_area_ptr_ptr,
-                               sizeof(afl_area_ptr_ptr));
-    gum_arm64_writer_put_bytes(cw, (const guint8 *)&afl_prev_loc_ptr,
-                               sizeof(afl_prev_loc_ptr));
+  instrument_patch_ardp(
+      &code.code.adrp_x0_prev_loc1,
+      code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc1),
+      GUM_ADDRESS(&instrument_previous_pc));
 
-    gum_arm64_writer_put_label(cw, after_log_impl);
+  code.code.mov_x0_curr_loc |= area_offset << 5;
 
-  }
+  instrument_patch_ardp(
+      &code.code.adrp_x1_area_ptr,
+      code_addr + offsetof(afl_log_code, code.adrp_x1_area_ptr),
+      GUM_ADDRESS(__afl_area_ptr));
+
+  map_size_pow2 = util_log2(__afl_map_size);
+  area_offset_ror = util_rotate(area_offset, 1, map_size_pow2);
 
-  gum_arm64_writer_put_stp_reg_reg_reg_offset(
-      cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, -(16 + GUM_RED_ZONE_SIZE),
-      GUM_INDEX_PRE_ADJUST);
-  gum_arm64_writer_put_ldr_reg_u64(cw, ARM64_REG_X0, area_offset);
-  gum_arm64_writer_put_bl_imm(cw, current_log_impl);
-  gum_arm64_writer_put_ldp_reg_reg_reg_offset(
-      cw, ARM64_REG_LR, ARM64_REG_X0, ARM64_REG_SP, 16 + GUM_RED_ZONE_SIZE,
-      GUM_INDEX_POST_ADJUST);
+  instrument_patch_ardp(
+      &code.code.adrp_x0_prev_loc2,
+      code_addr + offsetof(afl_log_code, code.adrp_x0_prev_loc2),
+      GUM_ADDRESS(&instrument_previous_pc));
+
+  code.code.mov_x1_curr_loc_shr_1 |= (area_offset_ror << 5);
+
+  gum_arm64_writer_put_bytes(cw, code.bytes, sizeof(afl_log_code));
 
 }
 
 void instrument_coverage_optimize_init(void) {
 
+  char *shm_env = getenv(SHM_ENV_VAR);
+  FVERBOSE("SHM_ENV_VAR: %s", shm_env);
+
+  if (shm_env == NULL) {
+
+    FWARNF("SHM_ENV_VAR not set, using dummy for debugging purposes");
+
+    __afl_area_ptr = area_ptr_dummy;
+    memset(area_ptr_dummy, '\0', sizeof(area_ptr_dummy));
+
+  }
+
+  FVERBOSE("__afl_area_ptr: %p", __afl_area_ptr);
+  FVERBOSE("instrument_previous_pc: %p", &instrument_previous_pc);
+
 }
 
 void instrument_flush(GumStalkerOutput *output) {
diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c
index a1f80467..592ab673 100644
--- a/frida_mode/src/instrument/instrument_debug.c
+++ b/frida_mode/src/instrument/instrument_debug.c
@@ -35,6 +35,10 @@ static void instrument_debug(char *format, ...) {
 static void instrument_disasm(guint8 *start, guint8 *end,
                               GumStalkerOutput *output) {
 
+#if !defined(__arm__)
+  UNUSED_PARAMETER(output);
+#endif
+
   csh      capstone;
   cs_err   err;
   cs_mode  mode;
diff --git a/frida_mode/src/persistent/persistent_arm64.c b/frida_mode/src/persistent/persistent_arm64.c
index adad41be..48f29bb0 100644
--- a/frida_mode/src/persistent/persistent_arm64.c
+++ b/frida_mode/src/persistent/persistent_arm64.c
@@ -89,7 +89,7 @@ static void instrument_persitent_save_regs(GumArm64Writer *  cw,
 
   /* LR (x30) */
   gum_arm64_writer_put_str_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X0,
-                                          offsetof(GumCpuContext, x[30]));
+                                          offsetof(GumCpuContext, lr));
 
   /* PC & Adjusted SP (31) */
   gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X2,
@@ -189,7 +189,7 @@ static void instrument_persitent_restore_regs(GumArm64Writer *  cw,
 
   /* LR (x30) */
   gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X30, ARM64_REG_X0,
-                                          offsetof(GumCpuContext, x[30]));
+                                          offsetof(GumCpuContext, lr));
 
   /* Adjusted SP (31) (use x1 as clobber)*/
   gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X1, ARM64_REG_X0,
@@ -264,8 +264,7 @@ static void persistent_prologue_hook(GumArm64Writer *  cw,
   gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X2, 0);
   gum_arm64_writer_put_ldr_reg_reg_offset(cw, ARM64_REG_X2, ARM64_REG_X2, 0);
 
-  gum_arm64_writer_put_and_reg_reg_imm(cw, ARM64_REG_X2, ARM64_REG_X2,
-                                       G_MAXULONG);
+  gum_arm64_writer_put_mov_reg_reg(cw, ARM64_REG_W2, ARM64_REG_W2);
 
   gum_arm64_writer_put_ldr_reg_address(cw, ARM64_REG_X1,
                                        GUM_ADDRESS(&__afl_fuzz_ptr));
diff --git a/frida_mode/src/util.c b/frida_mode/src/util.c
index e4d2aaf2..90c10917 100644
--- a/frida_mode/src/util.c
+++ b/frida_mode/src/util.c
@@ -68,7 +68,7 @@ guint64 util_read_num(char *key, guint64 default_value) {
 
   errno = 0;
 
-  guint64 value = g_ascii_strtoull(value_str, NULL, 10);
+  guint64 value = g_ascii_strtoull(value_str, &end_ptr, 10);
 
   if (errno != 0) {