From c86808e911bed216575d8bb83103bbafffd49178 Mon Sep 17 00:00:00 2001 From: Naim2000 Date: Wed, 12 Feb 2025 21:28:36 -0500 Subject: [PATCH] work in progress --- Makefile | 6 +- data/{background => background.png} | Bin include/wiilight.h | 3 + source/fileops.c | 17 +- source/globals.h | 28 +- source/gui.c | 89 ++--- source/gui.h | 11 +- source/iospatch.c | 234 +++++++---- source/iospatch.h | 16 +- source/malloc.h | 11 - source/menu.c | 390 +++++++++--------- source/menu.h | 3 + source/mini_seeprom.c | 267 ------------- source/mini_seeprom.h | 59 --- source/nand.c | 10 +- source/nand.h | 2 + source/otp.c | 67 ---- source/otp.h | 29 -- source/stub.S | 6 - source/sys.c | 135 +++---- source/sys.h | 10 +- source/title.c | 185 ++++----- source/title.h | 19 +- source/utils.h | 17 +- source/video.c | 34 +- source/video.h | 12 +- source/wad-manager.c | 323 +++++++-------- source/wad.c | 590 ++++++++++++---------------- source/wkb.c | 2 + source/wkb.h | 4 - 30 files changed, 993 insertions(+), 1586 deletions(-) rename data/{background => background.png} (100%) delete mode 100644 source/malloc.h delete mode 100644 source/mini_seeprom.c delete mode 100644 source/mini_seeprom.h delete mode 100644 source/otp.c delete mode 100644 source/otp.h delete mode 100644 source/stub.S diff --git a/Makefile b/Makefile index c4985d4..34ded2e 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ INCLUDES := # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -Os -Wall $(MACHDEP) $(INCLUDE) +CFLAGS = -g -Os -Wall $(MACHDEP) $(INCLUDE) CXXFLAGS = $(CFLAGS) LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map @@ -128,9 +128,9 @@ $(OUTPUT).dol: $(OUTPUT).elf $(OUTPUT).elf: $(OFILES) #--------------------------------------------------------------------------------- -# This rule links in binary data with the .jpg extension +# This rule links in binary data with the .png extension #--------------------------------------------------------------------------------- -%.jpg.o : %.jpg +%.png.o : %.png #--------------------------------------------------------------------------------- @echo $(notdir $<) $(bin2o) diff --git a/data/background b/data/background.png similarity index 100% rename from data/background rename to data/background.png diff --git a/include/wiilight.h b/include/wiilight.h index aaaec6a..800dca7 100644 --- a/include/wiilight.h +++ b/include/wiilight.h @@ -1,3 +1,6 @@ +#define WII_LIGHT_OFF 0 +#define WII_LIGHT_ON 1 + void WIILIGHT_Init(); void WIILIGHT_TurnOn(); int WIILIGHT_GetLevel(); diff --git a/source/fileops.c b/source/fileops.c index ea43a50..f078983 100644 --- a/source/fileops.c +++ b/source/fileops.c @@ -1,23 +1,25 @@ #include #include +#include #include "fileops.h" -#include "malloc.h" - -static struct stat st; +#include "utils.h" bool FSOPFileExists(const char* file) { + struct stat st; return !stat(file, &st) && !S_ISDIR(st.st_mode); } bool FSOPFolderExists(const char* path) { + struct stat st; return !stat(path, &st) && S_ISDIR(st.st_mode); } size_t FSOPGetFileSizeBytes(const char* path) { + struct stat st; if (stat(path, &st) < 0) return 0; return st.st_size; @@ -56,17 +58,20 @@ void FSOPMakeFolder(const char* path) s32 FSOPReadOpenFile(FILE* fp, void* buffer, u32 offset, u32 length) { fseek(fp, offset, SEEK_SET); - return fread(buffer, length, 1, fp); + if (!fread(buffer, length, 1, fp)) + return -errno ?: -1; + + return 0; } s32 FSOPReadOpenFileA(FILE* fp, void** buffer, u32 offset, u32 length) { *buffer = memalign32(length); if (!*buffer) - return -1; + return -ENOMEM; s32 ret = FSOPReadOpenFile(fp, *buffer, offset, length); - if (ret <= 0) + if (ret < 0) { free(*buffer); *buffer = NULL; diff --git a/source/globals.h b/source/globals.h index 2464b2d..47d7159 100644 --- a/source/globals.h +++ b/source/globals.h @@ -3,12 +3,10 @@ // Constants #define CIOS_VERSION 249 -#define ENTRIES_PER_PAGE 12 #define MAX_FILE_PATH_LEN 1024 -#define WAD_DIRECTORY "/" -#define WAD_ROOT_DIRECTORY "/wad/" +#define DEFAULT_WAD_DIRECTORY "/wad/" -#define MAX_PASSWORD_LENGTH 10 +#define MAX_PASSWORD_LENGTH 16 #define MAX_FAT_DEVICE_LENGTH 10 #define MAX_NAND_DEVICE_LENGTH 10 @@ -19,27 +17,23 @@ #define NAND_DEVICE_INDEX_INVALID -1 #define CIOS_VERSION_INVALID -1 -// For the WiiLight -#define WII_LIGHT_OFF 0 -#define WII_LIGHT_ON 1 - -typedef struct +typedef struct wm_config { char password[MAX_PASSWORD_LENGTH]; - char startupPath [256]; - int cIOSVersion; - int fatDeviceIndex; - int nandDeviceIndex; + char startupPath[256]; + int cIOSVersion; + int fatDeviceIndex; + int nandDeviceIndex; +/* const char *smbuser; const char *smbpassword; const char *share; const char *ip; -} CONFIG; +*/ +} CONFIG, wm_config_t; -extern CONFIG gConfig; -extern nandDevice ndevList[]; -//extern fatDevice fdevList[]; +extern wm_config_t gConfig; #endif diff --git a/source/gui.c b/source/gui.c index 1ae76a4..6558f81 100644 --- a/source/gui.c +++ b/source/gui.c @@ -2,80 +2,61 @@ #include #include +#include "gui.h" #include "video.h" -#include "fat.h" -#include "menu.h" -#include "nand.h" +#include "pngu.h" #include "globals.h" -#include "fileops.h" + +#include "background_png.h" /* Constants */ -#define CONSOLE_XCOORD 70 -#define CONSOLE_YCOORD 114 -#define CONSOLE_WIDTH 502 -#define CONSOLE_HEIGHT 300 +static const GuiWindow s_defaultBackgroundData = { + .pngData = background_png, + .pngTarget = { 0, 0 }, -s32 __Gui_DrawPng(void *img, u32 x, u32 y) + .consoleTarget = { 70, 114 }, + .consoleWidth = 502, + .consoleHeight = 300, + + // .consoleTarget = { 32, 32 }, + // .consoleWidth = 640 - 64, + // .consoleHeight = 480 - 64, +}; + +s32 Gui_InitConsole(const GuiWindow *window) { + s32 ret = 0; IMGCTX ctx = NULL; PNGUPROP imgProp; - char path[1024]; - s32 ret = -1; - s32 i; - for (i = 0; i < FatGetDeviceCount(); i++) - { - snprintf(path, sizeof(path), "%s:%s", FatGetDevicePrefix(i), WM_BACKGROUND_PATH); - if (FSOPFileExists(path)) - { - ctx = PNGU_SelectImageFromDevice(path); - break; - } - - } + if (!window) + window = &s_defaultBackgroundData; - if(!ctx) + if (window->pngData) { /* Select PNG data */ - ctx = PNGU_SelectImageFromBuffer(img); - if (!ctx) { - ret = -1; + ctx = PNGU_SelectImageFromBuffer(window->pngData); + if (!ctx) + return -12; + + /* Get image properties */ + ret = PNGU_GetImageProperties(ctx, &imgProp); + if (ret != PNGU_OK) goto out; - } - } - - /* Get image properties */ - ret = PNGU_GetImageProperties(ctx, &imgProp); - if (ret != PNGU_OK) { - ret = -1; - goto out; + + /* Draw image */ + Video_DrawPng(ctx, imgProp, window->pngTarget.x, window->pngTarget.y); } - /* Draw image */ - Video_DrawPng(ctx, imgProp, x, y); - /* Success */ - ret = 0; + /* Initialize console */ + Con_Init(window->consoleTarget.x, window->consoleTarget.y, window->consoleWidth, window->consoleHeight); + // Con_Init(32, 32, 640 - 64, 480 - 64); out: /* Free memory */ if (ctx) PNGU_ReleaseImageContext(ctx); - return ret; + return -ret; } - - -void Gui_InitConsole(void) -{ - /* Initialize console */ - Con_Init(CONSOLE_XCOORD, CONSOLE_YCOORD, CONSOLE_WIDTH, CONSOLE_HEIGHT); -} - -void Gui_DrawBackground(void) -{ - extern char bgData[]; - - /* Draw background */ - __Gui_DrawPng(bgData, 0, 0); -} diff --git a/source/gui.h b/source/gui.h index 80f174c..f2a1028 100644 --- a/source/gui.h +++ b/source/gui.h @@ -1,8 +1,15 @@ #ifndef _GUI_H_ #define _GUI_H_ +typedef struct { u16 x, y; } point; +typedef struct GuiWindow { + const void *pngData; + point pngTarget; + point consoleTarget; // top left + u16 consoleWidth, consoleHeight; +} GuiWindow; + /* Prototypes */ -void Gui_InitConsole(void); -void Gui_DrawBackground(void); +s32 Gui_InitConsole(const GuiWindow *); #endif diff --git a/source/iospatch.c b/source/iospatch.c index 4895266..a05e36d 100644 --- a/source/iospatch.c +++ b/source/iospatch.c @@ -10,71 +10,89 @@ // Copyright 2010 Joseph Jordan // Wii U vWii patches Copyright 2012/2013 damysteryman - -#include -#include -#include +/* memmem says hi */ +#define _GNU_SOURCE #include +#include +#include #include "iospatch.h" +#include "sys.h" #define MEM_REG_BASE 0xd8b4000 #define MEM_PROT (MEM_REG_BASE + 0x20a) -static void disable_memory_protection() { - write32(MEM_PROT, read32(MEM_PROT) & 0x0000FFFF); +// I don't like hardcoding binary blobs like this either. We'll get serious later okay +static const u32 armCode[] = { + 0xE3A00536, /* mov r0, #0x0D800000 */ + 0xE5901060, /* ldr r1, [r0, #0x60] */ + 0xE3811008, /* orr r1, #0x08 */ + 0xE5801060, /* str r1, [r0, #0x60] */ + 0xE5901064, /* ldr r1, [r0, #0x64] */ + 0xE381113A, /* orr r1, #0x8000000E */ + 0xE3811EDF, /* orr r1, #0x00000DF0 */ + 0xE5801064, /* str r1, [r0, #0x64] */ + 0xE12FFF1E, /* bx lr */ +}; + +/* + * https://github.com/WiiLink24/wfc-patcher-wii/blob/main/launcher/source/IOS.cpp#L168-L171 + */ +int do_sha_exploit(u32 addr) { + int ret; + int fd = 0x10001; + ioctlv vecs[3] ATTRIBUTE_ALIGN(0x20) = {}; + + vecs[0].data = NULL; + vecs[0].len = 0; + vecs[1].data = (void *)0xFFFE0028; + vecs[1].len = 0; + + u32 *mem1 = (u32 *)0x80000000; + *mem1++ = 0x4903468D; + *mem1++ = 0x49034788; + *mem1++ = 0x49036209; + *mem1++ = 0x47080000; + *mem1++ = 0x10100000; + *mem1++ = MEM_VIRTUAL_TO_PHYSICAL(addr); + *mem1++ = 0xFFFF0014; + + vecs[2].data = mem1; + vecs[2].len = 0x20; + + ret = IOS_Ioctlv(fd, 0, 1, 2, vecs); + + return ret; } -static u32 apply_patch(char *name, const u8 *old, u32 old_size, const u8 *patch, u32 patch_size, u32 patch_offset) { - u8 *ptr_start = (u8*)*((u32*)0x80003134), *ptr_end = (u8*)0x94000000; - u32 found = 0; -// printf(" Patching %-30s", name); - u8 *location = NULL; - while (ptr_start < (ptr_end - patch_size)) { - if (!memcmp(ptr_start, old, old_size)) { - found++; - location = ptr_start + patch_offset; - u8 *start = location; - u32 i; - for (i = 0; i < patch_size; i++) { - *location++ = patch[i]; - } - DCFlushRange((u8 *)(((u32)start) >> 5 << 5), (patch_size >> 5 << 5) + 64); - ICInvalidateRange((u8 *)(((u32)start) >> 5 << 5), (patch_size >> 5 << 5) + 64); - } - ptr_start++; +static u32 apply_patch(const void *old, u32 old_size, const void *patch, u32 patch_size, u32 patch_offset) { + void *ptr_start = (void *)0x933E0000; + void *ptr_end = (void *)0x94000000; + u32 found; + + for (found = 0; ptr_start < ptr_end; found++) { + ptr_start = memmem(ptr_start, ptr_end - ptr_start, old, old_size); + if (!ptr_start) + break; + + memcpy(ptr_start + patch_offset, patch, patch_size); + DCFlushRange(ptr_start + patch_offset, patch_size); + ptr_start += patch_offset + patch_size; } -// if (found) -// printf(" patched\n"); -// else -// printf(" not patched\n"); + return found; } -/* -static const u8 di_readlimit_old[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0A, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x7E, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 -}; -static const u8 di_readlimit_patch[] = { 0x7e, 0xd4 }; -const u8 isfs_permissions_old[] = { 0x42, 0x8B, 0xD0, 0x01, 0x25, 0x66 }; -const u8 isfs_permissions_patch[] = { 0x42, 0x8B, 0xE0, 0x01, 0x25, 0x66 }; -static const u8 setuid_old[] = { 0xD1, 0x2A, 0x1C, 0x39 }; -static const u8 setuid_patch[] = { 0x46, 0xC0 }; -const u8 es_identify_old[] = { 0x28, 0x03, 0xD1, 0x23 }; -const u8 es_identify_patch[] = { 0x00, 0x00 };*/ -const u8 hash_old[] = { 0x20, 0x07, 0x23, 0xA2 }; -const u8 hash_patch[] = { 0x00 }; -const u8 new_hash_old[] = { 0x20, 0x07, 0x4B, 0x0B }; -const u8 es_set_ahbprot_old[] = { 0x68, 0x5B, 0x22, 0xEC, 0x00, 0x52, 0x18, 0x9B, 0x68, 0x1B, 0x46, 0x98, 0x07, 0xDB }; -const u8 es_set_ahbprot_patch[] = { 0x01 }; -const u8 ES_TitleVersionCheck_old[] = { 0xD2, 0x01, 0x4E, 0x56 }; +const u8 ES_TitleVersionCheck_old[] = { 0xD2, 0x01, 0x4E, 0x56 }; const u8 ES_TitleVersionCheck_patch[] = { 0xE0, 0x01, 0x4E, 0x56 }; -const u8 ES_TitleDeleteCheck_old[] = { 0xD8, 0x00, 0x4A, 0x04 }; + +const u8 ES_TitleDeleteCheck_old[] = { 0xD8, 0x00, 0x4A, 0x04 }; const u8 ES_TitleDeleteCheck_patch[] = { 0xE0, 0x00, 0x4A, 0x04 }; -const u8 isfs_permissions_old[] = { 0x9B, 0x05, 0x40, 0x03, 0x99, 0x05, 0x42, 0x8B, }; + +const u16 ES_KeyslotPermissionCheck_old[] = { 0x2d06, 0xd000, 0x4803 }; +const u16 ES_KeyslotPermissionCheck_patch[] = { 0x2d06, 0xe000, 0x4803 }; + +const u8 isfs_permissions_old[] = { 0x9B, 0x05, 0x40, 0x03, 0x99, 0x05, 0x42, 0x8B, }; const u8 isfs_permissions_patch[] = { 0x9B, 0x05, 0x40, 0x03, 0x1C, 0x0B, 0x42, 0x8B, }; //Following patches made my damysteryman for use with Wii U's vWii @@ -85,34 +103,102 @@ const u8 Kill_AntiSysTitleInstallv3_pt2_patch[] = { 0x46, 0xC0, 0x33, 0x06, 0x42 const u8 Kill_AntiSysTitleInstallv3_pt3_old[] = { 0x68, 0xFB, 0x2B, 0x00, 0xDB, 0x01 }; const u8 Kill_AntiSysTitleInstallv3_pt3_patch[] = { 0x68, 0xFB, 0x2B, 0x00, 0xDB, 0x10 }; -u32 IOSPATCH_AHBPROT() { - if (AHBPROT_DISABLED) { - write32(MEM_PROT, read32(MEM_PROT) & 0x0000FFFF); - //return apply_patch("set_ahbprot", check_tmd_old, sizeof(check_tmd_old), check_tmd_patch, sizeof(check_tmd_patch), 6); - return apply_patch("es_set_ahbprot", es_set_ahbprot_old, sizeof(es_set_ahbprot_old), es_set_ahbprot_patch, sizeof(es_set_ahbprot_patch), 25); +static inline bool validJumptablePtr(uint32_t x) { + return (x >= 0xFFFF0040) && (x < 0xFFFFF000) && ((x & 3) == 0); +} + +#define SRAMNOMIRR(x) (x - 0xF2B00000) +static u32 findTheSyscallTable(void) { + u32 undfInstruction = read32(0xD4F0004); + if ((undfInstruction & 0xFFFFF000) != 0xE59FF000 /* ldr pc, [pc, something] */) + // SRNPROT is probably on + return 0; + + u32 undfHandler = read32(0xD4F0004 + 8 /* pc is 2 steps ahead */ + (undfInstruction & 0xFFF)); + if (!validJumptablePtr(undfHandler)) + // Eh? + return 0; + + undfHandler = SRAMNOMIRR(undfHandler); + + // arbitrary number. don't plan to go far + for (int i = 0; i < 0x80; i += 4) { + undfInstruction = read32(undfHandler + i); + if ((undfInstruction & 0xFFFF0000) == 0xE59F0000) { // find the first thing loaded relative to PC + u32 addr = undfHandler + i + 8 + (undfInstruction & 0xFFF); + // syscall instr mask stack args cnt map the actual syscall table (they are right next to each other) + if (read32(addr) == 0xE6000010 && (read32(addr + 4) - read32(addr + 8)) < 0x400) { // this 0x400 (1024) is from the & 0xFF applied to the syscall # after it gets unmasked + return SRAMNOMIRR(read32(addr + 8)); // the actual syscall table wooooooooo yeahh babyy + } + } } + return 0; } -u32 IOSPATCH_Apply() { - u32 count = 0; - if (AHBPROT_DISABLED) { - disable_memory_protection(); - //count += apply_patch("di_readlimit", di_readlimit_old, sizeof(di_readlimit_old), di_readlimit_patch, sizeof(di_readlimit_patch), 12); - count += apply_patch("isfs_permissions", isfs_permissions_old, sizeof(isfs_permissions_old), isfs_permissions_patch, sizeof(isfs_permissions_patch), 0); - //count += apply_patch("es_setuid", setuid_old, sizeof(setuid_old), setuid_patch, sizeof(setuid_patch), 0); - //count += apply_patch("es_identify", es_identify_old, sizeof(es_identify_old), es_identify_patch, sizeof(es_identify_patch), 2); - count += apply_patch("hash_check", hash_old, sizeof(hash_old), hash_patch, sizeof(hash_patch), 1); - count += apply_patch("new_hash_check", new_hash_old, sizeof(new_hash_old), hash_patch, sizeof(hash_patch), 1); - count += apply_patch("ES_TitleVersionCheck", ES_TitleVersionCheck_old, sizeof(ES_TitleVersionCheck_old), ES_TitleVersionCheck_patch, sizeof(ES_TitleVersionCheck_patch), 0); - count += apply_patch("ES_TitleDeleteCheck", ES_TitleDeleteCheck_old, sizeof(ES_TitleDeleteCheck_old), ES_TitleDeleteCheck_patch, sizeof(ES_TitleDeleteCheck_patch), 0); +u32 *ptr_syscallTable = NULL; +u32 ptr_IOSC_VerifyPublicKeySign = 0; +static const u16 return0[] = { + 0x2000, // mov r0, #0 + 0x4770, // bx lr +}; - if((*(vu16*)0xCD8005A0 == 0xCAFE)) - { - count += apply_patch("Kill_AntiSysTitleInstallv3_pt1", Kill_AntiSysTitleInstallv3_pt1_old, sizeof(Kill_AntiSysTitleInstallv3_pt1_old), Kill_AntiSysTitleInstallv3_pt1_patch, sizeof(Kill_AntiSysTitleInstallv3_pt1_patch), 0); - count += apply_patch("Kill_AntiSysTitleInstallv3_pt2", Kill_AntiSysTitleInstallv3_pt2_old, sizeof(Kill_AntiSysTitleInstallv3_pt2_old), Kill_AntiSysTitleInstallv3_pt2_patch, sizeof(Kill_AntiSysTitleInstallv3_pt2_patch), 0); - count += apply_patch("Kill_AntiSysTitleInstallv3_pt3", Kill_AntiSysTitleInstallv3_pt3_old, sizeof(Kill_AntiSysTitleInstallv3_pt3_old), Kill_AntiSysTitleInstallv3_pt3_patch, sizeof(Kill_AntiSysTitleInstallv3_pt3_patch), 0); - } +int IOSPATCH_Apply(void) { + int fd = IOS_Open("/dev/dolphin", 0); + IOS_Close(fd); + if (fd >= 0) + return 0; + + int ret = fd = IOS_Open("/dev/sha", 0); + IOS_Close(fd); + if (ret < 0) + return (ret == IPC_ENOENT) ? 0 : ret; + + + ret = do_sha_exploit((u32)armCode); + + if (ret < 0) + return ret; + + int clock = 1000; + while (!AHBPROT_DISABLED) { + if (clock-- == 0) + return -0x123; + + usleep(1000); } - return count; + + ptr_syscallTable = (u32 *)findTheSyscallTable(); + if (!ptr_syscallTable) + return -0x105C; + + ptr_IOSC_VerifyPublicKeySign = read32((u32)&ptr_syscallTable[0x6C]); + + write16(MEM_PROT, 0); + + IOSPATCH_SetSignatureChecks(false); + // apply_patch(hash_old, sizeof(hash_old), hash_patch, sizeof(hash_patch), 1); + // apply_patch(new_hash_old, sizeof(new_hash_old), hash_patch, sizeof(hash_patch), 1); + apply_patch(isfs_permissions_old, sizeof(isfs_permissions_old), isfs_permissions_patch, sizeof(isfs_permissions_patch), 0); + apply_patch(ES_TitleVersionCheck_old, sizeof(ES_TitleVersionCheck_old), ES_TitleVersionCheck_patch, sizeof(ES_TitleVersionCheck_patch), 0); + apply_patch(ES_TitleDeleteCheck_old, sizeof(ES_TitleDeleteCheck_old), ES_TitleDeleteCheck_patch, sizeof(ES_TitleDeleteCheck_patch), 0); + apply_patch(ES_KeyslotPermissionCheck_old, sizeof(ES_KeyslotPermissionCheck_old), ES_KeyslotPermissionCheck_patch, sizeof(ES_KeyslotPermissionCheck_patch), 0); + + if (IS_WIIU) + { + apply_patch(Kill_AntiSysTitleInstallv3_pt1_old, sizeof(Kill_AntiSysTitleInstallv3_pt1_old), Kill_AntiSysTitleInstallv3_pt1_patch, sizeof(Kill_AntiSysTitleInstallv3_pt1_patch), 0); + apply_patch(Kill_AntiSysTitleInstallv3_pt2_old, sizeof(Kill_AntiSysTitleInstallv3_pt2_old), Kill_AntiSysTitleInstallv3_pt2_patch, sizeof(Kill_AntiSysTitleInstallv3_pt2_patch), 0); + apply_patch(Kill_AntiSysTitleInstallv3_pt3_old, sizeof(Kill_AntiSysTitleInstallv3_pt3_old), Kill_AntiSysTitleInstallv3_pt3_patch, sizeof(Kill_AntiSysTitleInstallv3_pt3_patch), 0); + } + + return 0; +} + +void IOSPATCH_SetSignatureChecks(bool enable) +{ + if (!ptr_syscallTable) + return; + + u32 new = enable ? ptr_IOSC_VerifyPublicKeySign : (MEM_VIRTUAL_TO_PHYSICAL(return0) | 0x1); + write32((u32)&ptr_syscallTable[0x6C], new); } diff --git a/source/iospatch.h b/source/iospatch.h index 9adfdbc..0b0303f 100644 --- a/source/iospatch.h +++ b/source/iospatch.h @@ -13,20 +13,12 @@ #ifndef _IOSPATCH_H #define _IOSPATCH_H -#ifdef __cplusplus -extern "C" { -#endif -/* __cplusplus */ - #include +#include -#define AHBPROT_DISABLED ((*(vu32*)0xcd800064 == 0xFFFFFFFF) ? 1 : 0) +#define AHBPROT_DISABLED (read32(0xcd800064) != 0) -u32 IOSPATCH_AHBPROT(); -u32 IOSPATCH_Apply(); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +int IOSPATCH_Apply(); +void IOSPATCH_SetSignatureChecks(bool); #endif /* _IOSPATCH_H */ diff --git a/source/malloc.h b/source/malloc.h deleted file mode 100644 index 8a12a83..0000000 --- a/source/malloc.h +++ /dev/null @@ -1,11 +0,0 @@ -#include - -static inline void *memalign32(size_t size) -{ - return aligned_alloc(0x20, (size + 0x1F) & ~0x1F); -} - -static inline void *memalign64(size_t size) -{ - return aligned_alloc(0x40, (size + 0x3F) & ~0x3F); -} \ No newline at end of file diff --git a/source/menu.c b/source/menu.c index b9bbe64..ea8e2ab 100644 --- a/source/menu.c +++ b/source/menu.c @@ -25,28 +25,13 @@ #include "fileops.h" #include "menu.h" -/* NAND device list */ -nandDevice ndevList[] = -{ - { "Disable", 0, 0x00, 0x00 }, - { "SD/SDHC Card", 1, 0xF0, 0xF1 }, - { "USB 2.0 Mass Storage Device", 2, 0xF2, 0xF3 }, -}; - static nandDevice *ndev = NULL; - static int gSelected; static bool gNeedPriiloaderOption = false; /* Macros */ -#define NB_NAND_DEVICES (sizeof(ndevList) / sizeof(nandDevice)) - -// Local prototypes: wiiNinja -void WaitPrompt (char *prompt); -u32 WaitButtons(void); -u32 Pad_GetButtons(void); -void WiiLightControl (int state); +#define ENTRIES_PER_PAGE (g_consoleHeight - 5) void PriiloaderRetainedPrompt(void); @@ -68,10 +53,8 @@ static int __Menu_EntryCmp(const void *p1, const void *p2) fatFile *f2 = (fatFile *)p2; /* Compare entries */ // wiiNinja: Include directory - if ((f1->isdir) && !(f2->isdir)) - return (-1); - else if (!(f1->isdir) && (f2->isdir)) - return (1); + if (f1->isdir ^ f2->isdir) + return f2->isdir - f1->isdir; else return strcasecmp(f1->filename, f2->filename); } @@ -104,7 +87,7 @@ static s32 __Menu_RetrieveList(char *inPath, fatFile **outbuf, u32 *outlen) bool iswad = false; size_t fsize = 0; - /* Hide entries that start with "._". I hate macOS */ + /* Hide entries that start with "._". I hate macOS. */ if (!strncmp(ent->d_name, "._", 2)) continue; @@ -187,7 +170,7 @@ static s32 __Menu_RetrieveList(char *inPath, fatFile **outbuf, u32 *outlen) void Menu_SelectIOS(void) { - u8 *iosVersion = NULL; + u8 iosVersions[255] = {}; u32 iosCnt; u8 tmpVersion; @@ -196,12 +179,12 @@ void Menu_SelectIOS(void) bool found = false; /* Get IOS versions */ - ret = Title_GetIOSVersions(&iosVersion, &iosCnt); + ret = Title_GetIOSVersions(iosVersions, &iosCnt); if (ret < 0) return; /* Sort list */ - qsort(iosVersion, iosCnt, sizeof(u8), __Menu_IsGreater); + qsort(iosVersions, iosCnt, sizeof(u8), __Menu_IsGreater); if (gConfig.cIOSVersion < 0) { @@ -218,7 +201,7 @@ void Menu_SelectIOS(void) /* Set default version */ for (cnt = 0; cnt < iosCnt; cnt++) { - u8 version = iosVersion[cnt]; + u8 version = iosVersions[cnt]; /* Custom IOS available */ //if (version == CIOS_VERSION) @@ -242,7 +225,7 @@ void Menu_SelectIOS(void) /* Clear console */ Con_Clear(); - printf("\t>> Select IOS version to use: < IOS%d >\n\n", iosVersion[selected]); + printf("\t>> Select IOS version to use: < IOS%d >\n\n", iosVersions[selected]); printf("\t Press LEFT/RIGHT to change IOS version.\n\n"); @@ -271,7 +254,7 @@ void Menu_SelectIOS(void) } } - u8 version = iosVersion[selected]; + u8 version = iosVersions[selected]; if (IOS_GetVersion() != version) { /* Shutdown subsystems */ @@ -280,7 +263,7 @@ void Menu_SelectIOS(void) /* Load IOS */ - if (!loadIOS(version)) + if (Sys_LoadIOS(version) != 0) { Wpad_Init(); Menu_SelectIOS(); @@ -337,14 +320,18 @@ void Menu_FatDevice(void) * 0xcc - vertical conjuction to right */ - char horizontal[60]; + char horizontal[80]; memset(horizontal, 0xcd, sizeof(horizontal)); - printf(" \xc9%.59s\xbb", horizontal); - printf(" \xcc%.14sWelcome to YAWM ModMii Edition!%.14s\xb9", horizontal, horizontal); - printf(" \xc8%.59s\xbc", horizontal); +/* + printf("\xc9%.*s\xbb", g_consoleWidth - 2, horizontal); + //31 + printf("\xcc%.*sWelcome to YAWM ModMii Edition!%.*s\xb9", (g_consoleWidth - 33) / 2, horizontal, (g_consoleWidth - 32) / 2, horizontal); + printf("\xc8%.*s\xbc", g_consoleWidth - 2, horizontal); +*/ - printf(" Running on IOS%u v%u (AHB access %s)\n\n", iosVersion, iosRevision, AHBPROT_DISABLED ? "enabled" : "disabled"); + printf(" -== Welcome to YAWM ModMii Edition! ==-\n"); + printf(" Running on IOS%u v%u (%u.%u)\n\n", iosVersion, iosRevision, iosRevision >> 8, iosRevision & 0xFF); if (VersionIsOriginal(version)) printf(" System menu: %s%c %s\n", GetSysMenuVersionString(version), region ?: '?', GetSysMenuRegionString(region)); // The ? should not appear any more, but, in any case. @@ -476,10 +463,10 @@ void Menu_NandDevice(void) /* LEFT/RIGHT buttons */ if (buttons & WPAD_BUTTON_LEFT) { if ((--selected) <= -1) - selected = (NB_NAND_DEVICES - 1); + selected = (ndevCount - 1); } if (buttons & WPAD_BUTTON_RIGHT) { - if ((++selected) >= NB_NAND_DEVICES) + if ((++selected) >= ndevCount) selected = 0; } @@ -533,20 +520,30 @@ err: char gTmpFilePath[MAX_FILE_PATH_LEN]; /* Install and/or Uninstall multiple WADs - Leathl */ -int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath) +int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath, bool delete) { int installCnt = 0; int uninstallCnt = 0; - int count; + int wadcnt = 0; + int ret = 0; + fatFile* wads[fileCount]; for (fatFile* f = files; f < files + fileCount; f++) { - if (f->install == 1) installCnt++; else - if (f->install == 2) uninstallCnt++; + switch (f->install) { + case 1: + wads[wadcnt++] = f; + installCnt++; + break; + case 2: + wads[wadcnt++] = f; + uninstallCnt++; + break; + } } if (!(installCnt || uninstallCnt)) return 0; - +/* for (;;) { Con_Clear(); @@ -678,6 +675,139 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath) } } } +*/ + char *ptr_fname = gTmpFilePath + sprintf(gTmpFilePath, "%s/", inFilePath); + + int start = 0; // No cursor here so we just need start + while (true) + { + Con_Clear(); + + printf("[+] List of WADs to %sinstall%s:\n\n", uninstallCnt ? "(un)" : "", delete ? " and delete" : ""); + for (int i = 0; i < ENTRIES_PER_PAGE; i++) + { + int index = start + i; + if (index >= wadcnt) // Data store interrupt safety!! + putchar('\n'); + else + printf(" %c %.50s\n", " +-"[wads[index]->install], wads[index]->filename); + } + + putchar('\n'); + puts("[+] A: Continue UP/DOWN: Move list"); + puts(" B: Cancel -/R: Toggle deletion"); + + u32 buttons = WaitButtons(); + + if (buttons & WPAD_BUTTON_UP) + { + if (start) start--; + } + else if (buttons & WPAD_BUTTON_DOWN) + { + if (wadcnt - start > ENTRIES_PER_PAGE) start++; + } + else if (buttons & WPAD_BUTTON_A) + { + break; + } + else if (buttons & WPAD_BUTTON_B) + { + return 0; + } + else if (buttons & WPAD_BUTTON_MINUS) + { + delete ^= true; + } + } + + WiiLightControl(WII_LIGHT_ON); + + for (int i = 0; i < wadcnt; i++) + { + fatFile *f = wads[i]; + FILE *fp = NULL; + + Con_Clear(); + + printf("[+] Processing WAD %i/%i...\n\n", i + 1, wadcnt); + + printf("[+] Opening \"%s\", please wait... ", f->filename); + strcpy(ptr_fname, f->filename); + fp = fopen(gTmpFilePath, "rb"); + if (!fp) + { + printf("ERROR!\n"); + perror(" "); + f->installstate = ret = -996; + } + else + { + puts("OK!"); + printf(" >> %s WAD...\n", f->install == 1 ? "Installing" : "Uninstalling"); + f->installstate = ret = (f->install == 1 ? Wad_Install : Wad_Uninstall)(fp); + fclose(fp); + + if (!ret) + { + if (delete) + { + printf(" >> Deleting WAD... "); + // ret = FSOPDeleteFile(gTmpFilePath); + ret = remove(gTmpFilePath); + if (!ret) + puts("OK!"); + else + printf("ERROR! (errno=%i)\n", errno); + } + } else + + if (ret == -1010) + { + do { wads[i++]->installstate = -1010; } while (i < wadcnt); + WaitPrompt("Wii System Memory is full. Installation terminated...\n"); + break; + } + } + + usleep((!ret) ? 500000 : 4000000); + continue; + } + + start = 0; + while (true) + { + Con_Clear(); + + printf("[+] End results:\n\n"); + + for (int i = 0; i < ENTRIES_PER_PAGE; i++) + { + int index = start + i; + if (index >= wadcnt) // Data store interrupt safety!! + putchar('\n'); + else + printf(" %-.32s: %s\n", wads[index]->filename, wad_strerror(wads[index]->installstate)); + } + + putchar('\n'); + puts("[+] A: Continue UP/DOWN: Move list"); + + u32 buttons = WaitButtons(); + + if (buttons & WPAD_BUTTON_UP) + { + if (start) start--; + } + else if (buttons & WPAD_BUTTON_DOWN) + { + if (wadcnt - start > ENTRIES_PER_PAGE) start++; + } + else if (buttons & WPAD_BUTTON_A) + { + break; + } + } if (gNeedPriiloaderOption) { @@ -685,11 +815,6 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath) gNeedPriiloaderOption = false; } - else - { - printf("\n Press any button to continue...\n"); - WaitButtons(); - } return 1; } @@ -761,15 +886,11 @@ int Menu_FolderOperations(fatFile* file, char* path) { int ret; - char workpath[MAX_FILE_PATH_LEN]; - fatFile *flist = NULL; unsigned int fcnt = 0; unsigned int wadcnt = 0; - char* ptr_fname = workpath + sprintf(workpath, "%s%s/", path, file->filename); - - ret = __Menu_RetrieveList(workpath, &flist, &fcnt); + ret = __Menu_RetrieveList(path, &flist, &fcnt); if (ret != 0) { WaitPrompt("__Menu_RetrieveList failed"); @@ -802,6 +923,7 @@ int Menu_FolderOperations(fatFile* file, char* path) if (buttons & (WPAD_BUTTON_LEFT | WPAD_BUTTON_RIGHT)) mode ^= 1; + if (buttons & WPAD_BUTTON_A) break; @@ -815,128 +937,10 @@ int Menu_FolderOperations(fatFile* file, char* path) goto finish; } - int start = 0; // No cursor here so we just need start - while (true) - { - Con_Clear(); - - printf("[+] List of WADs to %s:\n\n", mode ? "install and delete" : "install"); - for (int i = 0; i < ENTRIES_PER_PAGE; i++) - { - int index = start + i; - if (index >= wadcnt) // Data store interrupt safety!! - putchar('\n'); - else - printf(" %.50s\n", wads[index]->filename); - } - - putchar('\n'); - printf("[+] Press UP/DOWN to move list.\n"); - printf(" Press A to continue.\n"); - printf(" Press B to cancel."); - - u32 buttons = WaitButtons(); - - if (buttons & WPAD_BUTTON_UP) - { - if (start) start--; - } - else if (buttons & WPAD_BUTTON_DOWN) - { - if (wadcnt - start > ENTRIES_PER_PAGE) start++; - } - else if (buttons & WPAD_BUTTON_A) - { - break; - } - else if (buttons & WPAD_BUTTON_B) - { - goto finish; - } - } - for (int i = 0; i < wadcnt; i++) - { - fatFile *f = wads[i]; - FILE *fp = NULL; + wads[i]->install = 1; - Con_Clear(); - - printf("[+] Processing WAD %i/%i...\n\n", i + 1, wadcnt); - - printf("[+] Opening \"%s\", please wait...\n", f->filename); - strcpy(ptr_fname, f->filename); - fp = fopen(workpath, "rb"); - if (!fp) - { - printf(" ERROR! (errno=%i)\n", errno); - } - else - { - // puts(">> Installing WAD..."); - f->installstate = ret = Wad_Install(fp); - fclose(fp); - - if (!ret) - { - if (mode == 1) - { - printf(">> Deleting WAD... "); - // ret = FSOPDeleteFile(workpath); - ret = remove(workpath); - if (!ret) - puts("OK!"); - else - printf("ERROR! (errno=%i)\n", errno); - } - } - else if (ret == -1010) - { - do { wads[i++]->installstate = -1010; } while (i < wadcnt); - WaitPrompt("Wii System Memory is full to the brim. Installation terminated...\n"); - break; - } - } - - usleep((!ret) ? 500000 : 4000000); - continue; - } - - start = 0; - while (true) - { - Con_Clear(); - - printf("[+] End results:\n\n"); - - for (int i = 0; i < ENTRIES_PER_PAGE; i++) - { - int index = start + i; - if (index >= wadcnt) // Data store interrupt safety!! - putchar('\n'); - else - printf(" %-.32s: %s\n", wads[index]->filename, wad_strerror(wads[index]->installstate)); - } - - putchar('\n'); - printf("[+] Press UP/DOWN to move list.\n"); - printf(" Press A to continue."); - - u32 buttons = WaitButtons(); - - if (buttons & WPAD_BUTTON_UP) - { - if (start) start--; - } - else if (buttons & WPAD_BUTTON_DOWN) - { - if (wadcnt - start > ENTRIES_PER_PAGE) start++; - } - else if (buttons & WPAD_BUTTON_A) - { - break; - } - } + Menu_BatchProcessWads(flist, fcnt, path, mode == 1); finish: free(flist); @@ -1085,7 +1089,7 @@ void Menu_WadList(void) fflush(stdout); // if user provides startup directory, try it out first - if (strcmp(gConfig.startupPath, WAD_DIRECTORY) != 0) + if (*gConfig.startupPath != '\0') { // replace root dir with provided startup directory sprintf(tmpPath, "%s:%s", FatGetDevicePrefix(gSelected), gConfig.startupPath); @@ -1098,7 +1102,7 @@ void Menu_WadList(void) goto getList; } - sprintf(tmpPath, "%s:%s", FatGetDevicePrefix(gSelected), WAD_DIRECTORY); + sprintf(tmpPath, "%s:/", FatGetDevicePrefix(gSelected)); /* Retrieve filelist */ getList: @@ -1155,23 +1159,25 @@ getList: if ((cnt - start) >= ENTRIES_PER_PAGE) break; - /* Print filename */ //printf("\t%2s %s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", file->filename, filesize); if (file->isdir) // wiiNinja { - printf("\t%2s [%.40s]\n", (cnt == selected) ? ">>" : " ", file->filename); + printf("\t%2s [%.*s]\n", (cnt == selected) ? ">>" : " ", g_consoleWidth - 7, file->filename); } else { if(file->iswad) - printf("\t%2s%c%.40s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", " +-"[file->install], file->filename, filesize); + printf("\t%2s%c%.*s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", " +-"[file->install], g_consoleWidth - 7, file->filename, filesize); else - printf("\t%2s %.40s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", file->filename, filesize); + printf("\t%2s %.*s (%.2f MB)\n", (cnt == selected) ? ">>" : " ", g_consoleWidth - 7, file->filename, filesize); } } - putchar('\n'); + while ((cnt++ - start) < ENTRIES_PER_PAGE) + putchar('\n'); + + putchar('\n'); // One more newline! fatFile *file = &fileList[selected]; // There is only one occurence of /, likely because we are at the root! bool atRoot = (strchr(tmpPath, '/') == strrchr(tmpPath, '/')); @@ -1197,8 +1203,9 @@ getList: operationA = "Enter directory"; // "[+] A: Install/Uninstall WAD" - printf("[+] A: %-23s" "B: %s\n", operationA, operationB); - printf(" 1/R: %-23s" "2/L: Enable batch mode", operationR); + unsigned somewidth = g_consoleWidth / 2; + printf("[+] A: %-*s" "B: %-*s\n", somewidth - 9, operationA, somewidth - 6, operationB); + printf(" 1/R: %-*s" "2/L: Enable batch mode", somewidth - 9, operationR); } @@ -1299,7 +1306,7 @@ getList: { if (batchMode) { - int res = Menu_BatchProcessWads(fileList, fileCnt, tmpPath); + int res = Menu_BatchProcessWads(fileList, fileCnt, tmpPath, false); if (res == 1) { @@ -1374,15 +1381,6 @@ err: void Menu_Loop(void) { u8 iosVersion; - if (AHBPROT_DISABLED) - { - IOSPATCH_Apply(); - } - else - { - /* Select IOS menu */ - Menu_SelectIOS(); - } /* Retrieve IOS version */ iosVersion = IOS_GetVersion(); @@ -1463,10 +1461,12 @@ char *PeekCurrentDir (void) } #endif -void WaitPrompt (char *prompt) +void WaitPrompt (const char *prompt) { - printf("\n%s", prompt); - printf(" Press any button to continue...\n"); + if (prompt) + printf("\n%s", prompt); + + printf(" Press any button to continue...\n"); /* Wait for button */ WaitButtons(); @@ -1633,10 +1633,10 @@ void WiiLightControl (int state) void PriiloaderRetainedPrompt(void) { - puts(" Priiloader has been retained, but all hacks were reset.\n"); + puts(" Priiloader has been retained, but all hacks were reset.\n"); - puts(" Press A launch Priiloader now."); - puts(" Press any other button to continue..."); + puts(" Press A launch Priiloader now."); + puts(" Press any other button to continue..."); u32 buttons = WaitButtons(); diff --git a/source/menu.h b/source/menu.h index 0cb95a2..0f53488 100644 --- a/source/menu.h +++ b/source/menu.h @@ -2,6 +2,9 @@ #define _MENU_H_ /* Prototypes */ +void WaitPrompt(const char *prompt); +u32 WaitButtons(void); +void WiiLightControl (int state); void Menu_Loop(void); void SetPriiloaderOption(bool enabled); bool MenuTestDevice(); diff --git a/source/mini_seeprom.c b/source/mini_seeprom.c deleted file mode 100644 index fa49bef..0000000 --- a/source/mini_seeprom.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - mini - a Free Software replacement for the Nintendo/BroadOn IOS. - SEEPROM support - -Copyright (C) 2008, 2009 Sven Peter -Copyright (C) 2008, 2009 Haxx Enterprises -Copyright (C) 2008, 2009 Hector Martin "marcan" -Copyright (C) 2008, 2009 John Kelley -Copyright (C) 2020 Pablo Curiel "DarkMatterCore" - -# This code is licensed to you under the terms of the GNU GPL, version 2; -# see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt -*/ - -#include -#include -#include - -#include "mini_seeprom.h" - -#define HW_REG_BASE 0xd800000 -#define HW_GPIO1OUT (HW_REG_BASE + 0x0e0) -#define HW_GPIO1IN (HW_REG_BASE + 0x0e8) - -#define HW_SEEPROM_BLK_SIZE 2 -#define HW_SEEPROM_BLK_CNT (SEEPROM_SIZE / HW_SEEPROM_BLK_SIZE) - -#define eeprom_delay() usleep(5) - -enum { - GP_EEP_CS = 0x000400, - GP_EEP_CLK = 0x000800, - GP_EEP_MOSI = 0x001000, - GP_EEP_MISO = 0x002000 -}; - -static void seeprom_send_bits(u16 value, u8 bits) -{ - if (!bits || bits > 16) return; - - while(bits--) - { - if (value & (1 << bits)) - { - mask32(HW_GPIO1OUT, 0, GP_EEP_MOSI); - } else { - mask32(HW_GPIO1OUT, GP_EEP_MOSI, 0); - } - - eeprom_delay(); - - mask32(HW_GPIO1OUT, 0, GP_EEP_CLK); - eeprom_delay(); - - mask32(HW_GPIO1OUT, GP_EEP_CLK, 0); - eeprom_delay(); - } -} - -static u16 seeprom_recv_bits(u8 bits) -{ - if (!bits || bits > 16) return 0; - - int res = 0; - - while(bits--) - { - res <<= 1; - - mask32(HW_GPIO1OUT, 0, GP_EEP_CLK); - eeprom_delay(); - - mask32(HW_GPIO1OUT, GP_EEP_CLK, 0); - eeprom_delay(); - - res |= !!(read32(HW_GPIO1IN) & GP_EEP_MISO); - } - - return (u16)res; -} - -u16 seeprom_read(void *dst, u16 offset, u16 size) -{ - /* - * WiiUBrew told me that you interact with the SEEPROM the exact same way you do on Wii. - * However the contents are way different. Like there's absolutely no vWii stuff here. - */ - if (read16(0xCD8005A0) == 0xCAFE) return 0; - - if (!dst || offset >= SEEPROM_SIZE || !size || (offset + size) > SEEPROM_SIZE) return 0; - - u16 cur_offset = 0; - - u8 *ptr = (u8*)dst; - u8 val[HW_SEEPROM_BLK_SIZE] = {0}; - - // Calculate block offsets and sizes - u8 start_addr = (u8)(offset / HW_SEEPROM_BLK_SIZE); - u8 start_addr_offset = (u8)(offset % HW_SEEPROM_BLK_SIZE); - - u8 end_addr = (u8)((offset + size) / HW_SEEPROM_BLK_SIZE); - u8 end_addr_size = (u8)((offset + size) % HW_SEEPROM_BLK_SIZE); - - if (!end_addr_size) - { - end_addr--; - end_addr_size = HW_SEEPROM_BLK_SIZE; - } - - if (end_addr == start_addr) end_addr_size -= start_addr_offset; - - mask32(HW_GPIO1OUT, GP_EEP_CLK, 0); - mask32(HW_GPIO1OUT, GP_EEP_CS, 0); - eeprom_delay(); - - for(u16 i = start_addr; i <= end_addr; i++) - { - if (cur_offset >= size) break; - - // Start command cycle - mask32(HW_GPIO1OUT, 0, GP_EEP_CS); - - // Send read command + address - seeprom_send_bits(0x600 | i, 11); - - // Receive data - *((u16*)val) = seeprom_recv_bits(16); - - // End of command cycle - mask32(HW_GPIO1OUT, GP_EEP_CS, 0); - eeprom_delay(); - - // Copy read data to destination buffer - if (i == start_addr && start_addr_offset != 0) - { - // Handle unaligned read at start address - memcpy(ptr + cur_offset, val + start_addr_offset, HW_SEEPROM_BLK_SIZE - start_addr_offset); - cur_offset += (HW_SEEPROM_BLK_SIZE - start_addr_offset); - } else - if (i == end_addr && end_addr_size != HW_SEEPROM_BLK_SIZE) - { - // Handle unaligned read at end address - memcpy(ptr + cur_offset, val, end_addr_size); - cur_offset += end_addr_size; - } else { - // Normal read - memcpy(ptr + cur_offset, val, HW_SEEPROM_BLK_SIZE); - cur_offset += HW_SEEPROM_BLK_SIZE; - } - } - - return cur_offset; -} - -#if 0 -u16 seeprom_write(const void *src, u16 offset, u16 size) -{ - if (!src || offset >= SEEPROM_SIZE || !size || (offset + size) > SEEPROM_SIZE) return 0; - - u32 level = 0; - u16 cur_offset = 0; - - const u8 *ptr = (const u8*)src; - u8 val[HW_SEEPROM_BLK_SIZE] = {0}; - - // Calculate block offsets and sizes - u8 start_addr = (u8)(offset / HW_SEEPROM_BLK_SIZE); - u8 start_addr_offset = (u8)(offset % HW_SEEPROM_BLK_SIZE); - - u8 end_addr = (u8)((offset + size) / HW_SEEPROM_BLK_SIZE); - u8 end_addr_size = (u8)((offset + size) % HW_SEEPROM_BLK_SIZE); - - if (!end_addr_size) - { - end_addr--; - end_addr_size = HW_SEEPROM_BLK_SIZE; - } - - if (end_addr == start_addr) end_addr_size -= start_addr_offset; - - // Disable CPU interruptions - _CPU_ISR_Disable(level); - - mask32(HW_GPIO1OUT, GP_EEP_CLK, 0); - mask32(HW_GPIO1OUT, GP_EEP_CS, 0); - eeprom_delay(); - - // EWEN - Enable programming commands - mask32(HW_GPIO1OUT, 0, GP_EEP_CS); - seeprom_send_bits(0x4FF, 11); - mask32(HW_GPIO1OUT, GP_EEP_CS, 0); - eeprom_delay(); - - for(u16 i = start_addr; i <= end_addr; i++) - { - if (cur_offset >= size) break; - - // Copy data to write from source buffer - if ((i == start_addr && start_addr_offset != 0) || (i == end_addr && end_addr_size != HW_SEEPROM_BLK_SIZE)) - { - // Read data from SEEPROM to handle unaligned writes - - // Start command cycle - mask32(HW_GPIO1OUT, 0, GP_EEP_CS); - - // Send read command + address - seeprom_send_bits(0x600 | i, 11); - - // Receive data - *((u16*)val) = seeprom_recv_bits(16); - - // End of command cycle - mask32(HW_GPIO1OUT, GP_EEP_CS, 0); - eeprom_delay(); - - if (i == start_addr && start_addr_offset != 0) - { - // Handle unaligned write at start address - memcpy(val + start_addr_offset, ptr + cur_offset, HW_SEEPROM_BLK_SIZE - start_addr_offset); - cur_offset += (HW_SEEPROM_BLK_SIZE - start_addr_offset); - } else { - // Handle unaligned write at end address - memcpy(val, ptr + cur_offset, end_addr_size); - cur_offset += end_addr_size; - } - } else { - // Normal write - memcpy(val, ptr + cur_offset, HW_SEEPROM_BLK_SIZE); - cur_offset += HW_SEEPROM_BLK_SIZE; - } - - // Start command cycle - mask32(HW_GPIO1OUT, 0, GP_EEP_CS); - - // Send write command + address - seeprom_send_bits(0x500 | i, 11); - - // Send data - seeprom_send_bits(*((u16*)val), 16); - - // End of command cycle - mask32(HW_GPIO1OUT, GP_EEP_CS, 0); - eeprom_delay(); - - // Wait until SEEPROM is ready (write cycle is self-timed so no clocking needed) - mask32(HW_GPIO1OUT, 0, GP_EEP_CS); - - do { - eeprom_delay(); - } while(!(read32(HW_GPIO1IN) & GP_EEP_MISO)); - - mask32(HW_GPIO1OUT, GP_EEP_CS, 0); - eeprom_delay(); - } - - // EWDS - Disable programming commands - mask32(HW_GPIO1OUT, 0, GP_EEP_CS); - seeprom_send_bits(0x400, 11); - mask32(HW_GPIO1OUT, GP_EEP_CS, 0); - eeprom_delay(); - - // Enable CPU interruptions - _CPU_ISR_Restore(level); - - return cur_offset; -} -#endif diff --git a/source/mini_seeprom.h b/source/mini_seeprom.h deleted file mode 100644 index 897710b..0000000 --- a/source/mini_seeprom.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - mini - a Free Software replacement for the Nintendo/BroadOn IOS. - SEEPROM support - -Copyright (C) 2008, 2009 Sven Peter - -# This code is licensed to you under the terms of the GNU GPL, version 2; -# see http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt -*/ - -#ifndef __MINI_SEEPROM_H__ -#define __MINI_SEEPROM_H__ - -#define SEEPROM_SIZE 0x100 - -typedef struct -{ - union { - struct { - u8 boot2version; - u8 unknown1; - u8 unknown2; - u8 pad; - u32 update_tag; - }; - u8 data[8]; - }; - u16 checksum; // sum of data[] elements? -} __attribute__((packed)) eep_boot2_ctr_t; - -typedef struct -{ - union { - u32 nand_gen; // matches offset 0x8 in nand SFFS blocks - u8 data[4]; - }; - u16 checksum; // sum of data[] elements? -} __attribute__((packed)) eep_nand_ctr_t; - -struct SEEPROM -{ - u32 ms_id; // 0x00000002 - u32 ca_id; // 0x00000001 - u32 ng_key_id; - u8 ng_sig[60]; - eep_boot2_ctr_t boot2_counters[2]; - eep_nand_ctr_t nand_counters[3]; // current slot rotates on each write - u8 pad0[6]; - u8 korean_key[16]; - u8 pad1[116]; - u16 prng_seed[2]; // u32 with lo word stored first, incremented every time IOS starts. Used with the PRNG key to setup IOS's PRNG (syscalls 73/74 etc.) - u8 pad2[4]; -}; -_Static_assert(sizeof(struct SEEPROM) == SEEPROM_SIZE, "SEEPROM struct size incorrect!"); - -u16 seeprom_read(void *dst, u16 offset, u16 size); -// u16 seeprom_write(const void *src, u16 offset, u16 size); - -#endif /* __MINI_SEEPROM_H__ */ diff --git a/source/nand.c b/source/nand.c index bba65ea..ee68067 100644 --- a/source/nand.c +++ b/source/nand.c @@ -4,13 +4,21 @@ #include #include "nand.h" -#include "malloc.h" +#include "utils.h" #include "fileops.h" /* Buffer */ static u32 inbuf[8] ATTRIBUTE_ALIGN(32); static bool gNandInitialized = false; +/* NAND device list */ +nandDevice ndevList[] = +{ + { "Disable", 0, 0x00, 0x00 }, + { "SD/SDHC Card", 1, 0xF0, 0xF1 }, + { "USB 2.0 Mass Storage Device", 2, 0xF2, 0xF3 }, +}; +const int ndevCount = (sizeof(ndevList) / sizeof(nandDevice)); s32 Nand_Mount(nandDevice *dev) { diff --git a/source/nand.h b/source/nand.h index 3e61153..c2b18c2 100644 --- a/source/nand.h +++ b/source/nand.h @@ -20,6 +20,8 @@ typedef struct int type; } NameList; +extern nandDevice ndevList[]; +extern const int ndevCount; /* Prototypes */ s32 Nand_Mount(nandDevice *); diff --git a/source/otp.c b/source/otp.c deleted file mode 100644 index c52d708..0000000 --- a/source/otp.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include - -#include "otp.h" - -#define HW_OTP_COMMAND (*(vu32*)0xCD8001EC) -#define HW_OTP_DATA (*(vu32*)0xCD8001F0) - -#define HW_OTP_BLK_SIZE 4 -#define HW_OTP_BLK_CNT (OTP_SIZE / HW_OTP_BLK_SIZE) - -u8 otp_read(void *dst, u8 offset, u8 size) -{ - if (!dst || offset >= OTP_SIZE || !size || (offset + size) > OTP_SIZE) return 0; - - u8 cur_offset = 0; - - u8 *ptr = (u8*)dst; - u8 val[HW_OTP_BLK_SIZE] = {0}; - - // Calculate block offsets and sizes - u8 start_addr = (offset / HW_OTP_BLK_SIZE); - u8 start_addr_offset = (offset % HW_OTP_BLK_SIZE); - - u8 end_addr = ((offset + size) / HW_OTP_BLK_SIZE); - u8 end_addr_size = ((offset + size) % HW_OTP_BLK_SIZE); - - if (!end_addr_size) - { - end_addr--; - end_addr_size = HW_OTP_BLK_SIZE; - } - - if (end_addr == start_addr) end_addr_size -= start_addr_offset; - - for(u8 i = start_addr; i <= end_addr; i++) - { - if (cur_offset >= size) break; - - // Send command + address - HW_OTP_COMMAND = (0x80000000 | i); - - // Receive data - *((u32*)val) = HW_OTP_DATA; - - // Copy read data to destination buffer - if (i == start_addr && start_addr_offset != 0) - { - // Handle unaligned read at start address - memcpy(ptr + cur_offset, val + start_addr_offset, HW_OTP_BLK_SIZE - start_addr_offset); - cur_offset += (HW_OTP_BLK_SIZE - start_addr_offset); - } else - if (i == end_addr && end_addr_size != HW_OTP_BLK_SIZE) - { - // Handle unaligned read at end address - memcpy(ptr + cur_offset, val, end_addr_size); - cur_offset += end_addr_size; - } else { - // Normal read - memcpy(ptr + cur_offset, val, HW_OTP_BLK_SIZE); - cur_offset += HW_OTP_BLK_SIZE; - } - } - - return cur_offset; -} diff --git a/source/otp.h b/source/otp.h deleted file mode 100644 index d4d9939..0000000 --- a/source/otp.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __OTP_H__ -#define __OTP_H__ - -#define OTP_SIZE 0x80 - -typedef struct -{ - u8 boot1_hash[20]; - u8 common_key[16]; - u8 ng_id[4]; - union { // first two bytes of nand_hmac overlap last two bytes of ng_priv - struct { - u8 ng_priv[30]; - u8 _wtf1[18]; - }; - struct { - u8 _wtf2[28]; - u8 nand_hmac[20]; - }; - }; - u8 nand_key[16]; - u8 rng_key[16]; - u32 unk1; - u32 unk2; // 0x00000007 -} otp_t; - -u8 otp_read(void *dst, u8 offset, u8 size); - -#endif /* __OTP_H__ */ diff --git a/source/stub.S b/source/stub.S deleted file mode 100644 index 418c838..0000000 --- a/source/stub.S +++ /dev/null @@ -1,6 +0,0 @@ - .rodata - - .globl bgData - .balign 32 -bgData: - .incbin "../data/background" diff --git a/source/sys.c b/source/sys.c index c40a3fd..fb897f9 100644 --- a/source/sys.c +++ b/source/sys.c @@ -6,17 +6,11 @@ #include "sys.h" #include "nand.h" -#include "mini_seeprom.h" -#include "malloc.h" +#include "utils.h" #include "mload.h" #include "ehcmodule_elf.h" -/* Constants */ -#define CERTS_LEN 0x280 - /* Variables */ -static const char certs_fs[] ATTRIBUTE_ALIGN(32) = "/sys/cert.sys"; -u32 boot2version; static bool gDisablePRButtons = false; void __Sys_ResetCallback(__attribute__((unused)) u32 irq, __attribute__((unused)) void *ctx) @@ -33,57 +27,46 @@ void __Sys_PowerCallback(void) Sys_Shutdown(); } -bool tmdIsStubIOS(tmd* p_tmd) -{ - return - p_tmd->sys_version >> 32 == 0 - && p_tmd->num_contents == 3 - && p_tmd->contents[0].type == 0x0001 - && p_tmd->contents[1].type == 0x8001 - && p_tmd->contents[2].type == 0x8001; -} - +// we should be gangster and call the real ioctlv 69 +// (in all honesty I really don't like the blind copies of otp.c and mini_seeprom.c I added) bool ES_CheckHasKoreanKey(void) { - aeskey korean_key; - unsigned char iv[16] = {}; - __attribute__ ((__aligned__(0x10))) - unsigned char data[16] = {0x56, 0x52, 0x6f, 0x63, 0xa1, 0x2c, 0xd1, 0x32, 0x07, 0x99, 0x82, 0x3b, 0x1b, 0x08, 0x17, 0xd0}; + ATTRIBUTE_ALIGN(0x20) + unsigned char data[16] = { 0x56, 0x52, 0x6f, 0x63, 0xa1, 0x2c, 0xd1, 0x32, 0x07, 0x99, 0x82, 0x3b, 0x1b, 0x08, 0x17, 0xd0 }; + u32 iv[4] = {}; - if (seeprom_read(korean_key, offsetof(struct SEEPROM, korean_key), sizeof(korean_key)) != sizeof(korean_key)) - return false; - - AES_Decrypt(korean_key, 0x10, iv, 0x10, data, data, sizeof(data)); + int ret = ES_Decrypt(11, iv, data, sizeof(data), data); // return (!strcmp((char*) data, "thepikachugamer")) Just remembered that this is how the Trucha bug came to be - return (!memcmp(data, "thepikachugamer", sizeof(data))); + return (ret == 0) && (!memcmp(data, "thepikachugamer", sizeof(data))); } -bool isIOSstub(u8 ios_number) +bool Sys_CanLoadIOS(int ios) { + int ret; u32 tmd_size = 0; - tmd_view *ios_tmd; + u32 boot2version = 0; + tmd_view *view; - if ((boot2version >= 5) && (ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224)) + ES_GetBoot2Version(&boot2version); + if ((boot2version >= 5) && (ios == 202 || ios == 222 || ios == 223 || ios == 224)) return true; - ES_GetTMDViewSize(0x0000000100000000ULL | ios_number, &tmd_size); - if (!tmd_size) + ret = ES_GetTMDViewSize(0x0000000100000000ULL | ios, &tmd_size); + if (ret < 0) + return true; + + view = memalign32(tmd_size); + if (!view) + return true; + + ret = ES_GetTMDView(0x0000000100000000ULL | ios, (u8 *)view, tmd_size); + if (ret < 0) { - // getting size failed. invalid or fake tmd for sure! - // gprintf("failed to get tmd for ios %d\n",ios_number); + free(view); return true; } - ios_tmd = memalign32(tmd_size); - if (!ios_tmd) - { - // gprintf("failed to mem align the TMD struct!\n"); - return true; - } - memset(ios_tmd, 0, tmd_size); - ES_GetTMDView(0x0000000100000000ULL | ios_number, (u8 *)ios_tmd, tmd_size); - // gprintf("IOS %d is rev %d(0x%x) with tmd size of %u and %u contents\n",ios_number,ios_tmd->title_version,ios_tmd->title_version,tmd_size,ios_tmd->num_contents); /*Stubs have a few things in common: - title version : it is mostly 65280 , or even better : in hex the last 2 digits are 0. example : IOS 60 rev 6400 = 0x1900 = 00 = stub @@ -91,59 +74,49 @@ bool isIOSstub(u8 ios_number) - the stub ios' have 1 app of their own (type 0x1) and 2 shared apps (type 0x8001). eventho the 00 check seems to work fine , we'll only use other knowledge as well cause some people/applications install an ios with a stub rev >_> ...*/ - u8 Version = ios_tmd->title_version; - if ((boot2version >= 5) && (ios_number == 249 || ios_number == 250) && (Version < 18)) + u16 title_version = view->title_version; + free(view); + + if ((boot2version >= 5) && (ios == 249 || ios == 250) && (title_version < 18)) return true; - if ((ios_number == 202 || ios_number == 222 || ios_number == 223 || ios_number == 224) && (Version < 4)) + + if ((ios == 202 || ios == 222 || ios == 223 || ios == 224) && (title_version < 4)) return true; - // version now contains the last 2 bytes. as said above, if this is 00, its a stub - if (Version == 0) - { - if ((ios_tmd->num_contents == 3) && (ios_tmd->contents[0].type == 1 && ios_tmd->contents[1].type == 0x8001 && ios_tmd->contents[2].type == 0x8001)) - { - // gprintf("IOS %d is a stub\n",ios_number); - free(ios_tmd); - return true; - } - else - { - // gprintf("IOS %d is active\n",ios_number); - free(ios_tmd); - return false; - } - } - // gprintf("IOS %d is active\n",ios_number); - free(ios_tmd); + + if ((title_version & 0xFF) == 0 && (ios < 200 || title_version == 0xFF00)) + return true; + return false; } -bool loadIOS(int ios) +int Sys_LoadIOS(int ios) { - if (isIOSstub(ios)) - return false; + if (Sys_CanLoadIOS(ios)) + return -1; + mload_close(); - if (IOS_ReloadIOS(ios) >= 0) + int ret = IOS_ReloadIOS(ios); + if (ret < 0) + return ret; + + usleep(100000); // there should be a more professional way to do this + + if (IOS_GetVersion() != 249 && IOS_GetVersion() != 250) { - if (IOS_GetVersion() != 249 && IOS_GetVersion() != 250) + if (mload_init() >= 0) { - if (mload_init() >= 0) - { - data_elf my_data_elf; - mload_elf((void *)ehcmodule_elf, &my_data_elf); - mload_run_thread(my_data_elf.start, my_data_elf.stack, my_data_elf.size_stack, 0x47); - } + data_elf my_data_elf; + mload_elf((void *)ehcmodule_elf, &my_data_elf); + mload_run_thread(my_data_elf.start, my_data_elf.stack, my_data_elf.size_stack, 0x47); } - return true; } - return false; + + return ret; } void Sys_Init(void) { - /* Initialize video subsytem */ - VIDEO_Init(); - /* Set RESET/POWER button callback */ SYS_SetResetCallback(__Sys_ResetCallback); SYS_SetPowerCallback(__Sys_PowerCallback); @@ -186,6 +159,9 @@ void Sys_Shutdown(void) } +#if 0 +// this is a title.c thing +// also we're a wad manager we don't need to be reading the system certificate store s32 Sys_GetCerts(signed_blob **certs, u32 *len) { static signed_blob certificates[CERTS_LEN] ATTRIBUTE_ALIGN(32); @@ -212,6 +188,7 @@ s32 Sys_GetCerts(signed_blob **certs, u32 *len) return ret; } +#endif void SetPRButtons(bool enabled) { diff --git a/source/sys.h b/source/sys.h index 01e500d..abace38 100644 --- a/source/sys.h +++ b/source/sys.h @@ -3,17 +3,13 @@ #define IS_WIIU (*(vu16*)0xCD8005A0 == 0xCAFE) -extern u32 boot2version; - /* Prototypes */ -bool isIOSstub(u8 ios_number); -bool tmdIsStubIOS(tmd*); -bool loadIOS(int ios); -bool ES_CheckHasKoreanKey(void); void Sys_Init(void); void Sys_Reboot(void); void Sys_Shutdown(void); -s32 Sys_GetCerts(signed_blob **, u32 *); +bool Sys_CanLoadIOS(int ios); +int Sys_LoadIOS(int ios); +bool ES_CheckHasKoreanKey(void); void SetPRButtons(bool enabled); #endif diff --git a/source/title.c b/source/title.c index f49fb13..e193c08 100644 --- a/source/title.c +++ b/source/title.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -10,7 +11,6 @@ #include "nand.h" #include "sha1.h" #include "utils.h" -#include "otp.h" #include "malloc.h" s32 Title_ZeroSignature(signed_blob *p_sig) @@ -185,14 +185,33 @@ err: return ret; } +s32 Title_GetTMDContents(signed_blob *s_tmd, u32 **contents, u32 *num_contents) +{ + s32 ret; + + ret = ES_GetNumStoredTMDContents(s_tmd, SIGNED_TMD_SIZE(s_tmd), num_contents); + if (ret < 0) + return ret; + + *contents = memalign32(*num_contents * sizeof(u32)); + if (!*contents) + return -1; + + ret = ES_GetStoredTMDContents(s_tmd, SIGNED_TMD_SIZE(s_tmd), *contents, *num_contents); + if (ret >= 0) + return ret; + + free(*contents); + *contents = NULL; + *num_contents = 0; + return ret; +} + s32 Title_GetTMDView(u64 tid, tmd_view** outbuf, u32* outlen) { s32 ret; u32 view_sz = 0; - *outbuf = NULL; - *outlen = 0; - ret = ES_GetTMDViewSize(tid, &view_sz); if (ret < 0) return ret; @@ -210,79 +229,66 @@ s32 Title_GetTMDView(u64 tid, tmd_view** outbuf, u32* outlen) return 0; fail: + *outbuf = NULL; + *outlen = 0; free(view); return ret; } s32 Title_GetVersion(u64 tid, u16 *outbuf) { - signed_blob *p_tmd = NULL; - tmd *tmd_data = NULL; - - u32 len; s32 ret; + tmd_view *view = NULL; + u32 len; /* Get title TMD */ - ret = Title_GetTMD(tid, &p_tmd, &len); + ret = Title_GetTMDView(tid, &view, &len); if (ret < 0) return ret; - /* Retrieve TMD info */ - tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); - /* Set values */ - *outbuf = tmd_data->title_version; + *outbuf = view->title_version; /* Free memory */ - free(p_tmd); + free(view); return 0; } s32 Title_GetSysVersion(u64 tid, u64 *outbuf) { - signed_blob *p_tmd = NULL; - tmd *tmd_data = NULL; - - u32 len; s32 ret; + tmd_view *view = NULL; + u32 len; /* Get title TMD */ - ret = Title_GetTMD(tid, &p_tmd, &len); + ret = Title_GetTMDView(tid, &view, &len); if (ret < 0) return ret; - /* Retrieve TMD info */ - tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); - /* Set values */ - *outbuf = tmd_data->sys_version; + *outbuf = view->sys_version; /* Free memory */ - free(p_tmd); + free(view); return 0; } s32 Title_GetSize(u64 tid, u32 *outbuf) { - signed_blob *p_tmd = NULL; - tmd *tmd_data = NULL; - - u32 cnt, len, size = 0; s32 ret; + tmd_view *view = NULL; + u32 len, size = 0; /* Get title TMD */ - ret = Title_GetTMD(tid, &p_tmd, &len); + ret = Title_GetTMDView(tid, &view, &len); if (ret < 0) return ret; - /* Retrieve TMD info */ - tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); - /* Calculate title size */ - for (cnt = 0; cnt < tmd_data->num_contents; cnt++) { - tmd_content *content = &tmd_data->contents[cnt]; + for (int cnt = 0; cnt < view->num_contents; cnt++) { + tmd_view_content *content = &view->contents[cnt]; /* Add content size */ size += content->size; @@ -297,7 +303,7 @@ s32 Title_GetSize(u64 tid, u32 *outbuf) return 0; } -s32 Title_GetIOSVersions(u8 **outbuf, u32 *outlen) +s32 Title_GetIOSVersions(u8 *outbuf, u32 *outlen) { u8 *buffer = NULL; u64 *list = NULL; @@ -310,23 +316,6 @@ s32 Title_GetIOSVersions(u8 **outbuf, u32 *outlen) if (ret < 0) return ret; - /* Count IOS */ - for (cnt = idx = 0; idx < count; idx++) { - u32 tidh = (list[idx] >> 32); - u32 tidl = (list[idx] & 0xFFFFFFFF); - - /* Title is IOS */ - if ((tidh == 0x1) && (tidl >= 3) && (tidl <= 255)) - cnt++; - } - - /* Allocate memory */ - buffer = memalign32(cnt); - if (!buffer) { - ret = -1; - goto out; - } - /* Copy IOS */ for (cnt = idx = 0; idx < count; idx++) { u32 tidh = (list[idx] >> 32); @@ -338,63 +327,24 @@ s32 Title_GetIOSVersions(u8 **outbuf, u32 *outlen) } /* Set values */ - *outbuf = buffer; *outlen = cnt; - goto out; - -out: /* Free memory */ free(list); return ret; } -s32 Title_GetSharedContents(SharedContent** out, u32* count) +s32 Title_GetcIOSInfo(int ios, cIOSInfo* out) { - if (!out || !count) return false; - - u32 size; - SharedContent* buf = (SharedContent*)NANDLoadFile("/shared1/content.map", &size); - - if (!buf) - return (s32)size; - - else if (size % sizeof(SharedContent) != 0) { - free(buf); - return -996; - } - - *out = buf; - *count = size / sizeof(SharedContent); - - return 0; -} - -bool Title_SharedContentPresent(tmd_content* content, SharedContent shared[], u32 count) -{ - if (!shared || !content || !count) - return false; - - if (!(content->type & 0x8000)) - return false; - - for (SharedContent* s_content = shared; s_content < shared + count; s_content++) - { - if (memcmp(s_content->hash, content->hash, sizeof(sha1)) == 0) - return true; - } - - return false; -} - -bool Title_GetcIOSInfo(int IOS, cIOSInfo* out) -{ - u64 titleID = 0x0000000100000000ULL | IOS; + u64 titleID = 0x100000000ULL | ios; tmd_view* view = NULL; u32 view_size = 0; + int i; + char path[ISFS_MAXPATH]; - u32 size; + u32 size = 0; + cIOSInfo* buf = NULL; s32 ret = Title_GetTMDView(titleID, &view, &view_size); @@ -402,7 +352,7 @@ bool Title_GetcIOSInfo(int IOS, cIOSInfo* out) return ret; u32 content0 = 0; - for (int i = 0; i < view->num_contents; i++) + for (i = 0; i < view->num_contents; i++) { if (view->contents[i].index == 0) { content0 = view->contents[i].cid; @@ -411,19 +361,20 @@ bool Title_GetcIOSInfo(int IOS, cIOSInfo* out) } free(view); - sprintf(path, "/title/00000001/%08x/content/%08x.app", IOS, content0); + // insert ES_OpenTitleContent here + sprintf(path, "/title/00000001/%08x/content/%08x.app", ios, content0); buf = (cIOSInfo*)NANDLoadFile(path, &size); - if (!buf || size != 0x40 || buf->hdr_magic != CIOS_INFO_MAGIC || buf->hdr_version != CIOS_INFO_VERSION) - goto fail; + if (buf && size == 0x40 && buf->hdr_magic == CIOS_INFO_MAGIC && buf->hdr_version == CIOS_INFO_VERSION) { + *out = *buf; + ret = 0; + } + else { + ret = -1; + } - *out = *buf; free(buf); - return true; - -fail: - free(buf); - return false; + return ret; } #if 0 @@ -461,8 +412,7 @@ void Title_GetFreeSpace(u32* free, s32* user_free) *user_free = user_clusters_free * cluster_size; } #endif -__attribute__((aligned(0x10))) -aeskey WiiCommonKey, vWiiCommonKey; +u32 vWiiCommonKey[4] ATTRIBUTE_ALIGN(0x20); void Title_SetupCommonKeys(void) { @@ -470,16 +420,17 @@ void Title_SetupCommonKeys(void) if (keys_ok) return; - // Grab the Wii common key... - otp_read(WiiCommonKey, offsetof(otp_t, common_key), sizeof(aeskey)); + ATTRIBUTE_ALIGN(0x20) + static const u32 vWiiCommonKey_enc[4] = { 0x6E18DB23, 0x847CBA6C, 0x1931A417, 0x9BAF8E09 }; + u32 iv[4] = {}; - // ...and decrypt the vWii common key with it. - static const unsigned char vwii_key_enc_bin[0x10] = { 0x6e, 0x18, 0xdb, 0x23, 0x84, 0x7c, 0xba, 0x6c, 0x19, 0x31, 0xa4, 0x17, 0x9b, 0xaf, 0x8e, 0x09 }; - unsigned char iv[0x10] = {}; + s32 ret = ES_Decrypt(ES_KEY_COMMON, iv, vWiiCommonKey_enc, sizeof(vWiiCommonKey_enc), vWiiCommonKey); - memcpy(vWiiCommonKey, vwii_key_enc_bin, sizeof(vwii_key_enc_bin)); - AES_Decrypt(WiiCommonKey, sizeof(aeskey), iv, sizeof(iv), vWiiCommonKey, vWiiCommonKey, sizeof(aeskey)); + if (ret != 0) { + printf("ES_Encrypt -> %i\n", ret); + sleep(10); + } - keys_ok = true; + keys_ok = (ret == 0); return; }; diff --git a/source/title.h b/source/title.h index d872244..32db6df 100644 --- a/source/title.h +++ b/source/title.h @@ -3,16 +3,6 @@ #include -/* Constants */ -#define BLOCK_SIZE 0x4000 - -/* /shared1/content.map entry */ -typedef struct -{ - char filename[8]; - sha1 hash; -} ATTRIBUTE_PACKED SharedContent; - /* "cIOS build tag" */ enum { @@ -35,7 +25,7 @@ typedef struct _Static_assert(sizeof(cIOSInfo) == 0x40, "cIOSInfo struct size wrong"); /* Variables */ -extern aeskey WiiCommonKey, vWiiCommonKey; +extern u32 vWiiCommonKey[4]; /* Prototypes */ s32 Title_ZeroSignature(signed_blob *); @@ -45,13 +35,12 @@ s32 Title_GetList(u64 **, u32 *); s32 Title_GetTicketViews(u64, tikview **, u32 *); s32 Title_GetTMDView(u64, tmd_view **, u32 *); s32 Title_GetTMD(u64, signed_blob **, u32 *); +s32 Title_GetTMDContents(signed_blob *, u32**, u32*); s32 Title_GetVersion(u64, u16 *); s32 Title_GetSysVersion(u64, u64 *); s32 Title_GetSize(u64, u32 *); -s32 Title_GetIOSVersions(u8 **, u32 *); -s32 Title_GetSharedContents(SharedContent** out, u32* count); -bool Title_SharedContentPresent(tmd_content* content, SharedContent shared[], u32 count); -bool Title_GetcIOSInfo(int IOS, cIOSInfo*); +s32 Title_GetIOSVersions(u8 *, u32 *); +s32 Title_GetcIOSInfo(int IOS, cIOSInfo*); void Title_SetupCommonKeys(void); diff --git a/source/utils.h b/source/utils.h index 3a4862b..1dfa6d5 100644 --- a/source/utils.h +++ b/source/utils.h @@ -1,15 +1,30 @@ #ifndef _UTILS_H_ #define _UTILS_H_ +#include /* Constants */ #define KB_SIZE 1024.0 #define MB_SIZE 1048576.0 #define GB_SIZE 1073741824.0 /* Macros */ -#define round_up(x,n) (-(-(x) & -(n))) +#ifdef __builtin_align_up +# define round_up(x,n) __builtin_align_up(x, n) +#else +# define round_up(x,n) ((x + n - 1) & ~(n - 1)) +#endif /* Prototypes */ u32 swap32(u32); +static inline void *memalign32(size_t size) +{ + return aligned_alloc(0x20, (size + 0x1F) & ~0x1F); +} + +static inline void *memalign64(size_t size) +{ + return aligned_alloc(0x40, (size + 0x3F) & ~0x3F); +} + #endif diff --git a/source/video.c b/source/video.c index c223edb..ef5418c 100644 --- a/source/video.c +++ b/source/video.c @@ -8,11 +8,15 @@ static void *framebuffer = NULL; static GXRModeObj *vmode = NULL; +/* Console Variables */ +int g_consoleWidth, g_consoleHeight; void Con_Init(u32 x, u32 y, u32 w, u32 h) { /* Create console in the framebuffer */ CON_InitEx(vmode, x, y, w, h); + + CON_GetMetrics(&g_consoleWidth, &g_consoleHeight); } void Con_Clear(void) @@ -24,17 +28,13 @@ void Con_Clear(void) void Con_ClearLine(void) { - int cols, rows; u32 cnt; printf("\r"); fflush(stdout); - /* Get console metrics */ - CON_GetMetrics(&cols, &rows); - /* Erase line */ - for (cnt = 1; cnt < cols; cnt++) { + for (cnt = 1; cnt < g_consoleWidth; cnt++) { printf(" "); fflush(stdout); } @@ -59,16 +59,12 @@ void Con_BgColor(u32 color, u8 bold) void Con_FillRow(u32 row, u32 color, u8 bold) { - int cols, rows; u32 cnt; /* Set color */ printf("\x1b[%u;%um", color + 40, bold); fflush(stdout); - /* Get console metrics */ - CON_GetMetrics(&cols, &rows); - /* Save current row and col */ printf("\x1b[s"); fflush(stdout); @@ -78,7 +74,7 @@ void Con_FillRow(u32 row, u32 color, u8 bold) fflush(stdout); /* Fill row */ - for (cnt = 0; cnt < cols; cnt++) { + for (cnt = 0; cnt < g_consoleWidth; cnt++) { printf(" "); fflush(stdout); } @@ -92,22 +88,10 @@ void Con_FillRow(u32 row, u32 color, u8 bold) Con_FgColor(7, 1); } -void Video_Configure(GXRModeObj *rmode) +void Video_Init(void) { - /* Configure the video subsystem */ - VIDEO_Configure(rmode); + VIDEO_Init(); - /* Setup video */ - VIDEO_SetBlack(FALSE); - VIDEO_Flush(); - VIDEO_WaitVSync(); - - if (rmode->viTVMode & VI_NON_INTERLACE) - VIDEO_WaitVSync(); -} - -void Video_SetMode(void) -{ /* Select preferred video mode */ vmode = VIDEO_GetPreferredMode(NULL); @@ -127,7 +111,7 @@ void Video_SetMode(void) VIDEO_WaitVSync(); /* Clear the screen */ - Video_Clear(COLOR_BLACK); + Video_Clear(COLOR_RED); } void Video_Clear(s32 color) diff --git a/source/video.h b/source/video.h index e0fb7fd..cad6fde 100644 --- a/source/video.h +++ b/source/video.h @@ -3,7 +3,14 @@ #include "libpng/pngu/pngu.h" +/* Variables */ +extern int g_consoleWidth, g_consoleHeight; + /* Prototypes */ +void Video_Init(void); +void Video_Clear(s32); +void Video_DrawPng(IMGCTX, PNGUPROP, u16, u16); + void Con_Init(u32, u32, u32, u32); void Con_Clear(void); void Con_ClearLine(void); @@ -11,9 +18,4 @@ void Con_FgColor(u32, u8); void Con_BgColor(u32, u8); void Con_FillRow(u32, u32, u8); -void Video_Configure(GXRModeObj *); -void Video_SetMode(void); -void Video_Clear(s32); -void Video_DrawPng(IMGCTX, PNGUPROP, u16, u16); - #endif diff --git a/source/wad-manager.c b/source/wad-manager.c index 10a02d6..347e97f 100644 --- a/source/wad-manager.c +++ b/source/wad-manager.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -23,19 +24,17 @@ #include "iospatch.h" #include "fileops.h" -// Globals -CONFIG gConfig; - // Prototypes -extern void __exception_setreload(int t); -extern u32 WaitButtons (void); +extern void __exception_setreload(unsigned sec); + void CheckPassword (void); void SetDefaultConfig (void); int ReadConfigFile (void); int GetIntParam (char *inputStr); int GetStartupPath (char *startupPath, char *inputStr); int GetStringParam (char *outParam, char *inputStr, int maxChars); -int LaunchApp(const char* path, bool external); + +wm_config_t gConfig; // Default password Up-Down-Left-Right-Up-Down //#define PASSWORD "UDLRUD" @@ -151,38 +150,27 @@ void Disclaimer(void) int main(int argc, char **argv) { - __exception_setreload(10); + __exception_setreload(15); + Sys_LoadIOS(IOS_GetVersion()); - ES_GetBoot2Version(&boot2version); - if (!AHBPROT_DISABLED) -/* - We should just enable it tbh. - Like, look at https://github.com/WiiLink24/wfc-patcher-wii/blob/main/launcher/source/IOS.cpp - Awesome stuff. - */ - { - if (boot2version < 5) - { - if (!loadIOS(202)) if (!loadIOS(222)) if (!loadIOS(223)) if (!loadIOS(224)) if (!loadIOS(249)) loadIOS(36); - } else { - if (!loadIOS(249)) loadIOS(36); - } + /* Initialize display */ + Video_Init(); + + /* Initialize console */ + Gui_InitConsole(NULL); // todo: custom background & console config ? + + printf("hello\n"); + + s32 ret = IOSPATCH_Apply(); + if (ret != 0) { + printf("We goofed up.... (%#X)\n", ret); + sleep(15); + return ret; } /* Initialize subsystems */ Sys_Init(); - /* Set video mode */ - Video_SetMode(); - - FatMount(); - - /* Initialize console */ - Gui_InitConsole(); - - /* Draw background */ - Gui_DrawBackground(); - /* Initialize Wiimote and GC Controller */ Wpad_Init(); PAD_Init(); @@ -190,7 +178,8 @@ int main(int argc, char **argv) WKB_Initialize(); WIILIGHT_Init(); - AES_Init(); + FatMount(); + Title_SetupCommonKeys(); /* Print disclaimer */ @@ -219,96 +208,144 @@ int main(int argc, char **argv) int ReadConfigFile() { FILE* fptr; - char tmpStr[MAX_FILE_PATH_LEN]; - char tmpOutStr[40], path[128]; - s32 i; - bool found = false; + char tmpStr[256]; + char path[128]; - for (i = 0; i < FatGetDeviceCount(); i++) + if (__system_argv->argvMagic == ARGV_MAGIC) { + strncpy(path, __system_argv->argv[0], sizeof(path)); + char *fpath = strrchr(path, '/'); + if (fpath) + { + strcpy(fpath, "/config.txt"); + if (FSOPFileExists(path)) + goto found_the_file; + } + } + + for (int i = 0; i < FatGetDeviceCount(); i++) { snprintf(path, sizeof(path), "%s:%s", FatGetDevicePrefix(i), WM_CONFIG_FILE_PATH); if (FSOPFileExists(path)) - { - found = true; - break; - } + goto found_the_file; } - if (!found) - return -1; + return -1; +found_the_file: // Read the file // fptr = fopen(path, "rb"); // umm, why are we opening with mode rb and then using fgets? fptr = fopen(path, "r"); if (!fptr) { - // perror(path); + perror(path); return -1; } // Read the options while (true) { - if (!fgets(tmpStr, MAX_FILE_PATH_LEN, fptr)) + char *option, *value; + unsigned valueLen; + + if (!fgets(tmpStr, sizeof(tmpStr), fptr)) break; - else if (isalpha((int)tmpStr[0])) + option = tmpStr; + while (isspace((int)*option)) + option++; + + if (*option == ';' || *option == '#' || *option == '\0') + continue; + + value = strchr(tmpStr, '='); + if (!value) + continue; + + while (isspace((int)*++value)) + ; + + if (!*value) + continue; + + valueLen = (strpbrk(value, "#;\r\n") ?: strchr(value, 0)) - value; + while (isspace((int)value[valueLen])) + valueLen--; + + // Get the password + if (strncasecmp(option, "password", 8) == 0) { - // Get the password - if (strncmp (tmpStr, "Password", 8) == 0) - { - // Get password - // GetPassword (gConfig.password, tmpStr); - GetStringParam (gConfig.password, tmpStr, MAX_PASSWORD_LENGTH); + int i; - // If password is too long, ignore it - if (strlen (gConfig.password) > 10) - { - gConfig.password [0] = 0; - puts("Password longer than 10 characters; will be ignored. Press a button..."); - WaitButtons (); - } - } - - // Get startup path - else if (strncmp (tmpStr, "StartupPath", 11) == 0) + // Validate the length + if (valueLen >= MAX_PASSWORD_LENGTH) { - // Get startup Path - GetStartupPath (gConfig.startupPath, tmpStr); + WaitPrompt("Password is too long....\n"); + continue; } - // cIOS - else if (strncmp (tmpStr, "cIOSVersion", 11) == 0) - { - // Get cIOSVersion - gConfig.cIOSVersion = GetIntParam(tmpStr); + // Validate the characters + const char* const validPasswordChars = "UDLR12"; + for (i = 0; i < valueLen; i++) { + if (!strchr(validPasswordChars, value[i])) + break; } - // FatDevice - else if (strncmp (tmpStr, "FatDevice", 9) == 0) + if (i != valueLen) { - // Get fatDevice - GetStringParam (tmpOutStr, tmpStr, MAX_FAT_DEVICE_LENGTH); - for (i = 0; i < 5; i++) - { - if (strncmp(FatGetDevicePrefix(i), tmpOutStr, 4) == 0) - { - gConfig.fatDeviceIndex = i; - } - } + printf("Password has invalid characters! (?)\n"); + printf(" Valid characters: %s\n", validPasswordChars); + printf(" Provided password: %s\n", value); + printf(" %.*s^\n\n", i, ""); + + WaitPrompt(NULL); + continue; } - - // NandDevice - else if (strncmp (tmpStr, "NANDDevice", 10) == 0) + + strncpy(gConfig.password, value, i); + } + + // Get startup path + else if (strncasecmp(option, "startupPath", 11) == 0) + { + value[valueLen] = '\0'; + + if (FSOPFolderExists(value)) + strncpy(gConfig.startupPath, value, sizeof(gConfig.startupPath)); + } + + // cIOS + else if (strncasecmp(option, "cIOSVersion", 11) == 0) + { + char *endPtr; + long num = strtol(value, &endPtr, 10); + + if (num < 3 || num >= 256) { - // Get fatDevice - GetStringParam (tmpOutStr, tmpStr, MAX_NAND_DEVICE_LENGTH); - for (i = 0; i < 3; i++) - { - if (strncmp (ndevList[i].name, tmpOutStr, 2) == 0) - { - gConfig.nandDeviceIndex = i; - } - } + printf("Invalid cIOSVersion %lu (%s)\n", num, value); + WaitPrompt(NULL); + } + + // Get cIOSVersion + gConfig.cIOSVersion = num; + } + + // FatDevice + else if (strncasecmp(option, "fatDevice", 9) == 0) + { + // Get fatDevice + for (int i = 0; i < FatGetDeviceCount(); i++) + { + if (strcmp(FatGetDevicePrefix(i), value) == 0) + gConfig.fatDeviceIndex = i; + } + } + + // NandDevice + else if (strncasecmp(tmpStr, "NANDDevice", 10) == 0) + { + for (int i = 0; i < 3; i++) + { + if (strcmp(ndevList[i].name, value) == 0) + gConfig.nandDeviceIndex = i; } } } // EndWhile @@ -322,107 +359,13 @@ int ReadConfigFile() void SetDefaultConfig (void) { - // Default password is NULL or no password - gConfig.password [0] = 0; + memset(&gConfig, 0, sizeof(gConfig)); // Default startup folder - strcpy (gConfig.startupPath, WAD_ROOT_DIRECTORY); + strcpy (gConfig.startupPath, DEFAULT_WAD_DIRECTORY); gConfig.cIOSVersion = CIOS_VERSION_INVALID; // Means that user has to select later gConfig.fatDeviceIndex = FAT_DEVICE_INDEX_INVALID; // Means that user has to select gConfig.nandDeviceIndex = NAND_DEVICE_INDEX_INVALID; // Means that user has to select } // SetDefaultConfig - - -int GetStartupPath (char *startupPath, char *inputStr) -{ - int i = 0; - int len = strlen (inputStr); - - // Find the "=" - while ((inputStr [i] != '=') && (i < len)) - { - i++; - } - i++; - - // Get to the "/" - while ((inputStr [i] != '/') && (i < len)) - { - i++; - } - - // Get the startup Path - int count = 0; - while (isascii(inputStr [i]) && (i < len) && (inputStr [i] != '\n') && - (inputStr [i] != '\r') && (inputStr [i] != ' ')) - { - startupPath [count++] = inputStr [i++]; - } - startupPath [count] = 0; // NULL terminate - - return (0); -} // GetStartupPath - -int GetIntParam (char *inputStr) -{ - int retval = 0; - int i = 0; - int len = strlen (inputStr); - char outParam [40]; - - // Find the "=" - while ((inputStr [i] != '=') && (i < len)) - { - i++; - } - i++; - - // Get to the first alpha numeric character - while ((isdigit((int)inputStr[i]) == 0) && (i < len)) - { - i++; - } - - // Get the string param - int outCount = 0; - while ((isdigit((int)inputStr[i])) && (i < len) && (outCount < 40)) - { - outParam [outCount++] = inputStr [i++]; - } - outParam [outCount] = 0; // NULL terminate - retval = atoi (outParam); - - return (retval); -} // GetIntParam - - -int GetStringParam (char *outParam, char *inputStr, int maxChars) -{ - int i = 0; - int len = strlen (inputStr); - - // Find the "=" - while ((inputStr [i] != '=') && (i < len)) - { - i++; - } - i++; - - // Get to the first alpha character - while ((isalpha((int)inputStr[i]) == 0) && (i < len)) - { - i++; - } - - // Get the string param - int outCount = 0; - while ((isalnum((int)inputStr[i])) && (i < len) && (outCount < maxChars)) - { - outParam [outCount++] = inputStr [i++]; - } - outParam [outCount] = 0; // NULL terminate - - return (0); -} // GetStringParam diff --git a/source/wad.c b/source/wad.c index a23f3c5..860a486 100644 --- a/source/wad.c +++ b/source/wad.c @@ -9,8 +9,6 @@ #include "sys.h" #include "title.h" #include "utils.h" -#include "mini_seeprom.h" -#include "otp.h" #include "video.h" #include "wad.h" #include "wpad.h" @@ -95,76 +93,6 @@ static void DecEncTxtBuffer(char* buffer) } } -u64 get_title_ios(u64 title) { - s32 ret, fd; - static char filepath[256] ATTRIBUTE_ALIGN(32); - - // Check to see if title exists - if (ES_GetDataDir(title, filepath) >= 0 ) { - u32 tmd_size = 0; - static u8 tmd_buf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(32); - - ret = ES_GetStoredTMDSize(title, &tmd_size); - if (ret < 0){ - // If we fail to use the ES function, try reading manually - // This is a workaround added since some IOS (like 21) don't like our - // call to ES_GetStoredTMDSize - - //printf("Error! ES_GetStoredTMDSize: %d\n", ret); - - sprintf(filepath, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(title), TITLE_LOWER(title)); - - ret = ISFS_Open(filepath, ISFS_OPEN_READ); - if (ret <= 0) - { - //printf("Error! ISFS_Open (ret = %d)\n", ret); - return 0; - } - - fd = ret; - - ret = ISFS_Seek(fd, 0x184, 0); - if (ret < 0) - { - //printf("Error! ISFS_Seek (ret = %d)\n", ret); - return 0; - } - - ret = ISFS_Read(fd,tmd_buf,8); - if (ret < 0) - { - //printf("Error! ISFS_Read (ret = %d)\n", ret); - return 0; - } - - ret = ISFS_Close(fd); - if (ret < 0) - { - //printf("Error! ISFS_Close (ret = %d)\n", ret); - return 0; - } - - return be64(tmd_buf); - - } else { - // Normal versions of IOS won't have a problem, so we do things the "right" way. - - // Some of this code adapted from bushing's title_lister.c - signed_blob *s_tmd = (signed_blob *)tmd_buf; - ret = ES_GetStoredTMD(title, s_tmd, tmd_size); - if (ret < 0){ - //printf("Error! ES_GetStoredTMD: %d\n", ret); - return -1; - } - tmd *t = SIGNATURE_PAYLOAD(s_tmd); - return t->sys_version; - } - - - } - return 0; -} - static bool GetRegionFromTXT(char* region) { u32 size = 0; @@ -324,7 +252,9 @@ bool GetSysMenuExecPath(char path[ISFS_MAXPATH], bool mainDOL) u32 cid = GetSysMenuBootContent(); if (!cid) return false; - if (mainDOL) cid |= 0x10000000; + if (mainDOL) + cid = (cid & ~0xF00000000) | 0x10000000; + sprintf(path, "/title/00000001/00000002/content/%08x.app", cid); return true; @@ -506,56 +436,20 @@ static bool CompareHashes(bool priiloader) /* 'WAD Header' structure */ typedef struct { - /* Header length */ u32 header_len; - - /* WAD type */ u16 type; - - u16 padding; - - /* Data length */ + u16 version; u32 certs_len; u32 crl_len; u32 tik_len; u32 tmd_len; u32 data_len; u32 footer_len; -} ATTRIBUTE_PACKED wadHeader; +} wadHeader; /* Variables */ -static u8 wadBuffer[BLOCK_SIZE] ATTRIBUTE_ALIGN(32); - -s32 __Wad_GetTitleID(FILE *fp, wadHeader *header, u64 *tid) -{ - signed_blob *p_tik = NULL; - tik *tik_data = NULL; - - u32 offset = 0; - s32 ret; - - /* Ticket offset */ - offset += round_up(header->header_len, 64); - offset += round_up(header->certs_len, 64); - offset += round_up(header->crl_len, 64); - - /* Read ticket */ - ret = FSOPReadOpenFileA(fp, (void*)&p_tik, offset, header->tik_len); - if (ret != 1) - goto out; - - /* Ticket data */ - tik_data = (tik *)SIGNATURE_PAYLOAD(p_tik); - - /* Copy title ID */ - *tid = tik_data->titleid; - -out: - /* Free memory */ - free(p_tik); - - return ret; -} +ATTRIBUTE_ALIGN(0x40) +static u8 wadBuffer[16 << 10]; bool __Wad_FixTicket(signed_blob *s_tik) { @@ -583,7 +477,7 @@ bool __Wad_FixTicket(signed_blob *s_tik) iv[0] = p_tik->titleid; iv[1] = 0; - AES_Encrypt(WiiCommonKey, 0x10, iv, 0x10, tkeybuf, tkeybuf, sizeof(tkeybuf)); + ES_Encrypt(ES_KEY_COMMON, (u32 *)iv, tkeybuf, sizeof(tkeybuf), tkeybuf); memcpy(p_tik->cipher_title_key, tkeybuf, sizeof(tkeybuf)); } @@ -597,10 +491,7 @@ bool __Wad_FixTicket(signed_blob *s_tik) bool __Wad_VerifyHeader(wadHeader* header) { - return - header->header_len == 0x20 - && header->type == ('I' << 8 | 's') - && header->padding == 0x00; + return (header->header_len == 0x20 && header->type == 0x4973 && header->version == 0x0000); } const char* wad_strerror(int ec) @@ -614,10 +505,14 @@ const char* wad_strerror(int ec) case -999: return "BRICK BLOCKED"; case -1010: return "Wii System memory full!"; case -1017: return "Invalid argument"; + case -1020: return "Device ID mismatch"; case -1022: return "Content hash mismatch"; + case -1027: return "Issuer not found in the certificate chain"; + case -1028: return "Ticket not found"; + case -1029: return "Invalid Ticket"; case -1035: return "Newer version already installed"; case -1036: return "Needed IOS missing!"; - case -2011: return "No trucha bug?"; + case -2011: return "No signature check patch?"; /* * from libogc. * This rarely happens unless the WAD had an invalid ticket/tmd size @@ -629,6 +524,12 @@ const char* wad_strerror(int ec) } } +// Convenience purposes +u32 hbcList[] = { 0x48415858, 0x4A4F4449, 0xAF1BF516, 0x4C554C5A, 0x4F484243 }; +u32 eulaList[] = { 0x48414B45, 0x48414B50, 0x48414B4A, 0x48414B4B }; +u32 rgnselList[] = { 0x48414C45, 0x48414C50, 0x48414C4A, 0x48414C4B }; + + // Some of the safety checks can block region changing // Entering the Konami code turns this true, so it will // skip the problematic checks for region changing. @@ -636,26 +537,26 @@ bool skipRegionSafetyCheck = false; s32 Wad_Install(FILE *fp) { - SetPRButtons(false); - wadHeader *header = NULL; + s32 ret; + wadHeader *header = {}; signed_blob *p_certs = NULL, *p_crl = NULL, *p_tik = NULL, *p_tmd = NULL; + tmd *tmd_data = NULL; + u64 tid; + tmd_view *view = NULL; + u32 view_size = 0; + u32 boot2version; + u32 cnt, offset = 0; + u32 *installedContents = NULL; + u32 installedContentsCount = 0; - SharedContent* sharedContents = NULL; - - tmd *tmd_data = NULL; - - u32 cnt, offset = 0; - u32 sharedContentsCount = 0; - int ret; - u64 tid; bool retainPriiloader = false; bool cleanupPriiloader = false; - printf("\t\t>> Reading WAD data..."); - fflush(stdout); + SetPRButtons(false); + printf("\t\t>> Reading WAD data...\n\n"); ret = FSOPReadOpenFileA(fp, (void*)&header, offset, sizeof(wadHeader)); - if (ret != 1) + if (ret < 0) goto err; if (!__Wad_VerifyHeader(header)) @@ -665,7 +566,9 @@ s32 Wad_Install(FILE *fp) } offset += round_up(header->header_len, 64); - + +/* + * IOS won't let you do this unless you actually call ES_ImportBoot //Don't try to install boot2 __Wad_GetTitleID(fp, header, &tid); @@ -675,10 +578,10 @@ s32 Wad_Install(FILE *fp) ret = -999; goto out; } - + */ /* WAD certificates */ ret = FSOPReadOpenFileA(fp, (void*)&p_certs, offset, header->certs_len); - if (ret != 1) + if (ret < 0) goto err; offset += round_up(header->certs_len, 64); @@ -686,7 +589,7 @@ s32 Wad_Install(FILE *fp) /* WAD crl */ if (header->crl_len) { ret = FSOPReadOpenFileA(fp, (void*)&p_crl, offset, header->crl_len); - if (ret != 1) + if (ret < 0) goto err; offset += round_up(header->crl_len, 64); @@ -694,140 +597,159 @@ s32 Wad_Install(FILE *fp) /* WAD ticket */ ret = FSOPReadOpenFileA(fp, (void*)&p_tik, offset, header->tik_len); - if (ret != 1) + if (ret < 0) goto err; - bool isvWiiTitle = __Wad_FixTicket(p_tik); - offset += round_up(header->tik_len, 64); /* WAD TMD */ ret = FSOPReadOpenFileA(fp, (void*)&p_tmd, offset, header->tmd_len); - if (ret != 1) + if (ret < 0) goto err; offset += round_up(header->tmd_len, 64); - Con_ClearLine(); + bool isvWiiTitle = __Wad_FixTicket(p_tik); /* Get TMD info */ tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); + tid = tmd_data->title_id; if (TITLE_UPPER(tmd_data->sys_version) == 0) // IOS { - if ((isvWiiTitle || tmd_data->vwii_title) ^ IS_WIIU) // xor is one of my favourite binary operators of all time + bool stubbed = (tmd_data->title_version & 0xFF) == 0 || tmd_data->title_version == 404; + bool isCrossPlatformIOS = (isvWiiTitle || tmd_data->vwii_title) ^ IS_WIIU; // xor is one of my favourite binary operators of all time + + if (isCrossPlatformIOS && !skipRegionSafetyCheck) { - printf("\n Cannot install vWii IOS on Wii\n or Wii IOS on vWii.\n"); + printf(" Cannot install vWii IOS on Wii\n"); + printf(" or Wii IOS on vWii.\n"); + printf(" I mean maybe you can. I'm not going to find out though\n"); ret = -999; goto err; } - if(tid == get_title_ios(TITLE_ID(1, 2))) + ret = Title_GetTMDView(0x100000002LL, &view, &view_size); + if (ret < 0) { - if (tmdIsStubIOS(tmd_data)) + printf(" Hey, where's Perry?\n\n"); + + printf(" (No really, where is your Wii System Menu?)\n"); + goto err; + } + + if (view->sys_version == tmd_data->title_id) + { + if (isCrossPlatformIOS) { - printf("\n I won't install a stub System Menu IOS\n"); + printf(" Anything but the System menu's IOS...!!!!\n"); ret = -999; goto err; } - // this code feels like a MESS - else if (!IS_WIIU && (tid == TITLE_ID(1, 70) || tid == TITLE_ID(1, 80))) + if (stubbed) { + printf(" I won't install a stub System Menu IOS\n"); + ret = -999; + goto err; + } + + if (!IS_WIIU && (view->title_version >> 5) >= 15) // 4.2 or later. Again. { tik* ticket = (tik*)SIGNATURE_PAYLOAD(p_tik); - __aligned(0x10) + __aligned(0x20) aeskey titlekey; u64 iv[2] = { tid }; - memcpy(titlekey, ticket->cipher_title_key, sizeof(aeskey)); - AES_Decrypt(WiiCommonKey, sizeof(aeskey), iv, sizeof(iv), titlekey, titlekey, sizeof(aeskey)); + ES_Decrypt(ES_KEY_COMMON, (u32 *)iv, titlekey, sizeof(aeskey), titlekey); u32 content0_offset = offset; - for (tmd_content* con = tmd_data->contents; con < tmd_data->contents + tmd_data->num_contents; con++) + for (int i = 0; i < tmd_data->num_contents; i++) { - if (con->index == 0) break; - content0_offset += round_up(con->size, 0x40); + if (tmd_data->contents[i].index == 0) break; + content0_offset += round_up(tmd_data->contents[i].size, 0x40); } __aligned(0x20) cIOSInfo build_tag = {}; - ret = FSOPReadOpenFile(fp, (void*)&build_tag, content0_offset, sizeof(cIOSInfo)); - if (ret != 1) + ret = FSOPReadOpenFile(fp, (void*)&build_tag, content0_offset, sizeof(build_tag)); + if (ret < 0) goto err; iv[0] = 0; iv[1] = 0; - AES_Decrypt(titlekey, sizeof(aeskey), iv, sizeof(iv), &build_tag, &build_tag, sizeof(cIOSInfo)); + AES_Decrypt(titlekey, sizeof(aeskey), iv, sizeof(iv), &build_tag, &build_tag, sizeof(build_tag)); if ((build_tag.hdr_magic != CIOS_INFO_MAGIC || build_tag.hdr_version != CIOS_INFO_VERSION || build_tag.ios_base != 60) && ES_CheckHasKoreanKey()) { - printf("\n" - " Installing this System menu IOS will brick your Wii.\n" - " Please remove the Korean key via KoreanKii,\n" - " then try again.\n\n" - ); + printf(" Installing this System menu IOS will brick your Wii.\n\n"); + + printf(" Please remove the Korean key via KoreanKii,\n"); + printf(" then try again.\n"); ret = -999; goto err; } } } - - if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'E')) - || tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'P')) - || tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'J')) - || tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | 'K'))) + + if (stubbed) { - if (tmdIsStubIOS(tmd_data)) + u64 sysvers = 0; + + for (int i = 0; i < 4; i++) { - printf("\n I won't install a stub EULA IOS\n"); - ret = -999; - goto err; + if ((Title_GetSysVersion(TITLE_ID(0x00010008, eulaList[i]), &sysvers) == 0) && tid == sysvers) + { + printf(" I won't install a stub EULA IOS\n"); + ret = -999; + goto err; + } + + if ((Title_GetSysVersion(TITLE_ID(0x00010008, rgnselList[i]), &sysvers) == 0) && tid == sysvers) + { + printf(" I won't install a stub Region select IOS\n"); + ret = -999; + goto err; + } } - } - - if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'E')) - || tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'P')) - || tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'J')) - || tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | 'K'))) - { - if (tmdIsStubIOS(tmd_data)) + + for (int i = 0; i < 5; i++) { - printf("\n I won't install a stub rgnsel IOS\n"); - ret = -999; - goto err; - } - } - if(tid == get_title_ios(TITLE_ID(0x10001, 0x48415858)) - || tid == get_title_ios(TITLE_ID(0x10001, 0x4A4F4449)) - || tid == get_title_ios(TITLE_ID(0x10001, 0xAF1BF516)) - || tid == get_title_ios(TITLE_ID(0x10001, 0x4C554C5A)) - || tid == get_title_ios(TITLE_ID(0x10001, 0x4F484243))) - { - if (tmdIsStubIOS(tmd_data)) - { - printf("\n I won't stub Homebrew Channel's IOS\n"); - ret = -999; - goto err; + if ((Title_GetSysVersion(TITLE_ID(0x00010001, hbcList[i]), &sysvers) == 0) && tid == sysvers) + { + printf(" I won't stub The Homebrew Channel's IOS\n"); + ret = -999; + goto err; + } } } } else // not IOS { - if (isIOSstub(TITLE_LOWER(tmd_data->sys_version))) + ret = Title_GetTMDView(tmd_data->sys_version, &view, &view_size); + + if (ret < 0) { - printf("\n This Title wants IOS%i but the installed version\n is a stub.\n", TITLE_LOWER(tmd_data->sys_version)); + printf(" This title wants IOS%i, but the installed ver-...\n", TITLE_LOWER(tmd_data->sys_version)); + printf(" ...is it even installed?\n"); + goto err; + } + + if ((view->title_version & 0xFF) == 0 || view->title_version == 404) + { + printf(" This title wants IOS%i, but the installed version\n", TITLE_LOWER(tmd_data->sys_version)); + printf(" is a stub.\n"); ret = -1036; goto err; } - if (tid == TITLE_ID(1, 2)) + if (tid == 0x100000002LL) { if (skipRegionSafetyCheck || gForcedInstall) goto skipChecks; @@ -839,17 +761,18 @@ s32 Wad_Install(FILE *fp) if (isvWiiTitle || tmd_data->vwii_title) // && !IS_WIIU ? :thinking: { - printf("\n I won't install a vWii SM by default.\n\n"); - printf("\n If you're really sure what you're doing, next time\n"); - printf(" select your device using Konami...\n\n"); + printf(" I won't install a vWii SM by default.\n\n"); + + printf(" If you're really sure about what you're doing, next time\n"); + printf(" select your device using Konami...\n"); ret = -999; goto err; } - if(region == 0) + if (region == '\0') { - printf("\n Unknown System menu region\n Please check the site for updates\n"); + printf(" Unknown System menu region. What's up with setting.txt?\n"); ret = -999; goto err; @@ -857,10 +780,11 @@ s32 Wad_Install(FILE *fp) if (!VersionIsOriginal(tmd_data->title_version)) { - printf("\n I won't install an unknown SM versions by default.\n\n"); - printf("\n Are you installing a tweaked system menu?\n"); - printf("\n If you're really sure what you're doing, next time\n"); - printf(" select your device using Konami...\n\n"); + printf(" I won't install an unknown SM versions by default.\n\n"); + + printf(" Are you installing a tweaked system menu?\n"); + printf(" If you're really sure what you're doing, next time\n"); + printf(" select your device using Konami...\n"); ret = -999; goto err; @@ -869,9 +793,10 @@ s32 Wad_Install(FILE *fp) if(region != RegionLookupTable[(tmd_data->title_version & 0x0F)]) { printf("\n I won't install the wrong regions SM by default.\n\n"); + printf("\n Are you region changing?\n"); printf("\n If you're really sure what you're doing, next time\n"); - printf(" select your device using Konami...\n\n"); + printf(" select your device using Konami...\n"); ret = -999; goto err; @@ -882,15 +807,12 @@ s32 Wad_Install(FILE *fp) { cIOSInfo ios_info; - if (ES_CheckHasKoreanKey() && - (!Title_GetcIOSInfo(TITLE_LOWER(tmd_data->sys_version), &ios_info) || - ios_info.ios_base != 60)) + if ((Title_GetcIOSInfo(TITLE_LOWER(tmd_data->sys_version), &ios_info) != 0 || + ios_info.ios_base != 60) && ES_CheckHasKoreanKey()) { - printf("\n" - " Installing this System menu will brick your Wii.\n" - " Please remove the Korean key via KoreanKii,\n" - " then try again.\n\n" - ); + printf(" Installing this System menu will brick your Wii.\n"); + printf(" Please remove the Korean key via KoreanKii,\n"); + printf(" then try again.\n"); ret = -999; goto err; @@ -900,21 +822,25 @@ s32 Wad_Install(FILE *fp) skipChecks: if (tmd_data->title_version < 416) { + ES_GetBoot2Version(&boot2version); if(boot2version == 4) { - printf("\n This version of the System Menu\n is not compatible with your Wii\n"); + printf(" This version of the System Menu\n"); + printf(" is not compatible with your Wii\n"); ret = -999; goto err; } } - if (!gForcedInstall && AHBPROT_DISABLED && IsPriiloaderInstalled()) + if (!gForcedInstall && IsPriiloaderInstalled()) { cleanupPriiloader = true; - printf("\n Priiloader is installed next to the system menu.\n\n"); - printf(" It is recommended to retain Priiloader as it can\n"); - printf(" protect your console from being bricked.\n\n"); - printf(" Press A to retain Priiloader or B to remove."); + printf(" Priiloader is installed next to the system menu.\n\n"); + + printf(" It is recommended to retain Priiloader as it can\n"); + printf(" protect your console from being bricked.\n\n"); + + printf(" Press A to retain Priiloader or B to remove."); u32 buttons = WaitButtons(); @@ -989,26 +915,22 @@ skipChecks: } #endif - printf("\t\t>> Installing ticket..."); - fflush(stdout); + printf("\t\t>> Installing ticket...\n"); /* Install ticket */ ret = ES_AddTicket(p_tik, header->tik_len, p_certs, header->certs_len, p_crl, header->crl_len); if (ret < 0) goto err; - Con_ClearLine(); - - printf("\r\t\t>> Installing title..."); - fflush(stdout); + printf("\t\t>> Installing title...\n"); /* Install title */ ret = ES_AddTitleStart(p_tmd, header->tmd_len, p_certs, header->certs_len, p_crl, header->crl_len); if (ret < 0) goto err; - /* Get list of currently installed shared contents */ - Title_GetSharedContents(&sharedContents, &sharedContentsCount); + /* Get list of currently installed contents */ + Title_GetTMDContents(p_tmd, &installedContents, &installedContentsCount); /* Install contents */ for (cnt = 0; cnt < tmd_data->num_contents; cnt++) @@ -1021,23 +943,21 @@ skipChecks: /* Encrypted content size */ len = round_up(content->size, 64); - if (Title_SharedContentPresent(content, sharedContents, sharedContentsCount)) - { - offset += len; - continue; - } + if (content->type & 0x8000) // We're only doing shared. Unless we're going to genuinely read the non-shared contents and check the hash against what we're installing + for (int i = 0; i < installedContentsCount; i++) + if (installedContents[i] == content->cid) + { + offset += len; + continue; + } Con_ClearLine(); - printf("\r\t\t>> Installing content #%02d...", content->cid); - fflush(stdout); + printf("\r\t\t>> Installing content #%02d...", content->index); /* Install content */ - cfd = ES_AddContentStart(tmd_data->title_id, content->cid); - if (cfd < 0) - { - ret = cfd; + ret = cfd = ES_AddContentStart(tmd_data->title_id, content->cid); + if (ret < 0) goto err; - } /* Install content data */ while (idx < len) @@ -1046,12 +966,12 @@ skipChecks: /* Data length */ size = (len - idx); - if (size > BLOCK_SIZE) - size = BLOCK_SIZE; + if (size > sizeof(wadBuffer)) + size = sizeof(wadBuffer); /* Read data */ - ret = FSOPReadOpenFile(fp, &wadBuffer, offset, size); - if (ret != 1) + ret = FSOPReadOpenFile(fp, wadBuffer, offset, size); + if (ret < 0) { ES_AddContentFinish(cfd); goto err; @@ -1183,7 +1103,7 @@ skipChecks: } err: - printf("\n ERROR! (ret = %d)\n", ret); + printf("\n ERROR! (ret = %d)\n", ret); if (retainPriiloader) SetPriiloaderOption(false); @@ -1200,7 +1120,8 @@ out: free(p_crl); free(p_tik); free(p_tmd); - free(sharedContents); + free(installedContents); + free(view); if (gForcedInstall) return Wad_Install(fp); @@ -1211,30 +1132,30 @@ out: s32 Wad_Uninstall(FILE *fp) { - SetPRButtons(false); - wadHeader *header = NULL; - tikview *viewData = NULL; + wadHeader *header = {}; + + tikview *tikviews = NULL; signed_blob *s_tik = NULL; signed_blob *s_tmd = NULL; - u64 tid; + u64 tid, sysvers; u32 viewCnt; int ret; - printf("\t\t>> Reading WAD data..."); - fflush(stdout); + SetPRButtons(false); + printf("\t\t>> Reading WAD data...\n"); /* WAD header */ ret = FSOPReadOpenFileA(fp, (void*)&header, 0, sizeof(wadHeader)); - if (ret != 1) + if (ret < 0) { - printf(" ERROR! (ret = %d)\n", ret); + printf(" ERROR! (ret = %d)\n", ret); goto out; } if (!__Wad_VerifyHeader(header)) { - puts("\t\tInvalid WAD file?"); + puts(" Invalid WAD file?"); ret = ES_EINVAL; goto out; } @@ -1246,8 +1167,8 @@ s32 Wad_Uninstall(FILE *fp) offset += round_up(header->crl_len, 0x40); ret = FSOPReadOpenFileA(fp, (void*)&s_tik, offset, header->tik_len); - if (ret != 1) { - printf(" ERROR! (ret = %d)\n", ret); + if (ret < 0) { + printf(" ERROR! (ret = %d)\n", ret); goto out; } @@ -1257,8 +1178,8 @@ s32 Wad_Uninstall(FILE *fp) offset += round_up(header->tik_len, 0x40); ret = FSOPReadOpenFileA(fp, (void*)&s_tmd, offset, header->tmd_len); - if (ret != 1) { - printf(" ERROR! (ret = %d)\n", ret); + if (ret < 0) { + printf(" ERROR! (ret = %d)\n", ret); goto out; } @@ -1267,134 +1188,91 @@ s32 Wad_Uninstall(FILE *fp) //Assorted Checks if (TITLE_UPPER(tid) == 0x1) { - if (!get_title_ios(TITLE_ID(1, 2))) + if ((ret = Title_GetSysVersion(0x100000002LL, &sysvers)) != 0) { - printf("\n I can't determine the System Menus IOS\nDeleting system titles is disabled\n"); - ret = -999; + printf(" I can't determine the System Menus IOS\n"); + printf(" Deleting system titles is disabled\n"); goto out; } if (((isvWiiTitle || tmd_data->vwii_title) ^ IS_WIIU) && !skipRegionSafetyCheck) // Only this way around this time // Ehh nvm { - printf("\n" - " Attempting to uninstall a Wii IOS WAD on vWii.\n" - " or a vWii IOS WAD on Wii.\n\n" + printf( + " Attempting to uninstall a Wii IOS WAD on vWii.\n" + " or a vWii IOS WAD on Wii.\n\n" - " Maybe you installed one on accident before?\n\n" + " Maybe you installed one on accident before?\n\n" - " If you're sure about what you're doing, input\n" - " the Konami code on the device screen. Have fun.\n"); + " If you're sure about what you're doing, input\n" + " the Konami code on the device screen. Have fun.\n"); ret = -999; goto out; } - if (tid == TITLE_ID(1, 1)) + if (tid == 0x100000001LL) { - printf("\n I won't try to uninstall boot2\n"); + printf(" I won't try to uninstall boot2\n"); ret = -999; goto out; } - if (tid == TITLE_ID(1, 2)) + if (tid == 0x100000002LL) { - printf("\n I won't uninstall the System Menu\n"); + printf(" I won't uninstall the System Menu\n"); ret = -999; goto out; } - if (tid == get_title_ios(TITLE_ID(1, 2))) + if (tid == sysvers) { - printf("\n I won't uninstall the System Menus IOS\n"); + printf(" I won't uninstall the System Menu's IOS\n"); ret = -999; goto out; } - if (tid == get_title_ios(TITLE_ID(0x10001, 0x48415858)) - || tid == get_title_ios(TITLE_ID(0x10001, 0x4A4F4449)) - || tid == get_title_ios(TITLE_ID(0x10001, 0xAF1BF516)) - || tid == get_title_ios(TITLE_ID(0x10001, 0x4C554C5A)) - || tid == get_title_ios(TITLE_ID(0x10001, 0x4F484243))) + + for (int i = 0; i < 5; i++) { - printf("\n I won't uninstall the Homebrew Channel's IOS!\n"); - ret = -999; - goto out; + if ((Title_GetSysVersion(TITLE_ID(0x00010001, hbcList[5 - i]), &sysvers) == 0) && tid == sysvers) + { + printf(" I won't uninstall the Homebrew Channel's IOS!\n"); + ret = -999; + goto out; + } } } char region = 0; GetSysMenuRegion(NULL, ®ion); - if((tid == TITLE_ID(0x10008, 0x48414B00 | 'E') || tid == TITLE_ID(0x10008, 0x48414B00 | 'P') || tid == TITLE_ID(0x10008, 0x48414B00 | 'J') || tid == TITLE_ID(0x10008, 0x48414B00 | 'K') - || (tid == TITLE_ID(0x10008, 0x48414C00 | 'E') || tid == TITLE_ID(0x10008, 0x48414C00 | 'P') || tid == TITLE_ID(0x10008, 0x48414C00 | 'J') || tid == TITLE_ID(0x10008, 0x48414C00 | 'K'))) - && region == 0) + if (((tid | 0xFF) == 0x0001000848414CFFLL || (tid | 0xFF) == 0x0001000848414BFFLL) && strchr("JEPK", (char)tid) && region == 0) { - printf("\n Unknown SM region\n Please check the site for updates\n"); + printf(" Unknown System Menu region\n Please check the site for updates\n"); ret = -999; goto out; } - if(tid == TITLE_ID(0x10008, 0x48414B00 | region)) + if (tid == TITLE_ID(0x10008, 0x48414B00 | region)) { - printf("\n I won't uninstall the EULA\n"); + printf(" I won't uninstall the EULA\n"); ret = -999; goto out; } - if(tid == TITLE_ID(0x10008, 0x48414C00 | region)) + if (tid == TITLE_ID(0x10008, 0x48414C00 | region)) { - printf("\n I won't uninstall rgnsel\n"); + printf(" I won't uninstall rgnsel\n"); ret = -999; goto out; } - if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414B00 | region))) + if (Title_GetSysVersion(0x0001000848414B00LL | region, &sysvers) == 0 && tid == sysvers) { - printf("\n I won't uninstall the EULAs IOS\n"); + printf(" I won't uninstall the EULAs IOS\n"); ret = -999; goto out; - } - if(tid == get_title_ios(TITLE_ID(0x10008, 0x48414C00 | region))) + } + if (Title_GetSysVersion(0x0001000848414C00LL | region, &sysvers) == 0 && tid == sysvers) { - printf("\n I won't uninstall the rgnsel IOS\n"); + printf(" I won't uninstall rgnsel's IOS\n"); ret = -999; goto out; } - Con_ClearLine(); - - /* Why don't we do this the other way around? Delete title contents, delete TMD, delete ticket. Seems more natural. */ - - printf("\t\t>> Deleting tickets..."); - fflush(stdout); - - /* Get ticket views */ - ret = Title_GetTicketViews(tid, &viewData, &viewCnt); - if (ret < 0) - printf(" ERROR! (ret = %d)\n", ret); - - /* Delete tickets */ - else { - u32 cnt; - static tikview view ATTRIBUTE_ALIGN(0x20); - - /* Delete all tickets */ - for (cnt = 0; cnt < viewCnt; cnt++) { - memcpy(&view, viewData + cnt, sizeof(tikview)); - - if (view.devicetype) - { - u32 deviceID = 0; - /* If we failed to get the ID or it actually matches, skip this */ - if (ES_GetDeviceID(&deviceID) || view.devicetype == deviceID) continue; - } - - ret = ES_DeleteTicket(&view); - if (ret < 0) - break; - } - - if (ret < 0) - printf(" ERROR! (ret = %d)\n", ret); - else - printf(" OK!\n"); - } - free(viewData); - - printf("\t\t>> Deleting title contents..."); - fflush(stdout); + printf("\t\t>> Deleting title contents... "); /* Delete title contents */ ret = ES_DeleteTitleContent(tid); @@ -1405,7 +1283,6 @@ s32 Wad_Uninstall(FILE *fp) printf("\t\t>> Deleting title..."); - fflush(stdout); /* Delete title */ ret = ES_DeleteTitle(tid); @@ -1414,6 +1291,39 @@ s32 Wad_Uninstall(FILE *fp) else printf(" OK!\n"); + printf("\t\t>> Deleting tickets..."); + + /* Get ticket views */ + ret = Title_GetTicketViews(tid, &tikviews, &viewCnt); + if (ret < 0) + printf(" ERROR! (ret = %d)\n", ret); + + /* Delete tickets */ + else + { + u32 cnt; + + /* Delete all tickets */ + for (cnt = 0; cnt < viewCnt; cnt++) { +#if 0 + if (view.devicetype) + { + u32 deviceID = 0; + /* If we failed to get the ID or it actually matches, skip this */ + if (ES_GetDeviceID(&deviceID) || view.devicetype == deviceID) continue; + } +#endif + ret = ES_DeleteTicket(&tikviews[cnt]); + if (ret < 0) + break; + } + + if (ret < 0) + printf(" ERROR! (ret = %d)\n", ret); + else + printf(" OK!\n"); + } + free(tikviews); out: /* Free memory */ free(header); diff --git a/source/wkb.c b/source/wkb.c index 4c5ed2a..5996d8c 100644 --- a/source/wkb.c +++ b/source/wkb.c @@ -86,6 +86,8 @@ static void WKBEventHandler(USBKeyboard_event evt) static void* WKBThread(__attribute__((unused)) void* arg) { + sleep(10); // HACK: IOS totally bricks up if I initialize this too early(??) + while (WKBThreadActive) { /* diff --git a/source/wkb.h b/source/wkb.h index 6dce244..feb3de6 100644 --- a/source/wkb.h +++ b/source/wkb.h @@ -1,10 +1,6 @@ #ifndef _WKB_H_ #define _WKB_H_ -//#include -//#include -//#include -//#include #include // u8, u16, etc... #include