#include #include #include #include #include #include #include "sys.h" #include "subsystem.h" #include "cfg.h" #include "fat.h" #include "menu.h" #include "gettext.h" #include "sha1.h" #include "sdhc.h" #include "usbstorage.h" #include "wpad.h" #include "apploader.h" #include "mem.h" #include "nand.h" #include "RuntimeIOSPatch.h" typedef struct { u32 block_size; u32 free_blocks; u32 used_blocks; u32 unk3; u32 unk4; u32 free_inodes; u32 unk5; } isfs_stats_t; /* Constants */ #define CERTS_LEN 0x280 typedef struct _iosinfo_t { u32 magicword; //0x1ee7c105 u32 magicversion; // 1 u32 version; // Example: 5 u32 baseios; // Example: 56 char name[0x10]; // Example: d2x char versionstring[0x10]; // Example: beta2 } __attribute__((packed)) iosinfo_t; bool get_iosinfo(int ios, signed_blob *TMD, iosinfo_t *iosinfo); char* get_ios_info_from_tmd(); extern char dm_boot_drive[16]; /* Variables */ static const char certs_fs[] ATTRIBUTE_ALIGN(32) = "/sys/cert.sys"; u8 shutdown = 0; void __Sys_ResetCallback(void) { /* Reboot console */ Sys_Reboot(); } void __Sys_PowerCallback(void) { /* Poweroff console */ //Sys_Shutdown(); shutdown = 1; } void Sys_Init(void) { /* Initialize video subsytem */ VIDEO_Init(); /* Set RESET/POWER button callback */ SYS_SetResetCallback(__Sys_ResetCallback); SYS_SetPowerCallback(__Sys_PowerCallback); /* Prepare random seed */ srand(time(0)); } void Sys_Reboot(void) { /* Restart console */ STM_RebootSystem(); } void Sys_Shutdown(void) { SDHC_Close(); USBStorage_Deinit(); Wpad_Disconnect(); /* Poweroff console */ if(CONF_GetShutdownMode() == CONF_SHUTDOWN_IDLE) { s32 ret; /* Set LED mode */ ret = CONF_GetIdleLedMode(); if(ret >= 0 && ret <= 2) STM_SetLedMode(ret); /* Shutdown to idle */ STM_ShutdownToIdle(); } else { /* Shutdown to standby */ STM_ShutdownToStandby(); } } void Sys_LoadMenu(void) { /* Return to the Wii system menu */ SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); } s32 Sys_GetCerts(signed_blob **certs, u32 *len) { static signed_blob certificates[CERTS_LEN] ATTRIBUTE_ALIGN(32); s32 fd, ret; /* Open certificates file */ fd = IOS_Open(certs_fs, 1); if (fd < 0) return fd; /* Read certificates */ ret = IOS_Read(fd, certificates, sizeof(certificates)); /* Close file */ IOS_Close(fd); /* Set values */ if (ret > 0) { *certs = certificates; *len = sizeof(certificates); } return ret; } void prep_exit() { dbg_printf("Services_Close\n"); Services_Close(); dbg_printf("Subsystem_Close\n"); Subsystem_Close(); dbg_printf("Video_Close\n"); extern void Video_Close(); Video_Close(); } void Sys_Exit() { prep_exit(); exit(0); } void Sys_HBC() { if (CFG.disable_options == 1) return; prep_exit(); WII_Initialize(); dbg_printf("HBC107\n"); WII_LaunchTitle(TITLE_ID(0x00010001,0x4C554C5A)); // LULZ WII_LaunchTitle(TITLE_ID(0x00010001,0xAF1BF516)); // 1.07 WII_LaunchTitle(TITLE_ID(0x00010001,0x4A4F4449)); // JODI WII_LaunchTitle(TITLE_ID(0x00010001,0x48415858)); // HAXX dbg_printf("exit\n"); exit(0); } void Sys_Channel(u32 channel) { prep_exit(); WII_Initialize(); WII_LaunchTitle(TITLE_ID(0x00010001,channel)); } // mload from uloader by Hermes #include "mload.h" #include "mload_modules.h" // uLoader 2.5: //#define size_ehcmodule2 20340 //#define size_dip_plugin2 3304 //extern unsigned char ehcmodule2[size_ehcmodule2]; //extern unsigned char dip_plugin2[size_dip_plugin2]; // uLoader 2.8D: //#define size_ehcmodule3 22264 //#define size_dip_plugin3 3352 //extern unsigned char ehcmodule3[size_ehcmodule3]; //extern unsigned char dip_plugin3[size_dip_plugin3]; // uLoader 3.0B: //#define size_ehcmodule4 32384 //#define size_dip_plugin4 3512 // uLoader 3.0C: //#define size_ehcmodule4 32432 // uLoader 3.1: //#define size_ehcmodule4 32400 //#define size_dip_plugin4 3080 // uloader 3.1 //#define size_dip_plugin4 3224 // uloader 3.2 //#define size_dip_plugin4 5920 // uloader 5.1 odip // EHCFAT module: //#define size_ehcmodule_frag 70529 // cfg50-52 //#define size_ehcmodule_frag 70613 // cfg53 //extern unsigned char ehcmodule_frag[size_ehcmodule_frag]; #define size_odip_frag 9120 // odip + frag extern unsigned char odip_frag[size_odip_frag]; //#define size_ehcmodule5 25287 // 5.0/5.1 hermes #define size_ehcmodule5 27134 // 5.1 rodries extern unsigned char ehcmodule5[size_ehcmodule5]; #define size_sdhc_module 5672 extern unsigned char sdhc_module[size_sdhc_module]; /* cksum: cios_mload_4.0 846383702 25614 ehcmodule.elf 3703302275 5920 odip_plugin.bin uloader 4.9A 5.0 846383702 25614 ehcmodule.elf 2749576855 5920 odip_plugin.bin cios_mload_4.1 2551980440 25287 ehcmodule.elf 3870739346 5920 odip_plugin.bin uloader 5.0C 5.1B 5.1D 5.1E 2551980440 25287 ehcmodule.elf 3870739346 5920 odip_plugin.bin */ //int mload_ehc_fat = 0; //int mload_need_fat = 0; // current void *ehcmodule; int size_ehcmodule; void *dip_plugin; int size_dip_plugin; // external2 /* char ehc_path[200]; void *external_ehcmodule2 = NULL; int size_external_ehcmodule2 = 0; // external3 char ehc_path3[200]; void *external_ehcmodule3 = NULL; int size_external_ehcmodule3 = 0; // external4 char ehc_path4[200]; void *external_ehcmodule4 = NULL; int size_external_ehcmodule4 = 0; // external_fat char ehc_path_fat[200]; void *external_ehcmodule_frag = NULL; int size_external_ehcmodule_frag = 0; */ /* static u32 ios_36[16] ATTRIBUTE_ALIGN(32)= { 0, // DI_EmulateCmd 0, 0x2022DDAC, // dvd_read_controlling_data 0x20201010+1, // handle_di_cmd_reentry (thumb) 0x20200b9c+1, // ios_shared_alloc_aligned (thumb) 0x20200b70+1, // ios_shared_free (thumb) 0x20205dc0+1, // ios_memcpy (thumb) 0x20200048+1, // ios_fatal_di_error (thumb) 0x20202b4c+1, // ios_doReadHashEncryptedState (thumb) 0x20203934+1, // ios_printf (thumb) }; static u32 ios_38[16] ATTRIBUTE_ALIGN(32)= { 0, // DI_EmulateCmd 0, 0x2022cdac, // dvd_read_controlling_data 0x20200d38+1, // handle_di_cmd_reentry (thumb) 0x202008c4+1, // ios_shared_alloc_aligned (thumb) 0x20200898+1, // ios_shared_free (thumb) 0x20205b80+1, // ios_memcpy (thumb) 0x20200048+1, // ios_fatal_di_error (thumb) 0x20202874+1, // ios_doReadHashEncryptedState (thumb) 0x2020365c+1, // ios_printf (thumb) }; */ u32 patch_datas[8] ATTRIBUTE_ALIGN(32); data_elf my_data_elf; int my_thread_id=0; /* void load_ext_ehc_module(int verbose) { if(!external_ehcmodule2) { snprintf(ehc_path, sizeof(ehc_path), "%s/ehcmodule.elf", USBLOADER_PATH); size_external_ehcmodule2 = Fat_ReadFile(ehc_path, &external_ehcmodule2); if (size_external_ehcmodule2 < 0) { size_external_ehcmodule2 = 0; } } if(!external_ehcmodule3) { snprintf(ehc_path3, sizeof(ehc_path3), "%s/ehcmodule3.elf", USBLOADER_PATH); size_external_ehcmodule3 = Fat_ReadFile(ehc_path3, &external_ehcmodule3); if (size_external_ehcmodule3 < 0) { size_external_ehcmodule3 = 0; } } if(!external_ehcmodule4) { snprintf(ehc_path4, sizeof(ehc_path4), "%s/ehcmodule4.elf", USBLOADER_PATH); size_external_ehcmodule4 = Fat_ReadFile(ehc_path4, &external_ehcmodule4); if (size_external_ehcmodule4 < 0) { size_external_ehcmodule4 = 0; } } if(!external_ehcmodule_frag) { snprintf(ehc_path_fat, sizeof(ehc_path_fat), "%s/ehcmodule_frag.elf", USBLOADER_PATH); size_external_ehcmodule_frag = Fat_ReadFile(ehc_path_fat, &external_ehcmodule_frag); if (size_external_ehcmodule_frag < 0) { size_external_ehcmodule_frag = 0; } } } */ static char mload_ver_str[100]; static int mload_ver = 0; void mk_mload_version() { mload_ver_str[0] = 0; mload_ver = 0; if (CFG.ios_mload || (is_ios_type(IOS_TYPE_WANIN) && IOS_GetRevision() >= 18) ) { if (IOS_GetRevision() >= 4) { if (is_ios_type(IOS_TYPE_WANIN)) { char *info = get_ios_info_from_tmd(); if (info) { sprintf(mload_ver_str, "Base: IOS%s ", info); } else { sprintf(mload_ver_str, "Base: IOS?? DI:%d ", wanin_mload_get_IOS_base()); } } else { sprintf(mload_ver_str, "Base: IOS%d ", mload_get_IOS_base()); } } if (IOS_GetRevision() > 4) { int v, s = 0; v = mload_ver = mload_get_version(); if (v>0) { s = v & 0x0F; v = v >> 4; } sprintf(mload_ver_str + strlen(mload_ver_str), "mload v%d.%d ", v, s); } else { sprintf(mload_ver_str + strlen(mload_ver_str), "mload v%d ", IOS_GetRevision()); } } } void print_mload_version_str(char *str) { int new_wanin = is_ios_type(IOS_TYPE_WANIN) && IOS_GetRevision() >= 18; *str = 0; if (CFG.ios_mload || new_wanin) { strcpy(str, mload_ver_str); } } void print_mload_version() { char str[100]; print_mload_version_str(str); printf("%s", str); } int load_ehc_module_ex(int verbose) { //extern int wbfs_part_fat; /* mload_ehc_fat = 0; if (mload_need_fat) { if (verbose) { if (strncasecmp(CFG.partition, "ntfs", 4) == 0) { printf("[NTFS]"); } else { printf("[FAT]"); } } if (IOS_GetRevision() < 4) { printf("\nERROR: IOS%u rev%u\n", IOS_GetVersion(), IOS_GetRevision()); printf(gt("FAT mode only supported with ios 222 rev4")); printf("\n"); sleep(5); return -1; } mload_ehc_fat = 1; size_ehcmodule = size_ehcmodule_frag; ehcmodule = ehcmodule_frag; size_dip_plugin = size_dip_plugin4; dip_plugin = dip_plugin4; if(external_ehcmodule_frag) { printf("\n"); printf_("external: %s\n", ehc_path_fat); printf_(""); ehcmodule = external_ehcmodule_frag; size_ehcmodule = size_external_ehcmodule_frag; } } else if (IOS_GetRevision() <= 2) { size_dip_plugin = size_dip_plugin2; dip_plugin = dip_plugin2; //size_ehcmodule = size_ehcmodule2; //ehcmodule = ehcmodule2; if(external_ehcmodule2) { //if (verbose) { printf("\n"); printf_("external: %s\n", ehc_path); printf_(""); //} ehcmodule = external_ehcmodule2; size_ehcmodule = size_external_ehcmodule2; } else { printf("\n"); printf(gt("ERROR: ehcmodule2 no longer included!\n" "external file ehcmodule.elf must be used!")); printf("\n"); sleep(5); return -1; } } else if (IOS_GetRevision() == 3) { size_dip_plugin = size_dip_plugin3; dip_plugin = dip_plugin3; //size_ehcmodule = size_ehcmodule3; //ehcmodule = ehcmodule3; if(external_ehcmodule3) { //if (verbose) { printf("\n"); printf_("external: %s\n", ehc_path3); printf_(""); //} ehcmodule = external_ehcmodule3; size_ehcmodule = size_external_ehcmodule3; } else { printf("\n"); printf(gt("ERROR: ehcmodule3 no longer included!\n" "external file ehcmodule3.elf must be used!")); printf("\n"); sleep(5); return -1; } } else if (IOS_GetRevision() == 4) { size_dip_plugin = size_dip_plugin4; dip_plugin = dip_plugin4; //size_ehcmodule = size_ehcmodule4; //ehcmodule = ehcmodule4; // use ehcmodule_frag also for wbfs size_ehcmodule = size_ehcmodule_frag; ehcmodule = ehcmodule_frag; if(external_ehcmodule4) { //if (verbose) { printf("\n"); printf_("external: %s\n", ehc_path4); printf_(""); //} ehcmodule = external_ehcmodule4; size_ehcmodule = size_external_ehcmodule4; } */ if (IOS_GetRevision() < 4) { printf("ERROR: IOS%d-mload v%d not supported!\n", IOS_GetVersion(), IOS_GetRevision()); sleep(10); return -1; } size_dip_plugin = size_odip_frag; dip_plugin = odip_frag; size_ehcmodule = size_ehcmodule5; ehcmodule = ehcmodule5; //mload_ehc_fat = 1; // force usb port 0 u8 *ehc_cfg = search_for_ehcmodule_cfg(ehcmodule, size_ehcmodule); if (ehc_cfg) { ehc_cfg += 12; ehc_cfg[0] = 0; // usb port 0 } // IOS_GetRevision() >= 4 dbg_printf("load ehc %d %d\n", size_dip_plugin, size_ehcmodule); int ret = load_ehc_module(); dbg_printf("load ehc = %d\n", ret); if (ret == 0) { dbg_printf("SDHC module\n"); mload_elf((void *) sdhc_module, &my_data_elf); my_thread_id= mload_run_thread(my_data_elf.start, my_data_elf.stack, my_data_elf.size_stack, my_data_elf.prio); dbg_printf("mload_run %d\n", my_thread_id); if(my_thread_id<0) ret = -5; } if (ret == 0) mk_mload_version(); mload_close(); return ret; #if 0 if (IOS_GetRevision() <= 2) { if (mload_module(ehcmodule, size_ehcmodule)<0) return -1; } else { // v3 if(mload_init()<0) return -1; mload_elf((void *) ehcmodule, &my_data_elf); my_thread_id= mload_run_thread(my_data_elf.start, my_data_elf.stack, my_data_elf.size_stack, my_data_elf.prio); if(my_thread_id<0) return -1; } usleep(350*1000); // Test for IOS int is_ios=0; mload_seek(0x20207c84, SEEK_SET); mload_read(patch_datas, 4); if(patch_datas[0]==0x6e657665) { is_ios=38; } else { is_ios=36; } if(is_ios==36) { // IOS 36 memcpy(ios_36, dip_plugin, 4); // copy the entry_point memcpy(dip_plugin, ios_36, 4*10); // copy the adresses from the array mload_seek(0x1377E000, SEEK_SET); // copy dip_plugin in the starlet mload_write(dip_plugin,size_dip_plugin); // enables DIP plugin mload_seek(0x20209040, SEEK_SET); mload_write(ios_36, 4); } if(is_ios==38) { // IOS 38 memcpy(ios_38, dip_plugin, 4); // copy the entry_point memcpy(dip_plugin, ios_38, 4*10); // copy the adresses from the array mload_seek(0x1377E000, SEEK_SET); // copy dip_plugin in the starlet mload_write(dip_plugin,size_dip_plugin); // enables DIP plugin mload_seek(0x20208030, SEEK_SET); mload_write(ios_38, 4); } mk_mload_version(); mload_close(); return 0; #endif } // Reload custom ios #include "usbstorage.h" #include "sdhc.h" #include "fat.h" #include "wbfs.h" #include "restart.h" #include "wpad.h" #include "wdvd.h" extern s32 wbfsDev; int ReloadIOS(int subsys, int verbose) { IOSPATCH_Apply(); int ret = -1; MountTable mnt; if (verbose) { printf_("IOS(%d) ", CFG.ios); if (CFG.ios_mload) printf("mload "); else if (CFG.ios_yal) printf("yal "); } if (CURR_IOS_IDX == CFG.game.ios_idx) { //&& is_ios_type(IOS_TYPE_WANIN)) return 0; printf("\n"); return 0; } /* mload_need_fat = 0; if (strncasecmp(CFG.partition, "fat", 3) == 0) { mload_need_fat = 1; } if (strncasecmp(CFG.partition, "ntfs", 4) == 0) { mload_need_fat = 1; } if (wbfsDev == WBFS_DEVICE_SDHC) { if (CFG.ios_mload) { // wbfs on sd with 222/223 requires fat module mload_need_fat = 1; } } if (CURR_IOS_IDX == CFG.game.ios_idx && mload_need_fat == mload_ehc_fat) { if (verbose) { if (mload_ehc_fat) { if (strncasecmp(CFG.partition, "ntfs", 4) == 0) { printf("[NTFS]"); } else { printf("[FAT]"); } } printf("\n\n"); } return 0; } if (CFG.ios_mload) { load_ext_ehc_module(verbose); } */ *mload_ver_str = 0; if (verbose) printf("."); // Close storage UnmountAll(&mnt); USBStorage_Deinit(); SDHC_Close(); // Close subsystems if (subsys) { Subsystem_Close(); WDVD_Close(); } Disable_Emu(); // deinit isfs, inited in get_iosinfo ISFS_Deinitialize(); /* Load Custom IOS */ dbg_printf("IOS_Reload(%d)\n", CFG.ios); usleep(100000); ret = IOS_ReloadIOS(CFG.ios); usleep(100000); if (ret < 0) { //if (verbose) { printf("\n"); printf_x(gt("ERROR:")); printf("\n"); printf_(gt("Custom IOS %d could not be loaded! (ret = %d)"), CFG.ios, ret); printf("\n"); //} goto err; } if (verbose) { printf("."); } // mload ehc & dip only for cIOS if (CFG.ios >= 202) { if (CFG.ios_mload) { ret = load_ehc_module_ex(verbose); if (ret < 0) { //if (verbose) { printf("\n"); printf_x(gt("ERROR: Loading EHC module! (%d)"), ret); printf("\n"); //} goto err; } } } if (is_ios_type(IOS_TYPE_WANIN) && IOS_GetRevision() >= 18) { //load_dip_249(); mk_mload_version(); mload_close(); } if (verbose) { printf("."); if (CFG.ios_mload) { printf("\n"); printf_(""); print_mload_version(); } } // re-Initialize Storage MountAll(&mnt); if (verbose) printf("."); // re-initialize subsystems if (subsys) { // wpad Wpad_Init(); // storage if (wbfsDev == WBFS_DEVICE_USB) { USBStorage_Init(); } if (wbfsDev == WBFS_DEVICE_SDHC) { SDHC_Init(); } // init dip ret = Disc_Init(); if (ret < 0) { //if (verbose) { printf("\n"); printf_x(gt("ERROR:")); printf("\n"); printf_(gt("Could not initialize DIP module! (ret = %d)"), ret); printf("\n"); //} goto err; } } if (verbose) printf(".\n"); CURR_IOS_IDX = CFG.game.ios_idx; return 0; err: if (subsys) { Wpad_Init(); Restart_Wait(); } return ret; } void Block_IOS_Reload() { if (CFG.game.block_ios_reload == 0) return; if (is_ios_d2x() >= 5) { // d2x ios reload block int es_fd = IOS_Open("/dev/es", 0); if (es_fd < 0) { printf("Couldn't open ES module\n"); sleep(5); return; } static ioctlv vector[0x08] ATTRIBUTE_ALIGN(32); static int mode ATTRIBUTE_ALIGN(32); static int ios ATTRIBUTE_ALIGN(32); mode = 2; ios = IOS_GetVersion(); vector[0].data = &mode; vector[0].len = 4; vector[1].data = &ios; vector[1].len = 4; int ret = IOS_Ioctlv(es_fd, 0xA0, 2, 0, vector); IOS_Close(es_fd); dbg_printf("d2x ios reload block %d: %d\n", ios, ret); if (ret < 0) { printf_("d2x IOS reload block FAILED!\n"); return; } goto out; } // if set to auto(2) and ios != d2x then don't do anything if (CFG.game.block_ios_reload == 2) return; if (CFG.ios_mload) { // hermes ios reload block patch_datas[0]=*((u32 *) (dip_plugin+16*4)); mload_set_ES_ioctlv_vector((void *) patch_datas[0]); } else { // unsupported printf_("IOS Reload Block only supported\nwith d2x and hermes cios\n"); sleep(3); return; } out: printf_(gt("IOS Reload: Blocked")); printf("\n"); if (CFG.game.block_ios_reload == 2) return; sleep(1); } u32 old_title_id = 0; void get_title_id() { u64 tid; if (ES_GetTitleID(&tid) >= 0) { old_title_id = (u32)tid; } else { // tid = (0x00010001ULL << 32) | *(u32 *)0x80000000; old_title_id = *(u32*)0x80000000; } if (old_title_id <= 2) { // HBC reload stub -> assuming boot from HBC old_title_id = HBC_LOWER_TID; } dbg_printf("channel id: %08X\n", old_title_id); } // by davebaol, WiiPower void d2x_return_to_channel() { if (CFG.return_to == 1) { CFG.return_to = old_title_id; if (CFG.return_to <= 2) { CFG.return_to = 0; } } if (CFG.return_to <= 2) return; if (is_ios_d2x() < 4) return; dbg_printf("d2x_return_to_channel %08x\n", CFG.return_to); static u64 sm_title_id ATTRIBUTE_ALIGN(32); // title id to be launched in place of the system menu sm_title_id = (0x00010001ULL << 32) | CFG.return_to; int ret; signed_blob *buf = NULL; u32 filesize; // Check if the title exists NeoGamma wants the cIOS to return to ret = GetTMD(sm_title_id, &buf, &filesize); SAFE_FREE(buf); if (ret != 0) { disable_return_to_patch = true; printf("Invalid return_to_channel=%08x\n", CFG.return_to); printf("Try using return_to_channel=auto\n"); printf("Which will use channel id: %08x\n", old_title_id); sleep(5); return; } static ioctlv vector[0x08] ATTRIBUTE_ALIGN(32); vector[0].data = &sm_title_id; vector[0].len = 8; int es_fd = IOS_Open("/dev/es", 0); if (es_fd < 0) { printf("Couldn't open ES module(2)\n"); sleep(5); return; } ret = IOS_Ioctlv(es_fd, 0xA1, 1, 0, vector); IOS_Close(es_fd); dbg_printf("d2x return to channel (%08x %d)\n", CFG.return_to, ret); if (ret >= 0) { // success disable_return_to_patch = true; } } u8 BCA_Data[64] ATTRIBUTE_ALIGN(32); int have_bca_data = 0; void load_bca_data(u8 *discid) { if (CFG.disable_bca) return; char filename[100]; int size = 0; void *buf = NULL; // ID6 snprintf(D_S(filename), "%s/%.6s.bca", USBLOADER_PATH, (char*)discid); size = Fat_ReadFile(filename, &buf); if (size <= 0) { // ID4 snprintf(D_S(filename), "%s/%.4s.bca", USBLOADER_PATH, (char*)discid); size = Fat_ReadFile(filename, &buf); } if (size < 64) { SAFE_FREE(buf); return; } printf_("BCA: %s\n", filename); memcpy(BCA_Data, buf, 64); have_bca_data = 1; SAFE_FREE(buf); } void Menu_Confirm_Exit() { printf_h("Press HOME to exit\n"); printf_h("Press any other button to continue\n"); if (CFG.home == CFG_HOME_SCRSHOT) { CFG.home = CFG_HOME_REBOOT; } Wpad_WaitButtonsCommon(); } int insert_bca_data() { if (!have_bca_data) return 0; if (!CFG.ios_mload || IOS_GetRevision() < 4) { printf(gt("ERROR: CIOS222/223 v4 required for BCA")); printf("\n"); sleep(2); return -1; } if(mload_init()<0) { printf("%s: BCA\n", gt("ERROR")); Menu_Confirm_Exit(); return -1; } // offset 15 (bca_data area) mload_seek(*((u32 *) (dip_plugin+15*4)), SEEK_SET); mload_write(BCA_Data, 64); mload_close(); have_bca_data = 2; return 0; } int verify_bca_data() { u8 tmp_data[64] ATTRIBUTE_ALIGN(32); int ret; if (have_bca_data != 2) return 0; printf("BCA:"); memset(tmp_data, 0xff, 64); ret = WDVD_Read_Disc_BCA(tmp_data); if (ret) { printf("%s: %d\n", gt("ERROR"), ret); goto fail; } printf("\n"); hex_dump3(BCA_Data, 64); if (memcmp(BCA_Data, tmp_data, 64) != 0) { printf("%s\n", gt("ERROR")); goto fail; } printf("%s\n", gt("OK")); return 0; fail: Menu_Confirm_Exit(); return -1; } // WANINKOKO DIP PLUGIN #if 0 void save_dip() { //int dip_buf[0x5000/sizeof(int)]; void *dip_buf = memalign(32,0x5000); int dip_size = 4000; printf("saving dip\n"); if(mload_init()<0) { printf("mload init\n"); sleep(3); return; } u32 base; int size; mload_get_load_base(&base, &size); printf("base: %08x %x\n", base, size); printf("mseek\n"); mload_seek(0x13800000, SEEK_SET); memset(dip_buf, 0, sizeof(dip_buf)); printf("mread\n"); mload_read(dip_buf, dip_size); printf("fopen\n"); FILE *f = fopen("sd:/dip.bin", "wb"); if (!f) { printf("fopen\n"); sleep(3); return; } printf("fwrite\n"); fwrite(dip_buf, dip_size, 1, f); fclose(f); printf("dip saved\n"); mload_close(); sleep(3); printf("unmount\n"); Fat_UnmountSDHC(); printf("exit\n"); exit(0); } void try_hello() { int ret; printf("mload init\n"); if(mload_init()<0) { sleep(3); return; } u32 base; int size; mload_get_load_base(&base, &size); printf("base: %08x %x\n", base, size); mload_close(); printf("disc init:\n"); ret = Disc_Init(); printf("= %d\n", ret); u32 x = 6; s32 WDVD_hello(u32 *status); ret = WDVD_hello(&x); printf("hello: %d %x %d\n", ret, x, x); ret = WDVD_hello(&x); printf("hello: %d %x %d\n", ret, x, x); sleep(1); //printf("exit\n"); //exit(0); } #endif #ifndef size_dip249 // #define size_dip249 5264 // r18-r20 #define size_dip249 5680 // r21 #endif extern u8 dip_plugin_249[size_dip249]; void load_dip_249() { int ret; // waninkoko cios rev18+ support mload if (!is_ios_type(IOS_TYPE_WANIN)) return; if (IOS_GetRevision() < 18) return; // d2x v6 already includes dip+frag if (is_ios_d2x() >= 6) return; WDVD_Close(); //printf("[FRAG]"); if(mload_init()<0) { printf("FRAG: mload_init ERROR\n"); sleep(5); return; } /* u32 base; int size; mload_get_load_base(&base, &size); printf("base: %08x %x\n", base, size); */ ret = mload_module(dip_plugin_249, size_dip249); if (ret < 0) { printf("FRAG: load ERROR %d\n", ret); sleep(5); } //printf("load mod: %d\n", ret); //mk_mload_version(); mload_close(); //printf("OK\n"); WDVD_Init(); } int get_ios_type() { switch (IOS_GetVersion()) { case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: return IOS_TYPE_WANIN; case 222: case 223: if (IOS_GetRevision() == 1) return IOS_TYPE_KWIIRK; case 224: return IOS_TYPE_HERMES; } return IOS_TYPE_UNK; } int is_ios_type(int type) { return (get_ios_type() == type); } int is_ios_d2x() { signed_blob *TMD = NULL; u32 TMD_size = 0; u64 title_id = TITLE_ID(1, IOS_GetVersion()); int ret; ret = GetTMD(title_id, &TMD, &TMD_size); if (ret >= 0) { iosinfo_t iosinfo; ret = get_iosinfo(IOS_GetVersion(), TMD, &iosinfo); SAFE_FREE(TMD); if (ret) { if (strcmp(iosinfo.name, "d2x") == 0) { return iosinfo.version; } } } if (is_ios_type(IOS_TYPE_WANIN)) { int rev = IOS_GetRevision(); if (rev > 21000 && rev < 25000) { return rev % 100; } } return 0; } s32 GetTMD(u64 TicketID, signed_blob **Output, u32 *Length) { signed_blob* TMD = NULL; u32 TMD_Length; s32 ret; /* Retrieve TMD length */ ret = ES_GetStoredTMDSize(TicketID, &TMD_Length); if (ret < 0) return ret; /* Allocate memory */ TMD = (signed_blob*)memalign(32, (TMD_Length+31)&(~31)); if (!TMD) return IPC_ENOMEM; /* Retrieve TMD */ ret = ES_GetStoredTMD(TicketID, TMD, TMD_Length); if (ret < 0) { free(TMD); return ret; } /* Set values */ *Output = TMD; *Length = TMD_Length; return 0; } s32 checkIOS(u32 IOS) { signed_blob *TMD = NULL; tmd *t = NULL; u32 TMD_size = 0; u64 title_id = 0; s32 ret = 0; // Get tmd to determine the version of the IOS title_id = (((u64)(1) << 32) | (IOS)); ret = GetTMD(title_id, &TMD, &TMD_size); if (ret == 0) { t = (tmd*)SIGNATURE_PAYLOAD(TMD); if (t->title_version == 65280) { // stub ret = -1; } } else { // not installed ret = -2; } free(TMD); return ret; } // ios base detection from NeoGamma R9 (by WiiPower) struct ios_hash_info { u32 slot; u32 hash[5]; char *info; }; static struct ios_hash_info ios_info[] = { { 249, {0x20e60607, 0x4e02c484, 0x2bbc5758, 0xee2b40fc, 0x35a68b0a}, "?? rev13a" }, { 249, {0x620c57c7, 0xd155b67f, 0xa451e2ba, 0xfb5534d7, 0xaa457878}, "?? rev13b" }, // rev 17 { 249, {0x369047f1, 0x4e37a34f, 0x3cca2936, 0xa60d527b, 0xac141d4a}, "38 rev17" }, { 249, {0x58ba3f8b, 0x7f8dccd3, 0x8b6c9109, 0x9a736e80, 0xc6c5ea67}, "38 rev17b" }, // rev 18 { 249, {0x3c968e54, 0x9e915458, 0x9ecc3bda, 0x16d0a0d4, 0x8cac7917}, "37 rev18" }, { 249, {0xe811bca8, 0xe1df1e93, 0x779c40e6, 0x2006e807, 0xd4403b97}, "38 rev18" }, { 249, {0x697676f0, 0x7a133b19, 0x881f512f, 0x2017b349, 0x6243c037}, "57 rev18" }, { 249, {0x34ec540b, 0xd1fb5a5e, 0x4ae7f069, 0xd0a39b9a, 0xb1a1445f}, "60 rev18" }, { 249, {0xd98a4dd9, 0xff426ddb, 0x1afebc55, 0x30f75489, 0x40b27ade}, "70 rev18" }, // rev 19 { 249, {0x0a49cd80, 0x6f8f87ff, 0xac9a10aa, 0xefec9c1d, 0x676965b9}, "37 rev19" }, { 249, {0x09179764, 0xeecf7f2e, 0x7631e504, 0x13b4b7aa, 0xca5fc1ab}, "38 rev19" }, { 249, {0x6010d5cf, 0x396415b7, 0x3c3915e9, 0x83ded6e3, 0x8f418d54}, "57 rev19" }, { 249, {0x589d6c4f, 0x6bcbd80a, 0xe768f258, 0xc53a322c, 0xd143f8cd}, "60 rev19" }, { 249, {0x8969e0bf, 0x7f9b2391, 0x31ecfd88, 0x1c6f76eb, 0xf9418fe6}, "70 rev19" }, // rev 20 { 249, {0x30aeadfe, 0x8b6ea668, 0x446578c7, 0x91f0832e, 0xb33c08ac}, "36 rev20" }, { 249, {0xba0461a2, 0xaa26eed0, 0x482c1a7a, 0x59a97d94, 0xa607773e}, "37 rev20" }, { 249, {0xb694a33e, 0xf5040583, 0x0d540460, 0x2a450f3c, 0x69a68148}, "38 rev20" }, { 249, {0xf6058710, 0xfe78a2d8, 0x44e6397f, 0x14a61501, 0x66c352cf}, "53 rev20" }, { 249, {0xfa07fb10, 0x52ffb607, 0xcf1fc572, 0xf94ce42e, 0xa2f5b523}, "55 rev20" }, { 249, {0xe30acf09, 0xbcc32544, 0x490aec18, 0xc276cee6, 0x5e5f6bab}, "56 rev20" }, { 249, {0x595ef1a3, 0x57d0cd99, 0x21b6bf6b, 0x432f6342, 0x605ae60d}, "57 rev20" }, { 249, {0x687a2698, 0x3efe5a08, 0xc01f6ae3, 0x3d8a1637, 0xadab6d48}, "60 rev20" }, { 249, {0xea6610e4, 0xa6beae66, 0x887be72d, 0x5da3415b, 0xa470523c}, "61 rev20" }, { 249, {0x64e1af0e, 0xf7167fd7, 0x0c696306, 0xa2035b2d, 0x6047c736}, "70 rev20" }, { 249, {0x0df93ca9, 0x833cf61f, 0xb3b79277, 0xf4c93cd2, 0xcd8eae17}, "80 rev20" }, // rev 21 { 249, {0x074dfb39, 0x90a5da61, 0x67488616, 0x68ccb747, 0x3a5b59b3}, "36 rev21" }, { 249, {0x6956a016, 0x59542728, 0x8d2efade, 0xad8ed01e, 0xe7f9a780}, "37 rev21" }, { 249, {0xdc8b23e6, 0x9d95fefe, 0xac10668a, 0x6891a729, 0x2bdfbca0}, "38 rev21" }, { 249, {0xaa2cdd40, 0xd628bc2e, 0x96335184, 0x1b51404c, 0x6592b992}, "53 rev21" }, { 249, {0x4a3d6d15, 0x014f5216, 0x84d65ffe, 0x6daa0114, 0x973231cf}, "55 rev21" }, { 249, {0xca883eb0, 0x3fe8e45c, 0x97cc140c, 0x2e2d7533, 0x5b369ba5}, "56 rev21" }, { 249, {0x469831dc, 0x918acc3e, 0x81b58a9a, 0x4493dc2c, 0xaa5e57a0}, "57 rev21" }, { 249, {0xe5af138b, 0x029201c7, 0x0c1241e7, 0x9d6a5d43, 0x37a1456a}, "58 rev21" }, { 249, {0x0fdee208, 0xf1d031d3, 0x6fedb797, 0xede8d534, 0xd3b77838}, "60 rev21" }, { 249, {0xaf588570, 0x13955a32, 0x001296aa, 0x5f30e37f, 0x0be91316}, "61 rev21" }, { 249, {0x50deaba2, 0x9328755c, 0x7c2deac8, 0x385ecb49, 0x65ea3b2b}, "70 rev21" }, { 249, {0x811b6a0b, 0xe26b9419, 0x7ffd4930, 0xdccd6ed3, 0x6ea2cdd2}, "80 rev21" }, // hermes { 222, {0xafbfc2c1, 0x28c59142, 0x953b1c6c, 0x809a984f, 0x427c9270}, "38 v4" }, { 222, {0xb72b71cd, 0xf42b2730, 0x3b9a4f2c, 0x41128ef9, 0x26f6dbcc}, "38+37 v4" }, { 222, {0xd6f1472f, 0x68740b4c, 0xbdf0078d, 0xb8ebb00a, 0x8c9afe2b}, "38+60 v4" }, // v5.0 { 222, {0xfa8ad097, 0x6c18542a, 0x5691bdec, 0xd0c47a6a, 0xbb857b08}, "38 v5.0" }, { 223, {0x07b9c8f2, 0xa0dbad4d, 0xa6ee0761, 0x7c371591, 0x4e4c63ec}, "37 v5.0" }, { 223, {0x0d0a12e0, 0x16065574, 0x844e39b4, 0x2d2dbdf1, 0x5b497869}, "57 v5.0" }, { 223, {0x0aa83bf0, 0x8fbd610f, 0x87bae3c1, 0x06f43826, 0x39524429}, "60 v5.0" }, // v5.1 { 222, {0xf865dfa5, 0xa909e4fb, 0x345f48ea, 0x804f5a64, 0x3704dd5a}, "38 v5.1" }, { 223, {0x889511aa, 0xdde5c849, 0xe30e6d20, 0x9687c95a, 0xb935342b}, "37 v5.1" }, { 223, {0x0584100d, 0xc3364080, 0xc3b8ffd0, 0x8c351aee, 0xf4632159}, "57 v5.1" }, { 223, {0x1cb7981c, 0xd791a2bf, 0x736395d6, 0x0224e181, 0x38324674}, "60 v5.1" }, // modmii special { 249, {0x00dc1209, 0x944c39db, 0x59eec2ab, 0x0212b86c, 0x7076cd3b}, "56 r21+r19 modmii" }, { 249, {0x00298dc2, 0x58fdae1a, 0x233b0958, 0x17269047, 0x8188633d}, "57 r21+r19 modmii" }, // d2x v1 { 249, {0x00ed2993, 0x0bae0cb2, 0xc7e430a2, 0x2e6eaf18, 0x156a9a70}, "37 r21-d2x-v1" }, { 249, {0x00d74607, 0x2d3fe23e, 0x47ecb019, 0x0f5d4380, 0x37ea6b50}, "38 r21-d2x-v1" }, { 249, {0x003d11ce, 0x4eb3b8bb, 0xe2c02fda, 0x5f879e74, 0x44a257de}, "56 r21-d2x-v1" }, { 249, {0x00ba4b4f, 0x27803366, 0x8d9121fa, 0x954eb5d5, 0x92242691}, "57 r21-d2x-v1" }, // d2x v2 { 249, {0x00475dce, 0x81a744dd, 0xf24157e4, 0x870fa3d8, 0xfc39fa8a}, "37 r21-d2x-v2" }, { 249, {0x00711af6, 0x017c48d4, 0xea0267d3, 0x1666600b, 0x38a8fe16}, "38 r21-d2x-v2" }, { 249, {0x00815782, 0x8604fe34, 0x474653b5, 0xbdbc5651, 0xf43b427a}, "56 r21-d2x-v2" }, { 249, {0x00d8e857, 0x8c96eb52, 0x4d006568, 0x95cf5415, 0xdb7712e8}, "57 r21-d2x-v2" }, // d2x v3 { 249, {0x0054e91c, 0xe022e307, 0x26d72e03, 0x53b6e157, 0x42adbe49}, "37 r21-d2x-v3" }, { 249, {0x000bd035, 0xe649cc22, 0x8bf647c5, 0xe0710e6a, 0xd79a5355}, "38 r21-d2x-v3" }, { 249, {0x00b8ca9c, 0x9b4053a3, 0x8de94a72, 0x1192fce5, 0x098e7404}, "56 r21-d2x-v3" }, { 249, {0x00e8e05f, 0x2aa4cd1e, 0x8c8f5529, 0x498f259b, 0xfa41258e}, "57 r21-d2x-v3" }, { 249, {0x0028dbf1, 0x3827be46, 0x28c82eb2, 0x122325c3, 0xc72dbd46}, "58 r21-d2x-v3" }, // d2x v3 (r21003) { 249, {0x006ec958, 0xbc59364d, 0x5b2f58a0, 0xf8feeac4, 0x89a0b697}, "37 r21-d2x-v3" }, { 249, {0x00fe6ad4, 0xbbf9a5e2, 0xeb2b0110, 0xc1fddbdf, 0xfb634350}, "38 r21-d2x-v3" }, { 249, {0x00ecc3a8, 0xec2d3b64, 0x506314e3, 0x740274ef, 0x6505cc75}, "56 r21-d2x-v3" }, { 249, {0x008e68fd, 0xa1221185, 0xc09a1a26, 0xfeb09ead, 0xf375c2f2}, "57 r21-d2x-v3" }, { 249, {0x006237ad, 0xda4cb0e1, 0xa97e4b41, 0xf1bb24a2, 0xd663b7f7}, "58 r21-d2x-v3" }, // d2x v4 (r21004) beta 2 { 249, {0x00733fa4, 0x1d3e6245, 0xb0311e24, 0x675868b1, 0x353d882c}, "37 r21-d2x-v4-b2" }, { 249, {0x007b9fca, 0x0a6f40c5, 0xccd37b25, 0x1c49064b, 0x1041ddb3}, "38 r21-d2x-v4-b2" }, { 249, {0x000d243c, 0x07a183df, 0x0592ce22, 0x2bb81b46, 0x64cce4a7}, "56 r21-d2x-v4-b2" }, { 249, {0x00c7b39a, 0xed42a4a0, 0xcc125669, 0xf23c1f6e, 0x2244cb9b}, "57 r21-d2x-v4-b2" }, { 249, {0x00120cb0, 0x4cb9b4b1, 0xbe02e0e6, 0x30bfcb95, 0xfbfcaba5}, "58 r21-d2x-v4-b2" }, // d2x v4 (r21004) release / hb installer { 249, {0xba124a8e, 0x73f5b2cb, 0x5e2439be, 0x76629335, 0xa3f36418}, "37 r21-d2x-v4" }, { 249, {0x2e5b15a4, 0x6e638735, 0x6d3d7403, 0xa78cdcc0, 0xe62a106b}, "38 r21-d2x-v4" }, { 249, {0xf13c731c, 0x3d77c021, 0x48c3119f, 0x7679939f, 0xbde8857f}, "53 r21-d2x-v4" }, { 249, {0x292464d3, 0xf94267d3, 0x849fd15c, 0x03200bde, 0xe8e0d6e8}, "55 r21-d2x-v4" }, { 249, {0xfefb9f74, 0x9961dd76, 0xe5416e0f, 0x7df6a95b, 0x923d2561}, "56 r21-d2x-v4" }, { 249, {0xb7272b2f, 0x72bdab83, 0x31d0639f, 0xfabc719d, 0xad818d91}, "57 r21-d2x-v4" }, { 249, {0x91a7d59f, 0x4ae0671a, 0x9bdf2593, 0xf7535426, 0x85af4073}, "58 r21-d2x-v4" }, // d2x v4 (r21004) release / modmii { 249, {0x00de8cad, 0x17183381, 0x889a1299, 0x834a85eb, 0x45b59e05}, "37 r21-d2x-v4" }, { 249, {0x0007e951, 0x173de10f, 0x0324b33f, 0xaa1f93c7, 0x28461fbe}, "38 r21-d2x-v4" }, { 249, {0x00f92f4f, 0x8f989389, 0xcd9e2732, 0x7752e50b, 0xa47fde40}, "53 r21-d2x-v4" }, { 249, {0x0056c457, 0x99c9a90f, 0xf0d9d994, 0x0724362a, 0xbe8ac29f}, "55 r21-d2x-v4" }, { 249, {0x00a1872f, 0x412f94cf, 0xd90c818b, 0xde15681e, 0x63c41b52}, "56 r21-d2x-v4" }, { 249, {0x00b06c85, 0xab7a94c2, 0x674785fc, 0x8f133335, 0xc9b84d49}, "57 r21-d2x-v4" }, { 249, {0x000530f4, 0x0c472b29, 0xb8f22f5a, 0x752b0613, 0x109bace1}, "58 r21-d2x-v4" }, /* // modmii 249 { 249, {0x005b6439, 0xf4a2e0b7, 0xfce05f75, 0xdb1a66ce, 0x7a0811c1}, "38 r17 modmii" }, { 249, {0x007da65a, 0x1b57b279, 0x06a5443f, 0xc61fd6cb, 0x4ea9866a}, "37 r19 modmii" }, { 249, {0x00cb38fc, 0x3abc550f, 0xc128f0aa, 0xa1dc96b8, 0x3d3ed542}, "38 r19 modmii" }, { 249, {0x00cc7ee1, 0xc1af6682, 0x8a5a2b6f, 0xc417eb3d, 0x607377ec}, "57 r19 modmii" }, { 249, {0x00e96e3f, 0xe861fd7a, 0x092d0fcb, 0xa65af414, 0xd375d6bb}, "38 r20 modmii" }, { 249, {0x009e5dde, 0x2589d21d, 0x4db9dfaa, 0x765c4279, 0xc4a5ba75}, "56 r20 modmii" }, { 249, {0x003c1bd8, 0x7830d7dc, 0x79e74949, 0x9609bb13, 0x4b5c5072}, "57 r20 modmii" }, { 249, {0x000f5724, 0xe6002c66, 0x6718313c, 0x8c4ec895, 0x478480ce}, "37 r21 modmii" }, { 249, {0x00c61cad, 0x30328d5d, 0xe69eb487, 0x27f77d5e, 0xc3c47d0d}, "38 r21 modmii" }, { 249, {0x00994d20, 0xbe74e78b, 0x00d4f00c, 0xfc9da208, 0x262c5f90}, "56 r21 modmii" }, { 249, {0x009fb539, 0x5a56f778, 0x329fbfd7, 0xc3a8ff58, 0x6fdb010b}, "57 r21 modmii" }, { 249, {0x002a7dfe, 0xdc36d6d9, 0x9af35191, 0x54862ecb, 0xd8087cb3}, "58 r21 modmii" }, // modmii 250 { 250, {0x00186ce5, 0xe6ced602, 0x552e621d, 0xaf882fb8, 0xa479e47b}, "37 r19 modmii" }, { 250, {0x00e2ea30, 0x56c4568d, 0x4f2c165d, 0xc00471bd, 0x6939c9f1}, "38 r19 modmii" }, { 250, {0x005849db, 0xa1fc4519, 0x530a963b, 0x31810e9e, 0xea1f207a}, "57 r19 modmii" }, { 250, {0x00641c3c, 0xa7346fa0, 0x0fa518a6, 0xeeac8097, 0x60eb2e87}, "38 r20 modmii" }, { 250, {0x009c97f0, 0xda7da42e, 0xd3320862, 0xb33d22db, 0xdc80b9e2}, "56 r20 modmii" }, { 250, {0x006d76ce, 0x0a294191, 0x62c9705d, 0x355ec87b, 0xff152dd5}, "57 r20 modmii" }, { 250, {0x006937f9, 0x8fdccb08, 0x4f9396b3, 0xc91b8761, 0x8ff1f1bb}, "37 r21 modmii" }, { 250, {0x004ba2f2, 0x9e4269c6, 0xe5d91fd0, 0x2e6410db, 0x772b1986}, "38 r21 modmii" }, { 250, {0x00bca8d8, 0x82105397, 0xb140ddb2, 0x8774d57a, 0x66418504}, "56 r21 modmii" }, { 250, {0x000ac379, 0x719a8850, 0x469445e7, 0xcf51108e, 0xb832d628}, "57 r21 modmii" }, { 250, {0x008567af, 0xe41cdb0b, 0xce85dc29, 0x10970d12, 0xe0b608f3}, "58 r21 modmii" }, // modmii hermes { 222, {0x00ec3a7b, 0xc9869c77, 0x013cf962, 0x4eef5726, 0xda9d1488}, "38 v4 modmii" }, { 223, {0x0073251f, 0x88b53db8, 0x390234af, 0x26910ff6, 0x041f3d3f}, "38+37 v4 modmii" }, { 222, {0x00d801b3, 0xe280e6e2, 0x1c99b236, 0x470ed5a9, 0xf3544f86}, "38 v5.0 modmii" }, { 223, {0x007d38f5, 0xb6b841b4, 0xf57579db, 0xa47526fe, 0xc3b3d12a}, "37 v5.0 modmii" }, { 223, {0x00f08071, 0x2672d68b, 0xc63bed5a, 0x06ae3b3c, 0xcff913d7}, "57 v5.0 modmii" }, */ }; const int ios_info_number = sizeof(ios_info) / sizeof(struct ios_hash_info); s32 brute_tmd(tmd *p_tmd) { u16 fill; for(fill=0; fill<65535; fill++) { p_tmd->fill3 = fill; sha1 hash; SHA1((u8 *)p_tmd, TMD_SIZE(p_tmd), hash);; if (hash[0]==0) { return 0; } } return -1; } s32 brute_modmii(signed_blob *TMD, int size, unsigned char *hash) { u16 fill; tmd *p_tmd = (tmd*)SIGNATURE_PAYLOAD(TMD); for(fill=0; fill<65535; fill++) { p_tmd->fill3 = fill; SHA1((u8 *)TMD, size, hash);; if (hash[0]==0) { return 0; } } return -1; } s32 read_file_from_nand(char *filepath, u8 **buffer, u32 *filesize) { s32 Fd; int ret; if (buffer == NULL) { //printf("NULL Pointer\n"); return -1; } Fd = ISFS_Open(filepath, ISFS_OPEN_READ); if (Fd < 0) { //printf("ISFS_Open %s failed %d\n", filepath, Fd); return Fd; } fstats *status; status = memalign(32, sizeof(fstats)); if (status == NULL) { //printf("Out of memory for status\n"); return -1; } ret = ISFS_GetFileStats(Fd, status); if (ret < 0) { //printf("ISFS_GetFileStats failed %d\n", ret); ISFS_Close(Fd); free(status); return -1; } *buffer = memalign(32, (status->file_length+31)&(~31)); if (*buffer == NULL) { //printf("Out of memory for buffer\n"); ISFS_Close(Fd); free(status); return -1; } ret = ISFS_Read(Fd, *buffer, status->file_length); if (ret < 0) { //printf("ISFS_Read failed %d\n", ret); ISFS_Close(Fd); free(status); free(*buffer); return ret; } ISFS_Close(Fd); *filesize = status->file_length; free(status); if (*filesize > 0) { DCFlushRange(*buffer, *filesize); ICInvalidateRange(*buffer, *filesize); } return 0; } bool get_iosinfo(int ios, signed_blob *TMD, iosinfo_t *iosinfo) { char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(0x20); u8 *buffer = NULL; u32 filesize; int ret; bool retval = false; ISFS_Initialize(); sprintf(filepath, "/title/%08x/%08x/content/%08x.app", 0x00000001, ios, *(u8 *)((u32)TMD+0x1E7)); ret = read_file_from_nand(filepath, &buffer, &filesize); // ISFS_Deinitialize(); // If executed, it causes Castlevania to freeze as soon as the game "sees" a wii mote // It is executed now before an IOS Reload is executed if (ret >= 0 && buffer) { memcpy(iosinfo, buffer, sizeof(*iosinfo)); if (iosinfo->magicword == 0x1ee7c105 && iosinfo->magicversion == 1) { retval = true; } } SAFE_FREE(buffer); return retval; } u8 get_base_ios_from_tmd(int ios_slot, u32 *version) { u8 retValue = 0; signed_blob *TMD = NULL; tmd *t = NULL; u32 TMD_size = 0; u64 title_id = TITLE_ID(1, ios_slot); u32 i; int retry_count = 0; sha1 hash; int ret; int is_modmii = 0; //static char default_info[32]; //sprintf(default_info, "IOS%u (Rev %u)", IOS_GetVersion(), IOS_GetRevision()); //info = (char *)default_info; ret = GetTMD(title_id, &TMD, &TMD_size); if (ret != 0) goto out; t = (tmd*)SIGNATURE_PAYLOAD(TMD); dbg_printf("\ntmd id: %llx %x-%x t: %x v: %d", t->title_id, TITLE_UPPER(t->title_id), TITLE_LOWER(t->title_id), t->title_type, t->title_version); if (version) *version = t->title_version; // safety check if (t->title_id != title_id) goto out; iosinfo_t iosinfo; if (get_iosinfo(ios_slot, TMD, &iosinfo)) { //sprintf(info, "%s%uv%u%s (%u)", iosinfo->name, iosinfo->baseios, iosinfo->version, iosinfo->versionstring, CIOS_VERSION); // Example: "d2x56v5beta2 (249)" // "56 r21-d2x-v4" retValue = iosinfo.baseios; goto out; } // modmii check // brute match? signed_blob *TMD_copy = malloc(TMD_size); memcpy(TMD_copy, TMD, TMD_size); tmd *tt = (tmd*)SIGNATURE_PAYLOAD(TMD_copy); brute_tmd(tt); int match = memcmp(TMD, TMD_copy, TMD_size) == 0; if (!match) dbg_printf("\nbrute match: %d %u %u\n", match, t->fill3, tt->fill3); SAFE_FREE(TMD_copy); SHA1((u8 *)TMD, TMD_size, hash); if (!match && hash[0] == 0) { is_modmii = 1; } retry:; if (retry_count) { if (retry_count > 100) goto out; brute_tmd(t); } retry_count++; SHA1((u8 *)TMD, TMD_size, hash); int mm; for (mm = 0; mm < 2; mm++) { for (i = 0; i < ios_info_number; i++) { if (ios_info[i].slot != TITLE_LOWER(t->title_id)) continue; if (memcmp((void *)hash, &ios_info[i].hash, sizeof(sha1)) == 0) { retValue = atoi(ios_info[i].info); break; } } if (retValue == 0 && is_modmii) { // use alternative brute hash // to search for modmii hashes in table brute_modmii(TMD, TMD_size, hash); } else { break; } } if (retValue == 0) { if (is_modmii == 1) { is_modmii++; // if modmii, first do the brute_tmd goto retry; } // patch title id, so hash matches if (ios_slot >= 245 && ios_slot <= 252) { if (t->title_id != TITLE_ID(1, 249)) { t->title_id = TITLE_ID(1, 249); goto retry; } if (ios_slot == 250) { // ios 250 has a fixed version of 65535 patch to a lower one if (t->title_version > 13) { if (t->title_version > 21) { t->title_version = 21; } else { t->title_version--; } goto retry; } } } if (t->title_id == TITLE_ID(1, 224)) { t->title_id = TITLE_ID(1, 223); goto retry; } if (t->title_id == TITLE_ID(1, 223)) { t->title_id = TITLE_ID(1, 222); goto retry; } } out: SAFE_FREE(TMD); return retValue; } char* get_iosx_info_from_tmd(int ios_slot, u32 *version) { signed_blob *TMD = NULL; tmd *t = NULL; u32 TMD_size = 0; u64 title_id = TITLE_ID(1, ios_slot); u32 i; int retry_count = 0; sha1 hash; int ret; char *info = NULL; static char info_str[32]; int is_modmii = 0; //static char default_info[32]; //sprintf(default_info, "IOS%u (Rev %u)", IOS_GetVersion(), IOS_GetRevision()); //info = (char *)default_info; ret = GetTMD(title_id, &TMD, &TMD_size); if (ret != 0) goto out; t = (tmd*)SIGNATURE_PAYLOAD(TMD); dbg_printf("\ntmd id: %llx %x-%x t: %x v: %d", t->title_id, TITLE_UPPER(t->title_id), TITLE_LOWER(t->title_id), t->title_type, t->title_version); if (version) *version = t->title_version; // safety check if (t->title_id != title_id) goto out; iosinfo_t iosinfo; if (get_iosinfo(ios_slot, TMD, &iosinfo)) { //sprintf(info, "%s%uv%u%s (%u)", iosinfo->name, iosinfo->baseios, iosinfo->version, iosinfo->versionstring, CIOS_VERSION); // Example: "d2x56v5beta2 (249)" // "56 r21-d2x-v4" info = info_str; sprintf(info, "%u %s v%u%s", iosinfo.baseios, iosinfo.name, iosinfo.version, iosinfo.versionstring); goto out; } // modmii check // brute match? signed_blob *TMD_copy = malloc(TMD_size); memcpy(TMD_copy, TMD, TMD_size); tmd *tt = (tmd*)SIGNATURE_PAYLOAD(TMD_copy); brute_tmd(tt); int match = memcmp(TMD, TMD_copy, TMD_size) == 0; if (!match) dbg_printf("\nbrute match: %d %u %u\n", match, t->fill3, tt->fill3); SAFE_FREE(TMD_copy); SHA1((u8 *)TMD, TMD_size, hash); if (!match && hash[0] == 0) { is_modmii = 1; } retry:; if (retry_count) { if (retry_count > 100) goto out; brute_tmd(t); } retry_count++; SHA1((u8 *)TMD, TMD_size, hash); int mm; for (mm = 0; mm < 2; mm++) { for (i = 0; i < ios_info_number; i++) { if (ios_info[i].slot != TITLE_LOWER(t->title_id)) continue; if (memcmp((void *)hash, &ios_info[i].hash, sizeof(sha1)) == 0) { info = ios_info[i].info; break; } } if (info == NULL && is_modmii) { // use alternative brute hash // to search for modmii hashes in table brute_modmii(TMD, TMD_size, hash); } else { break; } } if (info == NULL) { if (is_modmii == 1) { is_modmii++; // if modmii, first do the brute_tmd goto retry; } // patch title id, so hash matches if (ios_slot >= 245 && ios_slot <= 252) { if (t->title_id != TITLE_ID(1, 249)) { t->title_id = TITLE_ID(1, 249); goto retry; } if (ios_slot == 250) { // ios 250 has a fixed version of 65535 patch to a lower one if (t->title_version > 13) { if (t->title_version > 21) { t->title_version = 21; } else { t->title_version--; } goto retry; } } } if (t->title_id == TITLE_ID(1, 224)) { t->title_id = TITLE_ID(1, 223); goto retry; } if (t->title_id == TITLE_ID(1, 223)) { t->title_id = TITLE_ID(1, 222); goto retry; } } out: SAFE_FREE(TMD); if (info && is_modmii) { if (!strstr(info, "modmii")) { strcpy(info_str, info); strcat(info_str, " modmii"); info = info_str; } } return info; } void fill_base_array() { int i = 0; ISFS_Initialize(); for (i = 0; i < 11; i++) { cIOS_base[i] = 0; } cIOS_base[0] = get_base_ios_from_tmd(245, NULL);// CFG_IOS_245 cIOS_base[1] = get_base_ios_from_tmd(246, NULL);// CFG_IOS_246 cIOS_base[2] = get_base_ios_from_tmd(247, NULL);// CFG_IOS_247 cIOS_base[3] = get_base_ios_from_tmd(248, NULL);// CFG_IOS_248 cIOS_base[4] = get_base_ios_from_tmd(249, NULL);// CFG_IOS_249 cIOS_base[5] = get_base_ios_from_tmd(250, NULL);// CFG_IOS_250 cIOS_base[6] = get_base_ios_from_tmd(251, NULL);// CFG_IOS_251 cIOS_base[7] = get_base_ios_from_tmd(252, NULL);// CFG_IOS_252 cIOS_base[8] = get_base_ios_from_tmd(222, NULL);// CFG_IOS_222 cIOS_base[9] = get_base_ios_from_tmd(223, NULL);// CFG_IOS_223 cIOS_base[10] = get_base_ios_from_tmd(224, NULL);// CFG_IOS_224 } char* get_ios_info_from_tmd() { return get_iosx_info_from_tmd(IOS_GetVersion(), NULL); } void get_all_ios_info_str(char *str, int size) { int i; char *info; int ret; for (i=222; i<=252; i++) { if (i > 224 && i < 245) continue; snprintf(str, size, "IOS%d ", i); str_seek_end(&str, &size); ret = checkIOS(i); if (ret == -2) { snprintf(str, size, ": not installed\n"); } else if (ret == -1) { snprintf(str, size, ": stub\n"); } else { u32 ver; info = get_iosx_info_from_tmd(i, &ver); snprintf(str, size, "Base: %s (r%u)\n", info ? info : "??", ver); } str_seek_end(&str, &size); } /* isfs_stats_t st ATTRIBUTE_ALIGN(32); memset(&st, 0, sizeof(st)); ret = ISFS_GetStats(&st); snprintf(str, size, "%d NAND Free Blocks: %d %d %d\n", ret, st.free_blocks, st.block_size, st.used_blocks); */ } void print_all_ios_info_str(char *str, int size) { static int got_ios = 0; static char ios_info_str[400]; if (!got_ios) { get_all_ios_info_str(ios_info_str, sizeof(ios_info_str)); got_ios = 1; } strcopy(str, ios_info_str, size); } void print_all_ios_info(FILE *f) { char str[400]; print_all_ios_info_str(str, sizeof(str)); fprintf(f, "%s", str); } char* get_ios_tmd_hash_str(char *str) { signed_blob *TMD = NULL; tmd *t = NULL; u32 TMD_size = 0; char *info = NULL; int ret = GetTMD((((u64)(1) << 32) | (IOS_GetVersion())), &TMD, &TMD_size); if (ret != 0) goto out; t = (tmd*)SIGNATURE_PAYLOAD(TMD); dbg_printf("\ntmd id: %llx %x-%x t: %x v: %d", t->title_id, TITLE_UPPER(t->title_id), TITLE_LOWER(t->title_id), t->title_type, t->title_version); // safety check if (t->title_id != TITLE_ID(1, IOS_GetVersion())) goto out; sha1 hash; SHA1((u8 *)TMD, TMD_size, hash); int *x = (int*)&hash; sprintf(str, "{0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x},", x[0], x[1], x[2], x[3], x[4]); info = str; out: SAFE_FREE(TMD); return info; } bool shadow_mload() { if (!is_ios_type(IOS_TYPE_HERMES)) return false; int v51 = (5 << 4) | 1; if (mload_ver >= v51) { // shadow /dev/mload supported in hermes cios v5.1 printf_("[shadow "); //IOS_Open("/dev/usb123/OFF",0);// this disables ehc completely IOS_Open("/dev/mload/OFF",0); printf("mload]\n"); return true; } return false; } u16 get_miosinfo() { u16 mios = CFG_MIOS; struct tm time; // Timestamp of DML r52 strptime("Mar 7 2012 19:36:06", "%b %d %Y %H:%M:%S", &time); const time_t dml_r52_time = mktime(&time); // Timestamp of DML 1.2 strptime("Apr 24 2012 19:44:08", "%b %d %Y %H:%M:%S", &time); const time_t dml_1_2_time = mktime(&time); // Timestamp of DML 1.4b //strptime("May 7 2012 21:12:47", "%b %d %Y %H:%M:%S", &time); //const time_t dml_1_4b_time = mktime(&time); // Timestamp of DML 1.5 //strptime("Jun 14 2012 00:05:09", "%b %d %Y %H:%M:%S", &time); //const time_t dml_1_5_time = mktime(&time); // Timestamp of DM 2.0 //strptime("Jun 23 2012 19:43:21", "%b %d %Y %H:%M:%S", &time); //const time_t dm_2_0_time = mktime(&time); // Timestamp of DM 2.1 strptime("Jul 17 2012 11:25:35", "%b %d %Y %H:%M:%S", &time); const time_t dm_2_1_time = mktime(&time); // Timestamp of DM 2.2 initial release strptime("Jul 18 2012 16:57:47", "%b %d %Y %H:%M:%S", &time); const time_t dm_2_2_time = mktime(&time); // Timestamp of DM 2.2 update2 //strptime("Jul 20 2012 14:49:47", "%b %d %Y %H:%M:%S", &time); //const time_t dm_2_2_2_time = mktime(&time); // Timestamp of DML 2.2 initial release strptime("Aug 6 2012 15:19:17", "%b %d %Y %H:%M:%S", &time); const time_t dml_2_2_time = mktime(&time); // Timestamp of DML 2.2 update1 //strptime("Aug 13 2012 00:12:46", "%b %d %Y %H:%M:%S", &time); //const time_t dml_2_2_1_time = mktime(&time); // Timestamp of DML 2.3 mirror link //strptime("Sep 24 2012 13:13:42", "%b %d %Y %H:%M:%S", &time); //const time_t dml_2_3m_time = mktime(&time); // Timestamp of DM 2.3 //strptime("Sep 24 2012 15:51:54", "%b %d %Y %H:%M:%S", &time); //const time_t dm_2_3_time = mktime(&time); // Timestamp of DML 2.3 main link //strptime("Sep 25 2012 03:03:41", "%b %d %Y %H:%M:%S", &time); //const time_t dml_2_3_time = mktime(&time); // Timestamp of DM 2.4 //strptime("Oct 21 2012 22:57:12", "%b %d %Y %H:%M:%S", &time); //const time_t dm_2_4_time = mktime(&time); // Timestamp of DML 2.4 //strptime("Oct 21 2012 22:57:17", "%b %d %Y %H:%M:%S", &time); //const time_t dml_2_4_time = mktime(&time); // Timestamp of DM 2.5 //strptime("Nov 9 2012 21:18:52", "%b %d %Y %H:%M:%S", &time); //const time_t dm_2_5_time = mktime(&time); // Timestamp of DML 2.5 //strptime("Nov 9 2012 21:18:56", "%b %d %Y %H:%M:%S", &time); //const time_t dml_2_5_time = mktime(&time); // Timestamp of DM 2.6.0 // Dec 1 2012 01:52:53 // Timestamp of DML 2.6 // Dec 1 2012 16:22:29 // Timestamp of DM 2.6.1 // Dec 1 2012 16:42:34 // Timestamp of DM 2.7 // Feb 20 2013 14:54:33 // Timestamp of DML 2.7 // Feb 21 2013 03:13:49 // Timestamp of DML 2.8 // Feb 24 2013 13:30:29 // Timestamp of DM 2.8 // Feb 24 2013 14:17:03 // Timestamp of DML 2.9 // Apr 5 2013 18:20:33 // Timestamp of DM 2.9 // Apr 5 2013 18:29:35 // Timestamp of DML 2.10 // May 24 2013 18:51:58 strptime("May 24 2013 18:51:58", "%b %d %Y %H:%M:%S", &time); const time_t dml_2_10_time = mktime(&time); // Timestamp of DM 2.10 // May 24 2013 21:22:22 strptime("May 24 2013 21:22:22", "%b %d %Y %H:%M:%S", &time); const time_t dm_2_10_time = mktime(&time); u32 size = 0; u32 i = 0; s32 ret = 0; u8 *appfile = NULL; ISFS_Initialize(); dbg_printf("Reading 0000000c.app from MIOS\n"); ret = read_file_from_nand("/title/00000001/00000101/content/0000000c.app", &appfile, &size); if(ret >= 0 && appfile) { dbg_printf("Scanning 0000000c.app from MIOS\n"); for(i = 0; i < size; ++i) { if((*(vu32*)(appfile+i)) == 0x44494F53 && (*(vu32*)(appfile+i+5)) == 0x4D494F53) //DIOS MIOS { if(*(vu32*)(appfile+i+10) == 0x4C697465) //Lite { char *buffer = (char*)(appfile+i+31); strptime(buffer, "%b %d %Y %H:%M:%S", &time); time_t unixTime = mktime(&time); strcpy(dm_boot_drive, "sd:"); mios = CFG_DML_R52; sprintf(DIOS_MIOS_INFO, "DIOS MIOS Lite\n%s", buffer); dbg_printf("\nMIOS is %s", DIOS_MIOS_INFO); if (difftime(unixTime, dml_2_10_time) >= 0) { dbg_printf("\nMIOS is DIOS MIOS Lite 2.10+\n"); sprintf(DIOS_MIOS_INFO, "DIOS MIOS Lite 2.10+\n%s\n", buffer); mios = CFG_DM_2_2; } else if (difftime(unixTime, dml_2_2_time) >= 0) { dbg_printf("\nMIOS is DIOS MIOS Lite 2.2+\n"); sprintf(DIOS_MIOS_INFO, "DIOS MIOS Lite 2.2+\n%s\n", buffer); mios = CFG_DM_2_2; } else if (difftime(unixTime, dml_1_2_time) >= 0) { dbg_printf("\nMIOS is DIOS MIOS Lite 1.2+\n"); sprintf(DIOS_MIOS_INFO, "DIOS MIOS Lite 1.2+\n%s\n", buffer); mios = CFG_DML_1_2; } else if (difftime(unixTime, dml_r52_time) >= 0) { dbg_printf("\nMIOS is DIOS MIOS Lite r52+\n"); sprintf(DIOS_MIOS_INFO, "DIOS MIOS Lite r52+\n%s\n", buffer); mios = CFG_DML_R52; } else { dbg_printf("\nMIOS is DIOS MIOS Lite r51-\n"); sprintf(DIOS_MIOS_INFO, "DIOS MIOS Lite r51-\n%s\n", buffer); mios = CFG_DML_R51; } break; } else { char *buffer = (char*)(appfile+i+27); strcpy(dm_boot_drive, "usb:"); mios = CFG_DM_2_0; sprintf(DIOS_MIOS_INFO, "DIOS MIOS\n%s", buffer); dbg_printf("\nMIOS is %s", DIOS_MIOS_INFO); strptime(buffer, "%b %d %Y %H:%M:%S", &time); time_t unixTime = mktime(&time); if (difftime(unixTime, dm_2_10_time) >= 0) { dbg_printf("\nMIOS is DIOS MIOS 2.10+\n"); sprintf(DIOS_MIOS_INFO, "DIOS MIOS 2.10+\n%s\n", buffer); mios = CFG_DM_2_2; } else if (difftime(unixTime, dm_2_2_time) >= 0) { dbg_printf("\nMIOS is DIOS MIOS 2.2+\n"); sprintf(DIOS_MIOS_INFO, "DIOS MIOS 2.2+\n%s\n", buffer); mios = CFG_DM_2_2; } else if (difftime(unixTime, dm_2_1_time) >= 0) { dbg_printf("\nMIOS is DIOS MIOS 2.1\n"); sprintf(DIOS_MIOS_INFO, "DIOS MIOS 2.1\n%s\n", buffer); mios = CFG_DM_2_1; } else { dbg_printf("\nMIOS is DIOS MIOS 2.0+\n"); sprintf(DIOS_MIOS_INFO, "DIOS MIOS 2.0+\n%s\n", buffer); mios = CFG_DM_2_0; } break; } } } SAFE_FREE(appfile); } if (mios == CFG_MIOS) strcpy(dm_boot_drive, "usb:"); return mios; } void *allocate_memory(u32 size) { void *temp; temp = memalign(32, (size+31)&(~31) ); memset(temp, 0, (size+31)&(~31) ); return temp; } s32 Identify_GenerateTik(signed_blob **outbuf, u32 *outlen) { signed_blob *buffer = NULL; sig_rsa2048 *signature = NULL; tik *tik_data = NULL; u32 len; /* Set ticket length */ len = STD_SIGNED_TIK_SIZE; /* Allocate memory */ buffer = (signed_blob *)memalign(32, len); if (!buffer) return -1; /* Clear buffer */ memset(buffer, 0, len); /* Generate signature */ signature = (sig_rsa2048 *)buffer; signature->type = ES_SIG_RSA2048; /* Generate ticket */ tik_data = (tik *)SIGNATURE_PAYLOAD(buffer); strcpy(tik_data->issuer, "Root-CA00000001-XS00000003"); memset(tik_data->cidx_mask, 0xFF, 32); /* Set values */ *outbuf = buffer; *outlen = len; return 0; } s32 identify(u64 titleid, u8 *tmdBuffer, u32 tmdSize) { char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32); signed_blob *tikBuffer = NULL; u32 tikSize; u8 *certBuffer = NULL; u32 certSize; s32 ret; Identify_GenerateTik(&tikBuffer,&tikSize); sprintf(filepath, "/sys/cert.sys"); ret = read_file_from_nand(filepath, &certBuffer, &certSize); if (ret < 0) { dbg_printf("Reading certs failed\n"); free(tikBuffer); return ret; } //Print("done\n"); ret = ES_Identify((signed_blob*)certBuffer, certSize, (signed_blob*)tmdBuffer, tmdSize, tikBuffer, tikSize, NULL); if (ret < 0) { switch(ret) { case ES_EINVAL: dbg_printf("Error! ES_Identify (ret = %d;) Data invalid!\n", ret); break; case ES_EALIGN: dbg_printf("Error! ES_Identify (ret = %d;) Data not aligned!\n", ret); break; case ES_ENOTINIT: dbg_printf("Error! ES_Identify (ret = %d;) ES not initialized!\n", ret); break; case ES_ENOMEM: dbg_printf("Error! ES_Identify (ret = %d;) No memory!\n", ret); break; default: dbg_printf("Error! ES_Identify (ret = %d)\n", ret); break; } free(tikBuffer); free(certBuffer); return ret; } //Print("done\n"); free(tikBuffer); free(certBuffer); return 0; }