iosuhax successor (based on SALT iosuhax)
Notable additional features (see also: ios_process/source/config.h):
- de_Fuse support: Redirects all OTP reads to RAM. Requires minute_minute to patch in the data.
- Decrypted fw.img loading in IOSU.
- IOSU reloads passes through minute to make patching easier
- SEEPROM writes are disabled (for safety)
- redNAND MLC acceleration -- moves MLC cache (SCFM) to SLCCMPT
- Semihosting hooks -- print kprintf and syslogs to pico de_Fuse serial
- Disk drive disable (w/o SEEPROM writing)
USB_SHRINKSHIFT-- Allows having both the Wii U filesystem and a normal filesystem on a drive by shifting the Wii U portion after the MBRUSB_SEED_SWAP-- Override the SEEPROM USB key to allow easier system migration
Experimental/Unstable features:
- Loading
kernel.imgfrom sdcard
Warnings:
- redNAND formatting is incompatible with other implementations! use minute to format.
- If you have existing USB drives, keep
USB_SHRINKSHIFTset to 0 PRINT_FSAOPENis useful, but extremely slow- This is only tested on 5.5.x fw.imgs, I haven't ported to anything before that.
# Needed for plugins
export STROOPWAFEL_ROOT=$(pwd)
# wafel_core
make 00core.ipx
# plugin example
make -C wafel_plugin_example
Additional IOSU patches can be added trough plugins. A compiled plugin can be placed next to the wafel_core.ipx and it will be loaded by minute. Stroopwafel then calls two hooks in the plugin:
-
void kern_main()- runs before everything else in kernel mode. -
void mcp_main()- runs before MCP's main thread under MCP.
Both functions must return, but mcp_main() can spawn new threads.
A skeleton can be found here: wafel_plugin_example
A plugin can apply through several macros provided by stroopwafel in wafel/patch.h:
-
U32_PATCH_K(_addr, _val)overwrites the virtual address the provided 32bit value -
ASM_PATCH_K(_addr, _str)Takes a string containing assembly, assembles it at compile time and copies the binary at runtime at the given address. You can't do relative reference symbols outside the assembly string. -
ASM_T_PATCH_K(_addr, _str)same asASM_PATCH_K(_addr, _str)but for thumb -
BL_TRAMPOLINE_K(_addr, _dst)generates a relativeBLat the address to dst. You can't use that to jump to code in your plugin - the branch would be too far. -
BL_T_TRAMPOLINE_K(_addr, _dst)same asBL_TRAMPOLINE_K(_addr, _dst)but for thumb -
BRANCH_PATCH_K(_addr, _dst)generates a relativeBat the address to dst. You can't use that to jump to code in your plugin - the branch would be too far.
Stroopwafel provides two ways to hook into IOSU to call your C or asm code. The functions and structs are declared in wafel/trampoline.h
void trampoline_hook_before(uintptr_t addr, void *target)Creates a trampoline and aBLat address to call it. The trampoline will push all GP registers, call your function supplied intarget, after your function is finished it will restore the registers and execute the orginal instruction that was overwritten. Since aBLis used to branch to the trampoline, the originalLRwill be overwritten. The orignal instruction is not allowed to usePCrelative addressing, as that would be off. The only exception to this is aBL, in that case it will branch to the originalBLtarget instead. The called function receives a pointer to atrampoline_statestruct, which allows it to read and modify the register state that will be restored after the function finishes.void trampoline_t_hook_before(uintptr_t addr, void *target)Same as the previous, but for thumb. The only difference is that two instructions will be overwritten, since thumb instructions are 2 bytes, but theBLwill take 4. Both instructions will be relocated to the trampoline. The called function receives a pointer to atrampoline_t_statevoid trampoline_blreplace(uintptr_t addr, void *target)Replaces aBLfunction call. The new target function intargetreceives the first four original arguments (in r0-r3) in their original position, the fith argument is a pointer to the originalBLtarget, the sixth is the savedLR(artifact of how the trampoline works) and after that the other original arguments (on the stack) follow. You can descide if, where and whith what argument's you call the original target function using the supplied pointer.void trampoline_t_blreplace(uintptr_t addr, void *target)Same as before, but for thumbvoid trampoline_blreplace_with_regs(uintptr_t addr, void *target)Same astrampoline_blreplacebut also pushesr4-r12on the stack, so they are available as arguments. The signature of the target function looks like this:int ums_sync_hook(int r0, int r1, int r2, r3, int r4, int r5, int r6, int r7, int r8, int r9, int r10, int r11, int r12, int *(org_func)(int,..), const void *lr, int stack_arg1, ...)void trampoline_t_blreplace_with_regs(uintptr_t addr, void *target)Same astrampoline_t_blreplacebut also pushesr4-r7on the stack, so they are available as arguments. The signature of the target function looks like this:int ums_sync_hook(int r0, int r1, int r2, r3, int r4, int r5, int r6, int r7, int *(org_func)(int,..), const void *lr, int stack_arg1, ...)
These trampolines support hooking the same address multiple times. With the blreplace the replacement function is responsible to call the previous function via the supplied pointer to not break the chain.
A demo of the trampolines can be found here: wafel_trampoline_demo/source/main.c at main · jan-hofmeier/wafel_trampoline_demo · GitHub
Stroopwafel provides a custom IPC interface via the /dev/stroopwafel device, allowing user-land applications to interact with the IOS kernel. This interface supports memory operations, code execution, and more.
For a convenient wrapper to interact with this interface, see libstroopwafel.
Detailed technical information about the IPC commands and structures can be found in IPC.md.
stroopwafel operates similar to (and is based on) SaltyNX: Instead of jumping to the reset handler at 0xFFFF0000, code execution is redirected to wafel_core. wafel_core patches the IOS kernel, modules, and segments, and then jumps to 0xFFFF0000. The memory for stroopwafel plugins is taken from the end of the 128MiB ramdisk at 0x20000000. Specifics on bootstrapping can be found here.
Plugins are mapped to all IOS modules, to allow for code patching and function replacement. Additional MMU mappings are also added to allow for single-instruction B/BL trampolines. All plugins are PIE and relocate themselves once on startup. Additionally, plugins may resolve symbols from other plugins. wafel_core provides several base APIs for patching and symbol lookup.
wafel_core currently provides all of the previously mentioned features (redNAND, semihosting, wupserver, etc).
- smealum for the original iosuhax
- WulfyStylez and Dazzozo for many of the SALT iosuhax patches