HENkaku PS Vita CTF: Reverse Engineering

It has been nearly to a month since the HENkaku was released and Yifan Lu made a CTF challenge for everyone that is interested to learn more about PS Vita security. It’s a very interesting if you want to join and help with vita hacking to try it, anyway, let’s get started.

HENkaku works with three stages, where the first stage is to get ROP code under user-land, the second stage is to exploit the kernel and finally stage3 that is ROP code and native code execution.

Stage1: WebKit Exploit

I won’t explain details what the webkit exploit is because xyz already did an amazing writeup about the exploit and other guys already did some writeup about it. I really recommend you read it here that is very important to understand the next stages. I did it myself before, you can read it here (bad comments). The only problem here is that the code is a bit obfuscated(variables with short names, a total mess), so you will have to spend some hours to read the code and understand what it does. What the first ROP code will do is get the base address of each module (SceWebKit, SceLibKernel, SceLibC, SceLibHttp, SceNet and SceAppMgr) and stack memory and use SceHttp module to download the stage 2(the ‘x’ file) from the henkaku server. It’s necessary to defeat the ASLR and have a generic stage2 exploit, so each time you have the base address of each module, you send them to the server and server plus the addresses to each gadget and send back a stage2 with right addresses. Once you know how it works and having the modules dumped(you can dump modules using this tool), you can download the stage 2 ‘x’ file direct from server, here an example that I used to stage2 analysis.

http://go.henkaku.me/x?a1=50000000&a2=83a00780&a3=e0004d40&a4=83980a10&&a5=e0604c80&a6=e05236d0&a7=20000000&
webkit_base = 0x83a00780
stack_base = 50000000
libkernel_base = 0xe0004d40
libc_base = 0x83980a10
libhttp_base = 0xe0604c80
net_base = 0xe05236d0
driveruser_base = 0x20000000

 

Stage2: Kernel exploits

The stage2 is a huge rop-chain and to solve this problem I written a python script using capstone to help me to deal with it, you can find it here (the code is a mess). The output is a list of all gadged used in HENkaku stage2, an example. So I decided to write some pseudo code based on the rop-chain, that is one of the best ways to understand what the ROP code is doing.
code:

