about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--frida_mode/src/instrument/instrument.c2
-rw-r--r--frida_mode/src/instrument/instrument_arm64.c232
2 files changed, 177 insertions, 57 deletions
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) {