mirror of
https://github.com/nitraiolo/CfgUSBLoader.git
synced 2025-01-09 01:40:43 +01:00
a7a54c7439
Compilation - added all prebuild libraries for old PPC versions
2162 lines
54 KiB
C
2162 lines
54 KiB
C
#include <stdio.h>
|
|
#include <ogcsys.h>
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
|
|
#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;
|
|
} |