/*
* stack_base = 0x0x50000000
* lib_c = SceLibC
* lib_kernel = sceLibKernel
*/
void _rop_chain_() {

// copy sdstor0 to a region in the stack
// copy xmc-lp.. to a region in the stack
lib_c_strcpy(stack_sd_E5B4, "sdstor0");
lib_c_strcpy(stack_xmc_E5CC, "xmc-lp-ign-userext");

// clear buff, fill data with sceDevIoCtl
lib_c_memset(stack_buff_CE34, 0x400, 0x0)

// copy molecule0: to stack region
lib_c_strcpy(stack_mole_E5E4, "molecule0:")

/*
* In this point, the sceIoDevCtl is used to leak memory from stack
* the leaked memory will be in the stack_buff_CE34 until 0xCE34+0x3FF
* it won't work with values big than 0x3FF
*/
// sceIoOpen
lib_kernel_sceIoOpen("molecule0:", 0x0, 0x0);
// sceIoDevctl
lib_kernel_sceIoDevctl("sdstor0:", 0x5, "xmc-lp-ign-userext", 0x14, stack_buff_CE34, 0x3FF);

// This is the kernel module address leaked from stack
// it's used to defeat kernel ASLR
// an example: 0x00489E15
*(unsigned int *)(stack_leaked_addr_base_E364) = *(unsigned int *)(stack_leaked_output_D208) + 0xFFFFA8B9;

// stack_leak_addr_base_E364 = 0x004846CE
// create a thread, note that the entry-point is an address in SceWebKit region
thread_id_stack_ED94 = lib_kernel_createThread("pln", 0x83A05C48, 0x10000100, 0x00002000)

// store threadinfo size
stack_threadinfo_E52C = 0x7C

// get thread information
lib_kernel_threadinfo(thread_id_stack_ED94, stack_threadinfo_E52C, NULL);

// get thread stack address and plus 0x1000
*(unsigned int *)(stack_thread_new_sp_EDA0) = *(unsigned int *)(stack_thread_sp_E560) + 0x1000;
*(unsigned int *)(stack_leaked_output_E854) = 0x14; // inLen sceIoCtl
*(unsigned int *)(stack_leaked_output_len_E858) = stack_buff_CE34;
*(unsigned int *)(stack_var_E85C) = 0x3FF;
*(unsigned int *)(stack_leaked_input_len_E86C) = 0x400;
*(unsigned int *)(stack_var_E870) = 0x0;
*(unsigned int *)(stack_var_E874) = 0x0;

// thread 1 "pln" rop-chain
*(unsigned int *)(stack_var_E608) = 0x842DE135; // POP {R0-R5,PC}
*(unsigned int *)(stack_var_E60C) = stack_mole_E5E4; // R0
*(unsigned int *)(stack_var_E610) = 0x0; // R1
*(unsigned int *)(stack_var_E614) = 0x0; // R2
*(unsigned int *)(stack_var_E618) = 0x0; // R3
*(unsigned int *)(stack_var_E61C) = 0xE000F1ED; // R4
*(unsigned int *)(stack_var_E620) = 0x0; // R5
*(unsigned int *)(stack_var_E624) = 0x83AFD53B; // BX R4
*(unsigned int *)(stack_var_E628) = 0x0; // POP {R4, PC} R4 = 0
// lib_kernel_sceIoOpen

*(unsigned int *)(stack_var_E62C) = 0x842DE135; // POP {R0-R5, PC}
*(unsigned int *)(stack_var_E630) = stack_sd_E5B4; // sdstor0 R0
*(unsigned int *)(stack_var_E634) = 0x5; // R1
*(unsigned int *)(stack_var_E638) = stack_xmc_E5CC; // R2
*(unsigned int *)(stack_var_E63C) = stack_leaked_output_E854; // R3
*(unsigned int *)(stack_var_E640) = 0xE000B64C; // R4
*(unsigned int *)(stack_var_E644) = 0x0; // R5
*(unsigned int *)(stack_var_E648) = 0x83AFD53B; // BX R4
*(unsigned int *)(stack_var_E64C) = 0x0; // POP R4
// lib_kernel_sceIoDevctl

*(unsigned int *)(stack_var_E650) = 0x842DE135; // POP {R0-R5, PC}
*(unsigned int *)(stack_var_E654) = 0x000F4240; // R0
*(unsigned int *)(stack_var_E658) = 0x0; // R1
*(unsigned int *)(stack_var_E65C) = 0x0; // R2
*(unsigned int *)(stack_var_E660) = 0x0; // R3
*(unsigned int *)(stack_var_E664) = 0xE061D1C4; // R4 - thread delay
*(unsigned int *)(stack_var_E668) = 0x0; // R5
*(unsigned int *)(stack_var_E66C) = 0x83AFD53B; // BLX R4
*(unsigned int *)(stack_var_E670) = 0x0; // POP R4
// thread delay 0xF4240

*(unsigned int *)(stack_var_E674) = 0x842DE135; // POP {R0-R5, PC}
*(unsigned int *)(stack_var_E678) = stack_sd_E5B4; // R0
*(unsigned int *)(stack_var_E67C) = 0x5; // R1
*(unsigned int *)(stack_var_E680) = stack_leaked_input_D344; // R2
*(unsigned int *)(stack_var_E684) = stack_sd_E5B4; // R3
*(unsigned int *)(stack_var_E688) = 0xE000B64C; // R4 - lib_kernel_sceIoDevctl
*(unsigned int *)(stack_var_E68C) = 0x0; // R5
*(unsigned int *)(stack_var_E690) = 0x83AFD53B; // BLX R4
*(unsigned int *)(stack_var_E694) = 0x0; // POP R4
*(unsigned int *)(stack_var_E698) = 0x83A00C99; // while (true) {} B loc_83A00C98
// lib_kernel_sceIoDevctl

// stack_var_E608 = new rop-chain
// stack_thread_new_sp_EDA0 = new thread sp
libc_memcpy(stack_thread_new_sp_EDA0, stack_var_E608, 0x100);

// store the thread sp in E730
*(unsigned int *)(stack_var_E730) = *(unsigned int*)(stack_thread_new_sp_EDA0);
*(unsigned int *)(stack_var_E734) = 0x83AC0C0B;

// start "pln" thread that will run our rop_chain 1
lib_kernel_startThread(thread_id_stack_ED94, 0x1C, stack_var_E71C)

// put our thread to sleep
lib_http_delay_thread(0x186A0)

// ------------------------------------
/*
* Thread 1 - pln ROP Chain
* Here more interesting stuff
* The first part is used to leak again another peace of stack and stored in E854
* after the delay_thread, it will leak more stack memory, but using the INPUT
* and size 0x400
*/

lib_kernel_sceIoOpen("molecule0:");
lib_kernel_sceIoDevctl("sdstor0:", 0x5, "xmc-lp-ign-userext", stack_leaked_output_E854, stack_leaked_output_len_E858, stack_var_E85C)
lib_http_delay_thread(0xF4240)
lib_kernel_sceIoDevctl("sdstor0:", 0x5, stack_leaked_input_D344, stack_leaked_input_len_E86C, 0x0, 0x0)
while (1) {}
// ------------------------------------

// get value from the buffer that sceIoDevCtl used
//
*(unsigned int *)(stack_var_E358) = *(unsigned int *)(stack_var_D1F8) + 0xFFFFF544;

// probably the first gadget
*(unsigned int *)(stack_leaked_input_D344) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1E460;

*(unsigned int *)(stack_var_EDB8) = *(unsigned int *)(stack_var_E358) + 0x6F8 + 0x300;

// kernel ROP-Chain, base = 0x00489E15 - FW 1.50
*(unsigned int *)(stack_var_E98C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x31; // 0x489E46
*(unsigned int *)(stack_var_E990) = 0x08106803; // address ?
*(unsigned int *)(stack_var_E994) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1EFF1; // 0x4A8E06
*(unsigned int *)(stack_var_E998) = 0x38; // const ?
*(unsigned int *)(stack_var_E99C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1EFE1; // 0x4A8DF6
*(unsigned int *)(stack_var_E9A0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347; // 0x48A15C
*(unsigned int *)(stack_var_E9A4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_E9A8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1B571;
*(unsigned int *)(stack_var_E9AC) = 0x0; // ?
*(unsigned int *)(stack_var_E9B0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1E43;
*(unsigned int *)(stack_var_E9B4) = 0x0; // ?
*(unsigned int *)(stack_var_E9B8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1FC6D;
*(unsigned int *)(stack_var_E9BC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xEA73;
*(unsigned int *)(stack_var_E9C0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x31;
*(unsigned int *)(stack_var_E9C4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x27913;
*(unsigned int *)(stack_var_E0C8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xA523;
*(unsigned int *)(stack_var_E0CC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_E0D0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xCE3;
*(unsigned int *)(stack_var_E0D4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_E0D8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1F2B1;
*(unsigned int *)(stack_var_E0DC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x67;
*(unsigned int *)(stack_var_E0E0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x587F;
*(unsigned int *)(stack_var_E0E4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x19713;
*(unsigned int *)(stack_var_E0E8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1605;
*(unsigned int *)(stack_var_E0EC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1E1D;
*(unsigned int *)(stack_var_E0F0) = 0x0; // ?
*(unsigned int *)(stack_var_E0F4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1EFE1;
*(unsigned int *)(stack_var_E0F8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_E0FC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1603;
*(unsigned int *)(stack_var_EA00) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1F2B1;
*(unsigned int *)(stack_var_EA04) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1F17;
*(unsigned int *)(stack_var_EA08) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EA0C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x31;
*(unsigned int *)(stack_var_EA10) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xB913;
*(unsigned int *)(stack_var_EA14) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x23B61;
*(unsigned int *)(stack_var_EA18) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EA1C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EA20) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x232EB;
*(unsigned int *)(stack_var_EA24) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EA28) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1B571;
*(unsigned int *)(stack_var_EA2C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x23B61;
*(unsigned int *)(stack_var_EA30) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x232F1;
*(unsigned int *)(stack_var_EA34) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1411;
*(unsigned int *)(stack_var_EA38) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xAE1;
*(unsigned int *)(stack_var_EA3C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EA40) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x50E9;
*(unsigned int *)(stack_var_EA44) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1411;
*(unsigned int *)(stack_var_EA48) = 0x10; // 0x90
*(unsigned int *)(stack_var_EA4C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1F2B1;
*(unsigned int *)(stack_var_EA50) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x12B11;
*(unsigned int *)(stack_var_EA54) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xCE3;
*(unsigned int *)(stack_var_EA58) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xD1;
*(unsigned int *)(stack_var_EA5C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EA60) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1F2B1;
*(unsigned int *)(stack_var_EA64) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EA68) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EA6C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1FDC5;
*(unsigned int *)(stack_var_EA70) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1D8DB;
*(unsigned int *)(stack_var_EA74) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x19399;
*(unsigned int *)(stack_var_EA78) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x19399;
*(unsigned int *)(stack_var_EA7C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x11C5F;
*(unsigned int *)(stack_var_EA80) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x19399;
*(unsigned int *)(stack_var_EA84) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EA88) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xB913;
*(unsigned int *)(stack_var_EA8C) = 0x0; // ?
*(unsigned int *)(stack_var_EA90) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1EFE1;
*(unsigned int *)(stack_var_EA94) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EA98) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1861;
*(unsigned int *)(stack_var_EA9C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1FC6D;
*(unsigned int *)(stack_var_EAA9) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1F2B1;
*(unsigned int *)(stack_var_EAA4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EAA8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EAAC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x19399;
*(unsigned int *)(stack_var_EAB0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EAB4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x19399;
*(unsigned int *)(stack_var_EAB8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EABC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EAC0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1614D;
*(unsigned int *)(stack_var_EAC4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x233D3;
*(unsigned int *)(stack_var_EACC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EAD0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xAF;
*(unsigned int *)(stack_var_EAD4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1605;
*(unsigned int *)(stack_var_EAD8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1EFE1;
*(unsigned int *)(stack_var_EADC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EAE0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x50E9;
*(unsigned int *)(stack_var_EAE4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EAE8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1347;
*(unsigned int *)(stack_var_EAEC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EAF0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xB9;
*(unsigned int *)(stack_var_EAF4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1F2B1;
*(unsigned int *)(stack_var_EAF8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1347;
*(unsigned int *)(stack_var_EAFC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EB00) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39B;
*(unsigned int *)(stack_var_EB04) = 0x0; // ?
*(unsigned int *)(stack_var_EB08) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1CB95;
*(unsigned int *)(stack_var_EB0C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1EA93;
*(unsigned int *)(stack_var_EB10) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1411;
*(unsigned int *)(stack_var_EB14) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EB18) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x209D7;
*(unsigned int *)(stack_var_EB1C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x209D3;
*(unsigned int *)(stack_var_EB20) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1411;
*(unsigned int *)(stack_var_EB24) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EB28) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1BAF5;
*(unsigned int *)(stack_var_EB2C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1605;
*(unsigned int *)(stack_var_EB30) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EB34) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x652B;
*(unsigned int *)(stack_var_EB38) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EB3C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1BAF5;
*(unsigned int *)(stack_var_EB40) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x22A49;
*(unsigned int *)(stack_var_EB44) = 0xFFFFFEB0; // ?
*(unsigned int *)(stack_var_EB48) = 0x40; // ?
*(unsigned int *)(stack_var_EB4C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39B;
*(unsigned int *)(stack_var_EB50) = 0x22A49; // ?
*(unsigned int *)(stack_var_EB54) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EB58) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x652B;
*(unsigned int *)(stack_var_EB5C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EB60) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39B;
*(unsigned int *)(stack_var_EB64) = 0x40;
*(unsigned int *)(stack_var_EB68) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1605;
*(unsigned int *)(stack_var_EB6C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EB70) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1D9EB;
*(unsigned int *)(stack_var_EB74) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EB78) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x853;
*(unsigned int *)(stack_var_EB7C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1D8DB;
*(unsigned int *)(stack_var_EB80) = 0x38;
*(unsigned int *)(stack_var_EB84) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xAB;
*(unsigned int *)(stack_var_EB88) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xD1;
*(unsigned int *)(stack_var_EB8C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x2328B;
*(unsigned int *)(stack_var_EB90) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x22FCD;
*(unsigned int *)(stack_var_EB94) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xD1;
*(unsigned int *)(stack_var_EB98) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1EFF1;
*(unsigned int *)(stack_var_EB9C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x2A117;
*(unsigned int *)(stack_var_EBA0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EBA4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1605;
*(unsigned int *)(stack_var_EBA8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x19399;
*(unsigned int *)(stack_var_EBAC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EBB0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EBB4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1BF1F;
*(unsigned int *)(stack_var_EBB8) = 0xFFFFFEB0;
*(unsigned int *)(stack_var_EBBC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39B;
*(unsigned int *)(stack_var_EBC0) = 0x40; // 240
*(unsigned int *)(stack_var_EBC4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x22A49;
*(unsigned int *)(stack_var_EBC8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EBCC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x3D73;
*(unsigned int *)(stack_var_EBD0) = 0x0;
*(unsigned int *)(stack_var_EBD4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x21FD;
*(unsigned int *)(stack_var_EBD8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EBDC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x50E9;
*(unsigned int *)(stack_var_EBE0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xAE1;
*(unsigned int *)(stack_var_EBE4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EBE8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x2A117;
*(unsigned int *)(stack_var_EBEC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EBF0) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1F2B1;
*(unsigned int *)(stack_var_EBF4) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x67;
*(unsigned int *)(stack_var_EBF8) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EBFC) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1BF47;
*(unsigned int *)(stack_var_EC00) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EC04) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x50E9;
*(unsigned int *)(stack_var_EC08) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xAF33;
*(unsigned int *)(stack_var_EC0C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EC10) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1D9EB;
*(unsigned int *)(stack_var_EC14) = 0x0;
*(unsigned int *)(stack_var_EC18) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1FC6D;
*(unsigned int *)(stack_var_EC1C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xEA73;
*(unsigned int *)(stack_var_EC20) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39B;
*(unsigned int *)(stack_var_EC24) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x853;
*(unsigned int *)(stack_var_EC28) = 0xFFFFFFFF;
*(unsigned int *)(stack_var_EC2C) = 0x8106803;
*(unsigned int *)(stack_var_EC30) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x233D3;
*(unsigned int *)(stack_var_EC34) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EC38) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x433;
*(unsigned int *)(stack_var_EC3C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x233D3;
*(unsigned int *)(stack_var_EC40) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x150A3;
*(unsigned int *)(stack_var_EC44) = 0x0; //
*(unsigned int *)(stack_var_EC48) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0xA74D;
*(unsigned int *)(stack_var_EC4C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x0;
*(unsigned int *)(stack_var_EC50) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x853;
*(unsigned int *)(stack_var_EC54) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1BF1F;
*(unsigned int *)(stack_var_EC58) = 0x0; // 0x200
*(unsigned int *)(stack_var_EC5C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1605;
*(unsigned int *)(stack_var_EC60) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x347;
*(unsigned int *)(stack_var_EC64) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x50E9;
*(unsigned int *)(stack_var_EC68) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x1605;
*(unsigned int *)(stack_var_EC6C) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x22FCD;
*(unsigned int *)(stack_var_EC70) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x39EB;
*(unsigned int *)(stack_var_EC74) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x853;
*(unsigned int *)(stack_var_EC78) = *(unsigned int *)(stack_leaked_addr_base_E364) + 0x11C5F;

*(unsigned int *)(stack_var_EB04) = stack_var_EDB8;
*(unsigned int *)(stack_var_EA48) = 0x90;
*(unsigned int *)(stack_var_EBC0) = 0x240;
*(unsigned int *)(stack_var_EC58) = 0x200;
*(unsigned int *)(stack_var_EC14) = stack_var_EECC;

// copy the new ROP-chain (probably the rop chain used in kernel)
// to D348
libc_memcpy(stack_var_D348, stack_var_E98C, 0x300);
// copy 400 bytes from the "code" to stack_D644
// to teh end of rop-chain
libc_memcpy(stack_var_D644, stack_var_EDC4, 0x400);

*(unsigned int*)(stack_var_E758) = *(unsigned int*)(stack_leaked_addr_base_E364) + 0x6DC;
*(unsigned int*)(stack_var_E74C) = *(unsigned int*)(stack_leaked_addr_base_E364) + 0x6F8;
*(unsigned int*)(stack_var_E750) = *(unsigned int*)(stack_leaked_addr_base_E364) + 0x347;

// create a thread, note that the entry-point is an address in SceWebKit region
thread_id_stack_E520 = lib_kernel_createThread("mhm", 0x83A05C48, 0x10000100, 0x00002000)

*(unsigned int*)(stack_var_E52C) = 0x7c;

// get thread information
lib_kernel_threadinfo(thread_id_stack_E520, stack_threadinfo_E52C, NULL);

// setup new stack ptr to rop
*(unsigned int *)(stack_thread_sp_E5FC) = *(unsigned int *)(stack_threadinfo_sp_E560) + 0x1000;

// x = stack_var_16374
// E370 = socketFD
// a list of sceNetSyscallSocket
stack_var_E370 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E374 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E378 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E37C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E380 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E384 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E388 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E38C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E390 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E394 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E398 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E39C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3A0 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3A4 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3A8 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3AC = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3B0 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3B4 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3B8 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3BC = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3C0 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3C4 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3C8 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3CC = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3DD = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3D4 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3D8 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3DC = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3E0 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3E4 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3E8 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3EC = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3F0 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3F4 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3F8 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E3F0 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E400 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E404 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E408 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E40C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E410 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E414 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E418 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E41C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E420 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E424 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E428 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E42C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E430 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E434 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E438 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E43C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E440 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E444 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E448 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E44C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E450 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E454 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E458 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E45C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E460 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E464 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E468 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E46C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E470 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E474 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E478 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E47C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E480 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E484 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E488 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E48C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E490 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E494 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E498 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E49C = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E4A0 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E4A4 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E4A8 = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E4AC = lib_net_sceNetSyscallSocket("x", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_var_E4B8 = lib_net_sceNetSyscallSocket("sss", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);
stack_socket_fd_E4C4 = lib_net_sceNetSyscallSocket("tst", SCE_NET_AF_INET, 0x7, 0x0);

// thread 1 "pln" rop-chain
*(unsigned int *)(stack_var_E608) = 0x842DE135; // POP {R0-R5,PC}
*(unsigned int *)(stack_var_E60C) = stack_var_E4C4; // R0 E4C4 = socket file descriptor
*(unsigned int *)(stack_var_E610) = 0x10007300; // R1 CMD
*(unsigned int *)(stack_var_E614) = 0x0; // R2
*(unsigned int *)(stack_var_E618) = 0x0; // R3
*(unsigned int *)(stack_var_E61C) = 0xE052D660; // R4 sceNetSyscallIoctl_imp
*(unsigned int *)(stack_var_E620) = 0x0; // R5
*(unsigned int *)(stack_var_E624) = 0x83AFD53B;
*(unsigned int *)(stack_var_E628) = 0x5000E710;
// sceNetSyscalIoctl

*(unsigned int *)(stack_var_E62C) = 0x83A06129;
*(unsigned int *)(stack_var_E630) = 0x0;
*(unsigned int *)(stack_var_E634) = 0x83A00C99;
// store ioctl return and while (1) {}
// copy new rop-chain
libc_memcpy(&stack_thread_sp_E5FC, stack_var_E608, 0x100);

*(unsigned int *)(stack_var_E5FC) = stack_var_E730;
*(unsigned int *)(stack_var_E734) = 0x83AC0C0B;

stack_var_E4D0 = lib_net_sceNetSyscallSocket("tmp", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0x0);

stack_var_E4F4 = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E4F8 = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E4FC = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E500 = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E504 = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E508 = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E50C = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E510 = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E514 = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E4E8 = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0xF00, 0x0);
stack_var_E4DC = lib_net_sceNetSyscallDumpCreate_imp("ddd", 0x1000, 0x0);

lib_net_sceNetSyscallDumpClose_imp(stack_var_E4F4);
lib_net_sceNetSyscallDumpClose_imp(stack_var_E4FC);
lib_net_sceNetSyscallDumpClose_imp(stack_var_E504);
lib_net_sceNetSyscallDumpClose_imp(stack_var_E50C);
lib_net_sceNetSyscallDumpClose_imp(stack_var_E514);
lib_net_sceNetSyscallDumpClose_imp(stack_var_E4E8);

// allocate memory to code
unsigned int i = 0;
for (i = 0xD0000; i > 0xA0000; i -= 0x100) {
lib_net_sceNetSyscallDumpCreate_imp("ddd", i, 0x0);
}

lib_net_sceNetSyscallDumpCreate_imp("ddd", 0x1000, 0x0);
lib_net_sceNetSyscallDumpCreate_imp("ddd", 0x1000, 0x0);

// start thread "mhm"
lib_kernel_startThread(thread_id_stack_E520, 0x1C, stack_var_E71C);

// put our main thread to *sleep*
lib_http_delay_thread(0x16E360)

// ------------------------------------
/* guess1 -> alloc the object that will trigger the exploit later ?
* Thread 2 - mhm ROP Chain
*/ // file descriptor , command
*(unsigned int *)(stack_ioctl_return_E710) = sceNetSyscallIoctl_imp(stack_socket_fd_E4C4, 0x10007300, 0x0, 0x0);
while (1) {}
// ------------------------------------

lib_net_sceNetSyscallClose_imp(stack_var_E370);
lib_net_sceNetSyscallClose_imp(stack_var_E378);
lib_net_sceNetSyscallClose_imp(stack_var_E380);
lib_net_sceNetSyscallClose_imp(stack_var_E388);
lib_net_sceNetSyscallClose_imp(stack_var_E390);
lib_net_sceNetSyscallClose_imp(stack_var_E398);
lib_net_sceNetSyscallClose_imp(stack_var_E3A0);
lib_net_sceNetSyscallClose_imp(stack_var_E3A8);
lib_net_sceNetSyscallClose_imp(stack_var_E3B0);
lib_net_sceNetSyscallClose_imp(stack_var_E3B8);
lib_net_sceNetSyscallClose_imp(stack_var_E3C0);
lib_net_sceNetSyscallClose_imp(stack_var_E3C8);
lib_net_sceNetSyscallClose_imp(stack_var_E3D0);
lib_net_sceNetSyscallClose_imp(stack_var_E3D8);
lib_net_sceNetSyscallClose_imp(stack_var_E3E0);
lib_net_sceNetSyscallClose_imp(stack_var_E3E8);
lib_net_sceNetSyscallClose_imp(stack_var_E400);
lib_net_sceNetSyscallClose_imp(stack_var_E408);
lib_net_sceNetSyscallClose_imp(stack_var_E400);
lib_net_sceNetSyscallClose_imp(stack_var_E408);
lib_net_sceNetSyscallClose_imp(stack_var_E410);
lib_net_sceNetSyscallClose_imp(stack_var_E418);
lib_net_sceNetSyscallClose_imp(stack_var_E420);
lib_net_sceNetSyscallClose_imp(stack_var_E428);
lib_net_sceNetSyscallClose_imp(stack_var_E430);
lib_net_sceNetSyscallClose_imp(stack_var_E438);
lib_net_sceNetSyscallClose_imp(stack_var_E440);
lib_net_sceNetSyscallClose_imp(stack_var_E448);
lib_net_sceNetSyscallClose_imp(stack_var_E450);
lib_net_sceNetSyscallClose_imp(stack_var_E458);
lib_net_sceNetSyscallClose_imp(stack_var_E460);
lib_net_sceNetSyscallClose_imp(stack_var_E468);
lib_net_sceNetSyscallClose_imp(stack_var_E470);
lib_net_sceNetSyscallClose_imp(stack_var_E478);
lib_net_sceNetSyscallClose_imp(stack_var_E480);
lib_net_sceNetSyscallClose_imp(stack_var_E488);
lib_net_sceNetSyscallClose_imp(stack_var_E490);
lib_net_sceNetSyscallClose_imp(stack_var_E498);
lib_net_sceNetSyscallClose_imp(stack_var_E4A0);
lib_net_sceNetSyscallClose_imp(stack_var_E4A8);
lib_net_sceNetSyscallClose_imp(stack_socket_fd_E4C4);

// send ROP + Code
lib_net_sceNetSyscallControl_imp(0x0, 0x30000000, stack_var_E740, 0xFC);
// trigger the exploit (heap-overflow, object ptr overwrite)
lib_net_sceNetSyscallDumpClose(stack_var_E4DC);
lib_http_delay_thread(0xF4240);

stack_ioctl_return_E710 = *(unsigned int *)(stack_ioctl_return_E710) + 0x83A00CF5;

/* --------------------------------------------------------------------
ROP code
r0 = 0x5000E710 <- sceNetSyscallIoctl_imp return value
r1 = 0x83A00CF5 <- sceWebKit address space

ldr r0, [r0] <- get return value
add r0, r0, r1 <- plus with sceWebKit address space (as an offset)
mov r8, r0 <- mov value to r8
adds r0, r7, #0 <- dummy
adds r1, r6, #0 <- dummy
mov r3, r8 <- mov to r3 (function ptr)
blx r3 <- jump to this region
*/ --------------------------------------------------------------------

*(stack_ioctl_return_E710 + 0x83AC0C0B)(0x0, r6, r7);

// close more dumps
for (i = 0x1770; i < 0x1790; i++)
lib_net_sceNetSyscallDumpClose_imp(i);
while (1) {}
}

At the first time, the code didn’t make any sense. The best way to understand what each part does is debugging and know well about the Vita’s security measures. Since the PS Vita firmware 2.xx it has Address Space Layout Randomize in both user-land and kernel. Therefore if you want to attack both user-land and kernel you need a way to know the base address, in the case of user-land it’s done by the webkit exploit, but in kernel ?
Here is the answer:

// sceIoOpen
lib_kernel_sceIoOpen("molecule0:", 0x0, 0x0);
// sceIoDevctl
// device, cmd, input, input_size, output, output_size
lib_kernel_sceIoDevctl("sdstor0:", 0x5, "xmc-lp-ign-userext", 0x14, stack_buff_CE34, 0x3FF);

The first time that I read it, it didn’t make any sense, first because we don’t have a “molecule0” device on PS Vita and second that I didn’t know anything about the SceIoDevCtl. I read the vitasdk and psp2sdk to give me a good base and decided to write a ROP code for my 1.50 Vita and test the Syscalls. After I ran it on my vita and dump the output we have this:

1

Kernel stack leak

Pay attention to the yellow highlight addresses, PS Vita uses in the most of time THUMB2 instructions, the possibles candidates to be kernel addresses are the values that end with odd values. Furthermore, we are leaking data from the kernel stack and is there where our registers (R0, R3, R4, LR […]) are stored. So an example would be the 0x00489E15.

This is our first kernel exploit, it’s used to defeat Kernel ASLR and to write our Kernel ROP chain. Moreover, after more debugging, I concluded that: The kernel stack leak only happens when the SceIoDevCtl has values on output length less than 0x400, it probably happens because the buffer is uninitialized when the values are less than 0x400, another important thing is that is necessary always call de SceIoOpen before, is that will fill our stack with the pointers.
Here a quote Yifan Lu quote about it after I explained to him what I did:

sceIoDevctl is the first kernel exploit: it leaks stack pointers to SceSysmem and the kernel stack. it basically copies uninitialized stack buffer from kernel stack to user stack

After it, the ROP code will create another ROP code that will be used by a thread called “pln”, this thread is very important to the exploit, here is the “pln” thread code:

lib_kernel_sceIoDevctl("sdstor0:", 0x5, "xmc-lp-ign-userext", stack_leaked_output_E854, stack_leaked_output_len_E858, stack_var_E85C)
lib_http_delay_thread(0xF4240)
lib_kernel_sceIoDevctl("sdstor0:", 0x5, stack_leaked_input_D344, stack_leaked_input_len_E86C, 0x0, 0x0)
while (1) {}

 

It starts doing a stack leak as before, but there is a difference now, after the stack leak the thread will sleep (delay_thread function), while the “pln” thread is sleeping, the main thread is writing the Kernel ROP, the Kernel ROP is done using leaked LR value from stack plus some offsets, after finish the Kernel ROP, the main thread will copy the ROP chain to “stack_offset + 0xD348” with size 0x300 bytes, after it, will copy to “stack_offset + 0xD644” with size 0x400 bytes from the code(but only part of it is used). Later, “pln” thread wake up and call another sceIoDevctl, the vulnerable syscall can also be used to copy data into the kernel stack, so now its used to send data (in this case, our ROP + native code encrypted) to the kernel. Furthermore the kernel does not clear the stack before returning, so our data stays in kernel memory. It’s necessary because the PS Vita Kernel has a security measure called SMAP (Supervisor Memory Access Prevention) and even with kernel code execution we couldn’t read our ROP from the user-land mapping, otherwise we would have a fault. Another important thing is that we need to create another thread to execute this code and not in the main thread, here an explanation of Yifan Lu about it:

the point of all the thread creation: we need a “plant thread” to inject data into kernel memory. if we do it on the main thread, syscalls would corrupt it, so we create a new thread, leak the stack base, inject the krop, and then make it sleep forever

Now we have prepared the whole environment to the kernel exploit, we need to trigger it.

The Kernel exploit is in the the module that handle the SceNet functions (it’s the SceNetPs). The exploit starts when we allocate a bunch of socket file descriptor using sceNetSyscallSocket. If you pay attention in the code there is one call that is different from the others, that is:

stack_socket_fd_E4C4 = lib_net_sceNetSyscallSocket("tst", SCE_NET_AF_INET, 0x7, 0x0);

This socket created uses a type different from the others, it’s type 0x7, I tried to read both Linux and netBSD source code and didn’t find any reference to these, Yifan Lu says this is related to how the exploit is triggered and is not Sony’s work. Anyway, after this, we have more allocation but now using SceNetSyscallDumpCreate and some of these dump filedescriptor are unallocated  (but not all, they are close 8 by 8, like stack_var_E4F4, stack_var_E4FC) using SceNetSyscallDumpClose. Now the ROP will start the another thread called “mhm”, this thread will use SceNetSyscallIoctl with the socket file descriptor with type 0x7. At this point my guess was that the Vita heap is deterministic and what is happening is that the heap layout being manipulated to get a proper environment to trigger the exploit. So I thought about what is the exploit. A stack smash overflow are very difficult because Vita has stack canaries, and we have a bunch of Socket and DumpCreate syscall that allocate stuff into the heap memory,  so now either we have a User-After-Free or Heap Overflow, in this case, our kernel exploit is the former, an UAF. What happened is that probably Sony screw up with the SceNetPs module and unallocated one of the file descriptor allocated, but we still have the reference, now everything we need do is manipulate the heap layout and use an object with a modified vptr pointing to our payload and finally trigger it when we run the object.
So as we already have the kernel ROP inside the kernel memory (because the SceIoDevCtl used before), everything we need do now is trigger the exploit, everything that we have after it is close the socket descriptor in heap and finally call the sceNetSyscallControll and the another sceNetSyscallDump close that is where we trigger the object vptr to our kernel ROP. An another important technical information is about the threads, they are used to a combination of race attack and UAF.

Now we finally have kernel code execution.

Stage3: Kernel ROP and Code

After trigger the object with modified vptr, we will have kernel code execution and the first thing that it will run is the ROP build with the leaked address. We can’t do much without a way of dump memory (a read-primitive in kernel would be welcome), but I tried to analyze it anyway. If you remember the second SceIoDevCtl in the “pln” thread will send our data to the kernel, but there is something interesting here. The first 0x300 bytes is the kernel ROP and the 0x100 bytes(and not 0x400) is the kernel native code encrypted. So the truth is that we have three parts in the stage 3, the first is the ROP, the second is the payload 1 that my guess is that the ROP will map memory and decrypt using AES-ECB algorithm (I will explain why this algorithm later) and run the payload1 and finally the payload 1 will load and decrypt the payload 2 that is where we probably have the kernel patchs and download the pkg and install.
So why it uses AES-ECB algorithm ? I did a Cryptanalysis in the two payload files, the first payload has the same key between the HENkaku versions, the only thing that change is the last 0x20 bytes of the file. Normally when you change any byte we will have a file very different in terms of structure using another AES-Mode(like CBC, CTR […]), but in our case we have it:

2

20 last bytes of payload 1(encrypted), probably payload2 key ?

Only the 0x20 last bytes changes, it happens because ECB divides the data in blocks and each blocks is encrypted by the key. We have more evidences if we look the payload stage2, there are many 0x10 bytes that repeat in the file in different places.  So, the only way to decrypt it is understand the kernel rop and to it, we would need kernel code exec.

So that is my explanation about Stage2, probably Yifan Lu and xyz will make a proper write up explaning in details how each part of the exploit works, everything I said here is my point of view, maybe there are mistakes, but I think it’s enough to understand what is happening with Stage2 and part of Stage3. That is all folks.

This entry was posted in ps vita. Bookmark the permalink.

16 Responses to HENkaku PS Vita CTF: Reverse Engineering

  1. PDG says:

    Thank you.-

  2. TheRealSlimShady says:

    awesome!

  3. Ayu says:

    I’m just a simple humble high-level programmer (information systems) but I enjoy the weird enlightenment I get when reading stuff like this. Maybe I should have started studying cryptanalysis and security penetration back then when I was starting.

    Anyway, nice work! 🙂

  4. Ryan StMarie says:

    What a fantastic write up. Kudos to you!

  5. ViRGE says:

    Admittedly some of this is over my head, but this was still a great read. Obviously Sony didn’t get this perfect, otherwise we wouldn’t have Henkaku, but overall the Vita looks like its security was very well thought out and Sony followed a number of best-practice suggestions.

    Though I am a bit surprised to hear that it didn’t have ASLR until FW 2.xx. Given its importance and how long it has been around, I would have thought it would be there since day 1. I expect that omission is part of what helped Team Molecule do their initial analysis to break in.

  6. Ground says:

    Very nice explanation and write up, especially about the ECB encryption ;). This almost gets me to buy a vita.

  7. Ushio_chan says:

    I hope i could understand this 🙁

  8. /hbg/ says:

    Both CTR and CBC mode would still look similar to your first example under the same key/IV/nonce. In CBC the blocks containing the changes and everyone after it would be different, but in CTR only the bytes that actually changed would be different. Since the number of bytes changed is unknown there is no way to distinguish between them.

    However, you are right that repeated blocks mean ECB in nearly every case.

  9. krimo says:

    wow congrats !

  10. m6mb3rtx says:

    Excellent article.

    I hope you will continue to work reversing the KROP + Code.

    http://yifan.lu/2016/08/28/yes-its-a-kernel-exploit/

    Congrats!

  11. Pingback: YifanLu: "Yes, it's a kernel exploit!", and more explanations about HENkaku - Wololo.net

  12. st4rk says:

    At the beginning I really thought that it would be AES-CTR or AES-CBC, but I found some evidences that it’s ECB :p

  13. st4rk says:

    Yes, ASLR(user-land and Kernel), NID Poisoning, Stack Canaries and other security measures were implemented later, so if you want to hack the PS Vita a good way is exploit old firmwares.

  14. dev/null says:

    Thank you for sharing.

  15. walmac says:

    Sorry for my ignorance but which dissasembler are you using? can you tell? Thanks

  16. st4rk says:

    IDA Pro: https://www.hex-rays.com/products/ida/

    No problem, you’re welcome : )

Leave a Reply

Your email address will not be published. Required fields are marked *