diff --git a/Makefile b/Makefile index 9ec65392..132c4efd 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ SOURCES := source source/libwiigui source/images source/fonts source/sounds \ source/libwbfs source/unzip source/language source/mload source/patches \ source/usbloader source/xml source/network source/settings source/prompts \ source/ramdisc source/wad source/banner source/cheats source/homebrewboot +DATA := data INCLUDES := source #--------------------------------------------------------------------------------- @@ -150,6 +151,13 @@ language: $(wildcard $(PROJECTDIR)/Languages/*.lang) @echo $(notdir $<) $(bin2o) +%.certs.o : %.certs + @echo $(notdir $<) + $(bin2o) +%.dat.o : %.dat + @echo $(notdir $<) + $(bin2o) + export PATH := $(PROJECTDIR)/gettext-bin:$(PATH) diff --git a/data/certs.dat b/data/certs.dat new file mode 100644 index 00000000..2184107d Binary files /dev/null and b/data/certs.dat differ diff --git a/data/haxx.certs b/data/haxx.certs new file mode 100644 index 00000000..32dd50ca Binary files /dev/null and b/data/haxx.certs differ diff --git a/gui.pnproj b/gui.pnproj index 58b282f6..509ea2e0 100644 --- a/gui.pnproj +++ b/gui.pnproj @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gui.pnps b/gui.pnps index 9504be5f..be6e1712 100644 --- a/gui.pnps +++ b/gui.pnps @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/source/menu.cpp b/source/menu.cpp index 5c7fc04e..e2c863f8 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -44,6 +44,7 @@ #include "fatmounter.h" #include "buffer.h" #include "xml/xml.h" +#include "wad/title.h" #include "usbloader/wdvd.h" @@ -706,7 +707,7 @@ int MenuDiscList() if (Settings.godmode == 1) w.Append(&homebrewBtn); - if((Settings.hddinfo == hr12)||(Settings.hddinfo == hr24)) + if((Settings.hddinfo == hr12)||(Settings.hddinfo == hr24)) { w.Append(&clockTimeBack); w.Append(&clockTime); diff --git a/source/prompts/TitleBrowser.cpp b/source/prompts/TitleBrowser.cpp index 19e451e2..30ddbd57 100644 --- a/source/prompts/TitleBrowser.cpp +++ b/source/prompts/TitleBrowser.cpp @@ -2,7 +2,7 @@ * TitleBrowser * USB Loader GX 2009 * - * TitleBrowser.cpp + * TitleBrowser.cpp *giantpune* ***************************************************************************/ #include "language/gettext.h" #include "libwiigui/gui.h" @@ -45,6 +45,8 @@ int TitleBrowser(u32 type) FILE *f; char path[100]; + ISFS_Initialize(); + sprintf(path,"%s/config/database.txt",bootDevice); f = fopen(path, "r"); @@ -55,12 +57,6 @@ int TitleBrowser(u32 type) //exit(1); } - // Die if we can't handle this many - if (num_titles > 100){ - //printf("\tError! Too many titles! (%u)\n", num_titles); - //exit(1); - } - // Get titles of our requested type ret = getTitles_Type(type, titles, num_titles); if (ret < 0){ @@ -82,10 +78,11 @@ int TitleBrowser(u32 type) //exit(1); } - - + + //this array will hold all the names for the titles so we only have to get them one time + char name[num_titles+num_sys_titles][50]; - customOptionList options3(num_titles+num_sys_titles); + customOptionList options3(num_titles+num_sys_titles+1); //write the titles on the option browser u32 i = 0; @@ -95,45 +92,54 @@ int TitleBrowser(u32 type) while (i < num_titles){ //start from the beginning of the file each loop if (f)rewind(f); - char name[50]; + //char name[50]; char text[15]; - strcpy(name,"");//make sure name is empty - + strcpy(name[i],"");//make sure name is empty + u8 found=0; //set the title's name, number, ID to text sprintf(text, "%s", titleText(type, titles[i])); - //getTitle_Name(name, TITLE_ID(type, titles[i]), text); //get name from database cause i dont like the ADT function char line[200]; char tmp[50]; snprintf(tmp,50,tmp," "); - snprintf(name,sizeof(name),"Unknown Title"); + //snprintf(name[i],sizeof(name[i]),"Unknown Title"); - if (!f) { - sprintf(name,"Unknown--"); - } - else + if(f) { while (fgets(line, sizeof(line), f)) { if (line[0]== text[0]&& line[1]== text[1]&& line[2]== text[2]) { int j=0; + found=1; for(j=0;(line[j+4]!='\0' || j<51);j++) tmp[j]=line[j+4]; - snprintf(name,sizeof(name),"%s",tmp); - break; - + snprintf(name[i],sizeof(name[i]),"%s",tmp); + //break; + } + } + } + if(!found) + { + if (getName00(name[i], TITLE_ID(type, titles[i]),CONF_GetLanguage()*2)>=0) + found=2; + + if(!found) + { + if (getNameBN(name[i], TITLE_ID(type, titles[i]))>=0) + found=3; + + if(!found) + snprintf(name[i],sizeof(name[i]),"Unknown Title (%08x)",titles[i]); } - } - } //set the text to the option browser options3.SetName(i, "%s",text); - options3.SetValue(i, "%s",name); - //options3.SetValue(i, " (%08x)",titles[i]);//use this line to show the number to call to launch the channel + options3.SetValue(i, "%s",name[i]); + //options3.SetValue(i, " (%08x) %s",titles[i],name[i]);//use this line to show the number to call to launch the channel //move on to the next title i++; } @@ -142,49 +148,66 @@ int TitleBrowser(u32 type) while (i < num_titles+num_sys_titles){ //start from the beginning of the file each loop if (f)rewind(f); - char name[50]; + //char name[50]; char text[15]; - strcpy(name,"");//make sure name is empty - + strcpy(name[i],"");//make sure name is empty + u8 found=0; //set the title's name, number, ID to text sprintf(text, "%s", titleText(0x00010002, sys_titles[i-num_titles])); - //getTitle_Name(name, TITLE_ID(0x00010002, sys_titles[i-num_titles]), text); //get name from database cause i dont like the ADT function char line[200]; char tmp[50]; snprintf(tmp,50,tmp," "); - snprintf(name,sizeof(name),"Unknown Title"); - - if (!f) { - sprintf(name,"Unknown--"); - } - else + //snprintf(name[i],sizeof(name[i]),"Unknown Title"); + if(f) { while (fgets(line, sizeof(line), f)) { if (line[0]== text[0]&& line[1]== text[1]&& line[2]== text[2]) { int j=0; + found=1; for(j=0;(line[j+4]!='\0' || j<51);j++) tmp[j]=line[j+4]; - snprintf(name,sizeof(name),"%s",tmp); + snprintf(name[i],sizeof(name[i]),"%s",tmp); break; - } - + } + } + if(!found) + { + if (getName00(name[i], TITLE_ID(0x00010002, sys_titles[i-num_titles]))>=0) + found=2; + + if(!found) + { + if (getNameBN(name[i], TITLE_ID(0x00010002, sys_titles[i-num_titles]))>=0) + found=3; + + if(!found) + snprintf(name[i],sizeof(name[i]),"Unknown Title (%08x)",sys_titles[i-num_titles]); + } } - } //set the text to the option browser options3.SetName(i, "%s",text); - options3.SetValue(i, "%s",name); - //options3.SetValue(i, " (%08x)",titles[i]); + options3.SetValue(i, "%s",name[i]); + //options3.SetValue(i, " (%08x) %s",titles[i],name[i]);//use this line to show the number to call to launch the channel //move on to the next title i++; } + if(i == num_titles+num_sys_titles) + { options3.SetName(i, " "); + options3.SetValue(i, "%s",tr("Wii Settings")); + } + //we have all the titles we need so close the database and stop poking around in the wii + fclose(f); + //get rid of our footprints in there + Uninstall_FromTitle(TITLE_ID(1, 0)); + ISFS_Deinitialize(); bool exit = false; GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); @@ -231,7 +254,7 @@ int TitleBrowser(u32 type) if(num_titles > 9) scrollbaron = 1; - GuiCustomOptionBrowser optionBrowser3(396, 280, &options3, CFG.theme_path, "bg_options_gamesettings.png", bg_options_settings_png, num_titles>9?1:0, 200); + GuiCustomOptionBrowser optionBrowser3(396, 280, &options3, CFG.theme_path, "bg_options_gamesettings.png", bg_options_settings_png, num_titles+num_sys_titles>9?1:0, 200); optionBrowser3.SetPosition(0, 90); optionBrowser3.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); @@ -244,6 +267,8 @@ int TitleBrowser(u32 type) mainWindow->Append(&w); + + int tmp=num_titles+num_sys_titles; ResumeGui(); numtitle=num_titles; while(!exit) @@ -259,50 +284,25 @@ int TitleBrowser(u32 type) if(ret > -1) {//if a click happened - char name[50]; + //char name[50]; char text[15]; if (f)rewind(f); - strcpy(name,"");//make sure name is empty + //strcpy(name,"");//make sure name is empty if (ret"); - } - else - { - while (fgets(line, sizeof(line), f)) { - if (line[0]== text[0]&& - line[1]== text[1]&& - line[2]== text[2]) - { int j=0; - for(j=0;(line[j+4]!='\0' || j<51);j++) - - tmp[j]=line[j+4]; - snprintf(name,sizeof(name),"%s",tmp); - break; - } - } - } char temp[100]; //prompt to boot selected title - snprintf(temp, sizeof(temp), "%s : %s",text,name); + snprintf(temp, sizeof(temp), "%s : %s",text,name[ret]); int choice = WindowPrompt(tr("Boot?"), temp, tr("OK"), tr("Cancel")); if(choice) {//if they say yes //stop all this stuff before starting the channel - fclose(f); + CloseXMLDatabase(); ExitGUIThreads(); ShutdownAudio(); @@ -322,59 +322,46 @@ int TitleBrowser(u32 type) } else//if they clicked a system title { - //set the title's name, number, ID to text - sprintf(text, "%s", titleText(0x00010002, sys_titles[ret-num_titles])); - getTitle_Name(name, TITLE_ID(0x00010002, sys_titles[ret-num_titles]), text); - - //get name from database cause i dont like the ADT function - char line[200]; - char tmp[50]; - snprintf(tmp,50,tmp," "); - snprintf(name,sizeof(name),"Unknown Title"); - - if (!f) { - sprintf(name,"Unknown--"); - } - else - { - while (fgets(line, sizeof(line), f)) { - if (line[0]== text[0]&& - line[1]== text[1]&& - line[2]== text[2]) - { int j=0; - for(j=0;(line[j+4]!='\0' || j<51);j++) - - tmp[j]=line[j+4]; - snprintf(name,sizeof(name),"%s",tmp); - break; - } - } - } - char temp[100]; - //prompt to boot selected title - snprintf(temp, sizeof(temp), "%s : %s May not boot correctly if your System Menu is not up to date.",text,name); - int choice = WindowPrompt(tr("Boot?"), temp, tr("OK"), tr("Cancel")); - if(choice) {//if they say yes - - - //stop all this stuff before starting the channel - fclose(f); - CloseXMLDatabase(); - ExitGUIThreads(); - ShutdownAudio(); - StopGX(); + if(ret == tmp) + { + CloseXMLDatabase(); + ExitGUIThreads(); + ShutdownAudio(); + StopGX(); WII_Initialize(); - WII_LaunchTitle(TITLE_ID(0x00010002,sys_titles[ret-num_titles])); - //this really shouldn't be needed because the title will be booted - exit = true; - break; - } - else{ - //if they said no to booting the title - ret = -1; - optionBrowser3.ResetState(); - } + WII_ReturnToSettings(); + } + else + { + //set the title's name, number, ID to text + sprintf(text, "%s", titleText(0x00010002, sys_titles[ret-num_titles])); + + char temp[100]; + //prompt to boot selected title + snprintf(temp, sizeof(temp), "%s : %s May not boot correctly if your System Menu is not up to date.",text,name[ret]); + int choice = WindowPrompt(tr("Boot?"), temp, tr("OK"), tr("Cancel")); + if(choice) {//if they say yes + + + //stop all this stuff before starting the channel + + CloseXMLDatabase(); + ExitGUIThreads(); + ShutdownAudio(); + StopGX(); + WII_Initialize(); + WII_LaunchTitle(TITLE_ID(0x00010002,sys_titles[ret-num_titles])); + //this really shouldn't be needed because the title will be booted + exit = true; + break; + } + else{ + //if they said no to booting the title + ret = -1; + optionBrowser3.ResetState(); + } + } } } diff --git a/source/svnrev.c b/source/svnrev.c index 0ca73268..39029821 100644 --- a/source/svnrev.c +++ b/source/svnrev.c @@ -1,4 +1,4 @@ -#define SVN_REV "669M" +#define SVN_REV "672M" const char *GetRev() { diff --git a/source/wad/id.c b/source/wad/id.c new file mode 100644 index 00000000..fe77d02d --- /dev/null +++ b/source/wad/id.c @@ -0,0 +1,210 @@ +/*------------------------------------------------------------- + +id.c -- ES Identification code + +Copyright (C) 2008 tona +Unless other credit specified + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1.The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2.Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3.This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#include +#include +#include + +#include "id.h" +#include "patchmii_core.h" + +#include "certs_dat.h" + + +// Turn upper and lower into a full title ID +#define TITLE_ID(x,y) (((u64)(x) << 32) | (y)) +// Get upper or lower half of a title ID +#define TITLE_UPPER(x) ((u32)((x) >> 32)) +// Turn upper and lower into a full title ID +#define TITLE_LOWER(x) ((u32)(x)) + + +/* Debug functions adapted from libogc's es.c */ +//#define DEBUG_ES +//#define DEBUG_IDENT +#define ISALIGNED(x) ((((u32)x)&0x1F)==0) + +static u8 su_tmd[0x208] ATTRIBUTE_ALIGN(32); +static u8 su_tik[STD_SIGNED_TIK_SIZE] ATTRIBUTE_ALIGN(32); +int su_id_filled = 0; + + +/* Reads a file from ISFS to an array in memory */ +s32 ISFS_ReadFileToArray (const char *filepath, u8 *filearray, u32 max_size, u32 *file_size) { + s32 ret, fd; + static fstats filestats ATTRIBUTE_ALIGN(32); + + *file_size = 0; + ret = ISFS_Open(filepath, ISFS_OPEN_READ); + if (ret <= 0) + { + //printf("Error! ISFS_Open (ret = %d)\n", ret); + return -1; + } + + fd = ret; + + ret = ISFS_GetFileStats(fd, &filestats); + if (ret < 0) + { + //printf("Error! ISFS_GetFileStats (ret = %d)\n", ret); + return -1; + } + + *file_size = filestats.file_length; + + if (*file_size > max_size) + { + //printf("File is too large! Size: %u Max: %u", *file_size, max_size); + return -1; + } + + ret = ISFS_Read(fd, filearray, *file_size); + *file_size = ret; + if (ret < 0) + { + //printf("Error! ISFS_Read (ret = %d)\n", ret); + return -1; + } + else if (ret != filestats.file_length) + { + //printf("Error! ISFS_Read Only read: %d\n", ret); + return -1; + } + + ret = ISFS_Close(fd); + if (ret < 0) + { + //printf("Error! ISFS_Close (ret = %d)\n", ret); + return -1; + } + return 0; +} + +void Make_SUID(void){ + signed_blob *s_tmd, *s_tik; + tmd *p_tmd; + tik *p_tik; + + memset(su_tmd, 0, sizeof su_tmd); + memset(su_tik, 0, sizeof su_tik); + s_tmd = (signed_blob*)&su_tmd[0]; + s_tik = (signed_blob*)&su_tik[0]; + *s_tmd = *s_tik = 0x10001; + p_tmd = (tmd*)SIGNATURE_PAYLOAD(s_tmd); + p_tik = (tik*)SIGNATURE_PAYLOAD(s_tik); + + + strcpy(p_tmd->issuer, "Root-CA00000001-CP00000004"); + p_tmd->title_id = TITLE_ID(1,2); + + p_tmd->num_contents = 1; + + forge_tmd(s_tmd); + + strcpy(p_tik->issuer, "Root-CA00000001-XS00000003"); + p_tik->ticketid = 0x000038A45236EE5FLL; + p_tik->titleid = TITLE_ID(1,2); + + memset(p_tik->cidx_mask, 0xFF, 0x20); + forge_tik(s_tik); + + su_id_filled = 1; + +} + +s32 Identify(const u8 *certs, u32 certs_size, const u8 *idtmd, u32 idtmd_size, const u8 *idticket, u32 idticket_size) { + s32 ret; + u32 keyid = 0; + ret = ES_Identify((signed_blob*)certs, certs_size, (signed_blob*)idtmd, idtmd_size, (signed_blob*)idticket, idticket_size, &keyid); + /*if (ret < 0){ + switch(ret){ + case ES_EINVAL: + printf("Error! ES_Identify (ret = %d;) Data invalid!\n", ret); + break; + case ES_EALIGN: + printf("Error! ES_Identify (ret = %d;) Data not aligned!\n", ret); + break; + case ES_ENOTINIT: + printf("Error! ES_Identify (ret = %d;) ES not initialized!\n", ret); + break; + case ES_ENOMEM: + printf("Error! ES_Identify (ret = %d;) No memory!\n", ret); + break; + default: + printf("Error! ES_Identify (ret = %d)\n", ret); + break; + } + } + else + printf("OK!\n");*/ + return ret; +} + + +s32 Identify_SU(void) { + if (!su_id_filled) + Make_SUID(); + + //printf("\nIdentifying as SU..."); + //fflush(stdout); + return Identify(certs_dat, certs_dat_size, su_tmd, sizeof su_tmd, su_tik, sizeof su_tik); +} + +s32 Identify_SysMenu(void) { + s32 ret; + u32 sysmenu_tmd_size, sysmenu_ticket_size; + //static u8 certs[0xA00] ATTRIBUTE_ALIGN(32); + static u8 sysmenu_tmd[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(32); + static u8 sysmenu_ticket[STD_SIGNED_TIK_SIZE] ATTRIBUTE_ALIGN(32); + + /*printf("\nPulling Certs..."); + ret = ISFS_ReadFileToArray ("/sys/certs.sys", certs, 0xA00, &certs_size); + if (ret < 0) { + printf("\tReading Certs failed!\n"); + return -1; + }*/ + + //printf("\nPulling Sysmenu TMD..."); + ret = ISFS_ReadFileToArray ("/title/00000001/00000002/content/title.tmd", sysmenu_tmd, MAX_SIGNED_TMD_SIZE, &sysmenu_tmd_size); + if (ret < 0) { + //printf("\tReading TMD failed!\n"); + return -1; + } + + //printf("\nPulling Sysmenu Ticket..."); + ret = ISFS_ReadFileToArray ("/ticket/00000001/00000002.tik", sysmenu_ticket, STD_SIGNED_TIK_SIZE, &sysmenu_ticket_size); + if (ret < 0) { + //printf("\tReading TMD failed!\n"); + return -1; + } + + //printf("\nIdentifying as SysMenu..."); + //fflush(stdout); + return Identify(certs_dat, certs_dat_size, sysmenu_tmd, sysmenu_tmd_size, sysmenu_ticket, sysmenu_ticket_size); +} diff --git a/source/wad/id.h b/source/wad/id.h new file mode 100644 index 00000000..067c3d08 --- /dev/null +++ b/source/wad/id.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------- + +id.h -- ES Identification code + +Copyright (C) 2008 tona +Unless other credit specified + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1.The origin of this software must not be misrepresented; you +must not claim that you wrote the original software. If you use +this software in a product, an acknowledgment in the product +documentation would be appreciated but is not required. + +2.Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3.This notice may not be removed or altered from any source +distribution. + +-------------------------------------------------------------*/ + +#ifndef _ID_H_ +#define _ID_H_ + +// Identify as the "super user" +s32 Identify_SU(void); + +// Identify as the system menu +s32 Identify_SysMenu(void); + +#endif diff --git a/source/wad/patchmii_core.c b/source/wad/patchmii_core.c new file mode 100644 index 00000000..02356956 --- /dev/null +++ b/source/wad/patchmii_core.c @@ -0,0 +1,94 @@ +/* patchmii_core -- low-level functions to handle the downloading, patching + and installation of updates on the Wii + + Copyright (C) 2008 bushing / hackmii.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "patchmii_core.h" +#include "sha1.h" + +#define ALIGN(a,b) ((((a)+(b)-1)/(b))*(b)) + +int http_status = 0; +int tmd_dirty = 0, tik_dirty = 0, temp_ios_slot = 0; + +// yeah, yeah, I know. +signed_blob *s_tmd = NULL, *s_tik = NULL, *s_certs = NULL; +static u8 tmdbuf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(0x20); +static u8 tikbuf[STD_SIGNED_TIK_SIZE] ATTRIBUTE_ALIGN(0x20); + + +void zero_sig(signed_blob *sig) { + u8 *sig_ptr = (u8 *)sig; + memset(sig_ptr + 4, 0, SIGNATURE_SIZE(sig)-4); +} + +void brute_tmd(tmd *p_tmd) { + u16 fill; + for(fill=0; fill<65535; fill++) { + p_tmd->fill3=fill; + sha1 hash; + // debug_printf("SHA1(%p, %x, %p)\n", p_tmd, TMD_SIZE(p_tmd), hash); + SHA1((u8 *)p_tmd, TMD_SIZE(p_tmd), hash);; + + if (hash[0]==0) { + // debug_printf("setting fill3 to %04hx\n", fill); + return; + } + } + printf("Unable to fix tmd :(\n"); + exit(4); +} + +void brute_tik(tik *p_tik) { + u16 fill; + for(fill=0; fill<65535; fill++) { + p_tik->padding=fill; + sha1 hash; + // debug_printf("SHA1(%p, %x, %p)\n", p_tmd, TMD_SIZE(p_tmd), hash); + SHA1((u8 *)p_tik, sizeof(tik), hash); + + if (hash[0]==0) return; + } + printf("Unable to fix tik :(\n"); + exit(5); +} + +void forge_tmd(signed_blob *s_tmd) { +// debug_printf("forging tmd sig"); + zero_sig(s_tmd); + brute_tmd(SIGNATURE_PAYLOAD(s_tmd)); +} + +void forge_tik(signed_blob *s_tik) { +// debug_printf("forging tik sig"); + zero_sig(s_tik); + brute_tik(SIGNATURE_PAYLOAD(s_tik)); +} + + diff --git a/source/wad/patchmii_core.h b/source/wad/patchmii_core.h new file mode 100644 index 00000000..47488af5 --- /dev/null +++ b/source/wad/patchmii_core.h @@ -0,0 +1,63 @@ +#ifndef _PATCHMII_CORE_ +#define _PATCHMII_CORE_ + + +//Patchmii functions +void patchmii_network_init(void); +// Call with version = 0 to get the latest version +// Set "patch" if you want to try to patch title contents +s32 patchmii_install(u32 in_title_h, u32 in_title_l, u32 in_version, u32 out_title_h, u32 out_title_l, u32 out_version, bool patch); +s32 install_temporary_ios(u32 base_ios, u32 base_ver); +s32 load_temporary_ios(void); +s32 cleanup_temporary_ios(void); + +//Tools +void forge_tmd(signed_blob *s_tmd); +void forge_tik(signed_blob *s_tik); + +void spinner(void); + +#define TEMP_IOS + +// Basic I/O. + +static inline u32 read32(u32 addr) +{ + u32 x; + asm volatile("lwz %0,0(%1) ; sync" : "=r"(x) : "b"(0xc0000000 | addr)); + return x; +} + +static inline void write32(u32 addr, u32 x) +{ + asm("stw %0,0(%1) ; eieio" : : "r"(x), "b"(0xc0000000 | addr)); +} + +// USB Gecko. + +void usb_flush(int chn); +int usb_sendbuffer(int chn,const void *buffer,int size); + +// Version string. + +extern const char version[]; + +// Debug: blink the tray led. + +static inline void blink(void) +{ + write32(0x0d8000c0, read32(0x0d8000c0) ^ 0x20); +} + +void debug_printf(const char *fmt, ...); +void hexdump(FILE *fp, void *d, int len); +void aes_set_key(u8 *key); +void aes_decrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len); +void aes_encrypt(u8 *iv, u8 *inbuf, u8 *outbuf, unsigned long long len); + +#define TRACE(x) debug_printf("%s / %d: %d\n", __FUNCTION__, __LINE__, (x)) + +#define ISFS_ACCESS_READ 1 +#define ISFS_ACCESS_WRITE 2 + +#endif diff --git a/source/wad/sha1.c b/source/wad/sha1.c new file mode 100644 index 00000000..83a533a7 --- /dev/null +++ b/source/wad/sha1.c @@ -0,0 +1,172 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd if true. */ +#define SHA1HANDSOFF + +#include +#include +#include "sha1.h" + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifdef LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) +{ +unsigned long a, b, c, d, e; +typedef union { + unsigned char c[64]; + unsigned long l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +#ifdef SHA1HANDSOFF +static unsigned char workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) +{ +unsigned int i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ +unsigned long i, j; +unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *)"\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} + +void SHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf) { + SHA1_CTX ctx; + + SHA1Init(&ctx); + SHA1Update(&ctx, ptr, size); + SHA1Final(outbuf, &ctx); +} + diff --git a/source/wad/sha1.h b/source/wad/sha1.h new file mode 100644 index 00000000..757af1cd --- /dev/null +++ b/source/wad/sha1.h @@ -0,0 +1,12 @@ +typedef struct { + unsigned long state[5]; + unsigned long count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Transform(unsigned long state[5], unsigned char buffer[64]); +void SHA1Init(SHA1_CTX* context); +void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); +void SHA1Final(unsigned char digest[20], SHA1_CTX* context); + +void SHA1(unsigned char *ptr, unsigned int size, unsigned char *outbuf); diff --git a/source/wad/title.c b/source/wad/title.c index c36562a1..0fdfa9e9 100644 --- a/source/wad/title.c +++ b/source/wad/title.c @@ -8,6 +8,7 @@ #include "utils.h" #include "../settings/cfg.h" #include "fatmounter.h" +#include "id.h" #define MAX_TITLES 256 @@ -260,6 +261,113 @@ out: return ret; } +s32 Uninstall_RemoveTicket(u64 tid) +{ + static tikview viewdata[0x10] ATTRIBUTE_ALIGN(32); + + u32 cnt, views; + s32 ret; + +/* Get number of ticket views */ + ret = ES_GetNumTicketViews(tid, &views); + if (ret < 0) { + + return ret; + } + + if (!views) { + //printf(" No tickets found!\n"); + return 1; + } else if (views > 16) { + //printf(" Too many ticket views! (views = %d)\n", views); + return -1; + } + + /* Get ticket views */ + ret = ES_GetTicketViews(tid, viewdata, views); + if (ret < 0) { + //printf(" \n\tError! ES_GetTicketViews (ret = %d)\n", ret); + return ret; + } + + /* Remove tickets */ + for (cnt = 0; cnt < views; cnt++) { + ret = ES_DeleteTicket(&viewdata[cnt]); + if (ret < 0) { + //printf(" Error! (view = %d, ret = %d)\n", cnt, ret); + return ret; + } + } + //printf(" OK!\n"); + + return ret; +} + +s32 Uninstall_DeleteTitle(u32 title_u, u32 title_l) +{ + s32 ret; + char filepath[256]; + sprintf(filepath, "/title/%08x/%08x", title_u, title_l); + + /* Remove title */ + ret = ISFS_Delete(filepath); + return ret; +} + +s32 Uninstall_DeleteTicket(u32 title_u, u32 title_l) +{ + s32 ret; + + char filepath[256]; + sprintf(filepath, "/ticket/%08x/%08x.tik", title_u, title_l); + + /* Delete ticket */ + ret = ISFS_Delete(filepath); + + return ret; +} + +//carefull when using this function +//it will force remove stuff even if something fails +s32 Uninstall_FromTitle(const u64 tid) +{ + s32 contents_ret, tik_ret, title_ret, ret; + u32 id = tid & 0xFFFFFFFF, kind = tid >> 32; + contents_ret = tik_ret = title_ret = ret = 0; + + if (kind == 1) + { + // Delete title and ticket at FS level. + tik_ret = Uninstall_DeleteTicket(kind, id); + title_ret = Uninstall_DeleteTitle(kind, id); + contents_ret = title_ret; + } + else + { + // Remove title (contents and ticket) + tik_ret = Uninstall_RemoveTicket(tid); + contents_ret = ES_DeleteTitleContent(tid); + title_ret = ES_DeleteTitle(tid); + + + // Attempt forced uninstall if something fails + if (tik_ret < 0 || contents_ret < 0 || title_ret < 0){ + tik_ret = Uninstall_DeleteTicket(kind, id); + title_ret = Uninstall_DeleteTitle(kind, id); + contents_ret = title_ret; + + } + } + if (tik_ret < 0 && contents_ret < 0 && title_ret < 0) + ret = -1; + else if (tik_ret < 0 || contents_ret < 0 || title_ret < 0) + ret = 1; + else + ret = 0; + + return ret; +} + /*------------------------------------------------------------- taken from anytitledeleter @@ -268,104 +376,6 @@ out: Copyright (C) 2009 MrClick -------------------------------------------------------------*/ -// Max number of entries in the database -#define MAX_DB 1024 - -// Max name length -#define MAX_LINE 80 - -// Contains all title ids (e.g.: "HAC") -static char **__db_i; -// Contains all title names (e.g.: "Mii Channel") -static char **__db; -// Contains the number of entries in the database -static u32 __db_cnt = 0; - -s32 loadDatabase(){ - FILE *fdb; - - char dbfile[100]; - snprintf(dbfile,sizeof(dbfile),"SD:/database.txt"); - // Init SD card access, open database file and check if it worked - //fatInitDefault(); - SDCard_Init(); - fdb = fopen(dbfile, "r"); - if (fdb == NULL) - return -1; - - // Allocate memory for the database - __db_i = calloc(MAX_DB, sizeof(char*)); - __db = calloc(MAX_DB, sizeof(char*)); - - // Define the line buffer. Each line in the db file will be stored here first - char line[MAX_LINE]; - line[sizeof(line)] = 0; - - // Generic char buffer and counter variable - char byte; - u32 i = 0; - - // Read each character from the file - do { - byte = fgetc(fdb); - // In case a line was longer than MAX_LINE - if (i == -1){ - // Read bytes till a new line is hit - if (byte == 0x0A) - i = 0; - // In case were still good with the line length - } else { - // Add the new byte to the line buffer - line[i] = byte; - i++; - // When a new line is hit or MAX_LINE is reached - if (byte == 0x0A || i == sizeof(line) - 1) { - // Terminate finished line to create a string - line[i] = 0; - // When the line is not a comment or not to short - if (line[0] != '#' && i > 5){ - - // Allocate and copy title id to database - __db_i[__db_cnt] = calloc(4, sizeof(char*)); - memcpy(__db_i[__db_cnt], line, 3); - __db_i[__db_cnt][3] = 0; - // Allocate and copy title name to database - __db[__db_cnt] = calloc(i - 4, sizeof(char*)); - memcpy(__db[__db_cnt], line + 4, i - 4); - __db[__db_cnt][i - 5] = 0; - - // Check that the next line does not overflow the database - __db_cnt++; - if (__db_cnt == MAX_DB) - break; - } - // Set routine to ignore all bytes in the line when MAX_LINE is reached - if (byte == 0x0A) i = 0; else i = -1; - } - } - } while (!feof(fdb)); - - // Close database file; we are done with it - fclose(fdb); - - return 0; -} - - -void freeDatabase(){ - u32 i = 0; - for(; i < __db_cnt; i++){ - free(__db_i[i]); - free(__db[i]); - } - free(__db_i); - free(__db); -} - - -s32 getDatabaseCount(){ - return __db_cnt; -} s32 __convertWiiString(char *str, u8 *data, u32 cnt){ u32 i = 0; @@ -385,47 +395,6 @@ s32 __convertWiiString(char *str, u8 *data, u32 cnt){ return 0; } -s32 getNameDB(char* name, char* id){ - // Return fixed values for special entries - if (strncmp(id, "IOS", 3) == 0){ - sprintf(name, "Operating System %s", id); - return 0; - } - if (strncmp(id, "MIOS", 3) == 0){ - sprintf(name, "Gamecube Compatibility Layer"); - return 0; - } - if (strncmp(id, "SYSMENU", 3) == 0){ - sprintf(name, "System Menu"); - return 0; - } - if (strncmp(id, "BC", 2) == 0){ - sprintf(name, "BC"); - return 0; - } - - // Create an ? just in case the function aborts prematurely - sprintf(name, "?"); - - u32 i; - u8 db_found = 0; - // Compare each id in the database to the title id - for (i = 0; i < __db_cnt; i++) - if (strncmp(id, __db_i[i], 3) == 0){ - db_found = 1; - break; - } - - if (db_found == 0) - // Return -1 if no mathcing entry was found - return -1; - else { - // Get name from database once a matching id was found - sprintf(name, __db[i]); - return 0; - } -} - s32 getNameBN(char* name, u64 id){ // Terminate the name string just in case the function exits prematurely @@ -438,9 +407,9 @@ s32 getNameBN(char* name, u64 id){ // Bring the Wii into the title's userspace if (ES_SetUID(id) < 0){ // Should that fail repeat after setting permissions to system menu mode -// Identify_SysMenu(); -// if (ES_SetUID(id) < 0) -// return -1; + Identify_SysMenu(); + if (ES_SetUID(id) < 0) + return -1; } // Try to open file @@ -452,8 +421,8 @@ s32 getNameBN(char* name, u64 id){ // If it fails try to open again after identifying as SU if (fh == -102){ -// Identify_SU(); -// fh = ISFS_Open(file, ISFS_OPEN_READ); + Identify_SU(); + fh = ISFS_Open(file, ISFS_OPEN_READ); } // If the file won't open else if (fh < 0) @@ -494,11 +463,21 @@ s32 getNameBN(char* name, u64 id){ } -s32 getName00(char* name, u64 id){ +s32 getName00(char* name, u64 id, int lang){ +/* +languages +0jap +2eng +4german +6french +8spanish +10italian +12dutch +*/ // Create a string containing the absolute filename char file[256] __attribute__ ((aligned (32))); sprintf(file, "/title/%08x/%08x/content/00000000.app", (u32)(id >> 32), (u32)id); - + Identify_SU(); s32 fh = ISFS_Open(file, ISFS_OPEN_READ); @@ -510,8 +489,8 @@ s32 getName00(char* name, u64 id){ // In case there is some problem with the permission if (fh == -102){ // Identify as super user -// Identify_SU(); -// fh = ISFS_Open(file, ISFS_OPEN_READ); + Identify_SU(); + fh = ISFS_Open(file, ISFS_OPEN_READ); } else if (fh < 0) return fh; @@ -541,12 +520,16 @@ s32 getName00(char* name, u64 id){ free(data); // Assemble name - // Only the English name is returned - // There are 6 other language names in the str array - sprintf(name, "%s", str[2]); - if (strlen(str[3]) > 1) - sprintf(name, "%s (%s)", name, str[3]); - + if(strlen(str[lang]) > 1){ + sprintf(name, "%s", str[lang]); + if (strlen(str[lang+1]) > 1) + sprintf(name, "%s (%s)", name, str[lang+1]); + } + else{ + sprintf(name, "%s", str[2]); + if (strlen(str[3]) > 1) + sprintf(name, "%s (%s)", name, str[3]); + } // Job well done return 2; } @@ -575,35 +558,6 @@ s32 printContent(u64 tid){ } -s32 getTitle_Name(char* name, u64 id, char *tid){ - char buf[256] __attribute__ ((aligned (32))); - - s32 r = -1; - // Determine the title's name database/banner/00000000.app - r = getNameDB(buf, tid); - if (r < 0) - r = getNameBN(buf, id); - if (r < 0) - r = getName00(buf, id); - - switch (r){ - // In case a name was found in the database - case 0: sprintf(name, "%s", buf); - break; - // In case a name was found in the banner.bin - case 1: sprintf(name, "*%s*", buf); - break; - // In case a name was found in the 00000000.app - case 2: sprintf(name, "+%s+", buf); - break; - // In case no proper name was found return a ? - default: sprintf(name, "Unknown Title"); - break; - } - - return 0; -} - char *titleText(u32 kind, u32 title){ static char text[10]; @@ -684,7 +638,7 @@ s32 getTitles_TypeCount(u32 type, u32 *count) { upper = __title_list[i] >> 32; lower = __title_list[i] & 0xFFFFFFFF; if((upper == type)&& - ((lower !=0x48414741)&&//this filters out haga,haaa, hafa. dupe foctory channels that don't load + ((lower !=0x48414741)&&//this filters out haga,haaa, hafa. dupe factory channels that don't load (lower !=0x48414141)&&//since we dont care about apps that dont load for what we are doing (lower !=0x48414641))) type_count++; @@ -721,3 +675,6 @@ s32 getTitles_Type(u32 type, u32 *titles, u32 count) { } + + + diff --git a/source/wad/title.h b/source/wad/title.h index 03a68af2..3eb76a4b 100644 --- a/source/wad/title.h +++ b/source/wad/title.h @@ -39,26 +39,11 @@ s32 Title_GetSysVersion(u64, u64 *); s32 Title_GetSize(u64, u32 *); s32 Title_GetIOSVersions(u8 **, u32 *); -// Load the database from SD card -s32 loadDatabase(); - -// Free the database on exit -void freeDatabase(); - -// Get the number of entries in the database -s32 getDatabaseCount(); - -// Get the name of a title -s32 getTitle_Name(char *name, u64 id, char *tid); - -// Get the name of a title from the database located on the SD card -s32 getNameDB(char *name, char* id); - // Get the name of a title from its banner.bin in NAND s32 getNameBN(char *name, u64 id); // Get the name of a title from its 00000000.app in NAND -s32 getName00(char *name, u64 id); +s32 getName00(char *name, u64 id, int lang = 2); // Get string representation of lower title id char *titleText(u32 kind, u32 title); @@ -71,6 +56,11 @@ s32 getTitles_TypeCount(u32 type, u32 *count); // Get the list of titles of this type s32 getTitles_Type(u32 type, u32 *titles, u32 count); + +//returns a name for a title +char *__getTitleName(u64 titleid, int language); + +s32 Uninstall_FromTitle(const u64 tid); #ifdef __cplusplus } diff --git a/source/xml/xml.c b/source/xml/xml.c index 51f38710..da6cb8dc 100644 --- a/source/xml/xml.c +++ b/source/xml/xml.c @@ -331,7 +331,7 @@ void LoadTitlesFromXML(char *langtxt, bool forcejptoen) strcpy(title_text,title_text_EN); } - snprintf(id_text, 5, "%s",id_text); + snprintf(id_text, 7, "%s",id_text); title_set(id_text, title_text); } }