void BuildSaveListNand() { for( u32 j = 0; j < 3; j++ ) { u32 type; switch( j ) { case 0: type = 0x10000; break; case 1: type = 0x10001; break; case 2: type = 0x10004; break; } u32 cnt = NandTitles.SetType( type ); for( u32 i = 0; i < cnt; i++ ) { u64 tid = NandTitles.Next(); char pathBuf[ 65 ]__attribute__((aligned( 32 ))); snprintf( pathBuf, sizeof( pathBuf ), "/title/%08x/%08x/data/banner.bin", TITLE_UPPER( tid ), TITLE_LOWER( tid ) ); u8* buf; u32 len; int ret = -1234; if( ( ret = NandTitle::LoadFileFromNand( pathBuf, &buf, &len ) ) < 0 || !buf ) { //gprintf( "error loading: \"%s\" %i %p\n", pathBuf, ret, buf ); continue; } //gprintf( "load %016llx\n", tid ); BannerBin *save = new BannerBin( NULL, 0, tid ); if( !save->SetData( buf, len ) ) { gprintf( "error creating save: \"%s\"\n", pathBuf ); delete save; continue; } // get size u32 s1 = 0, s2 = 0; snprintf( pathBuf, sizeof( pathBuf ), "/title/%08x/%08x/data", TITLE_UPPER( tid ), TITLE_LOWER( tid ) ); if( !(ret = ISFS_GetUsage( pathBuf, &s1, &s2 )) ) { save->blocks = RU( s1, 8 ) / 8; } else { gprintf( "ISFS_GetUsage( \"%s\" ): %i\n", pathBuf, ret ); save->blocks = 0; } save->tid = tid; saveList << save; //return; } } }
static void Create_Channel_List() { for(u32 i = 0; i < ChannelHandle.Count(); i++) { chan = ChannelHandle.GetChannel(i); if(chan->id == NULL) continue; // Skip invalid channels memset((void*)&ListElement, 0, sizeof(dir_discHdr)); ListElement.index = m_gameList.size(); ListElement.settings[0] = TITLE_UPPER(chan->title); ListElement.settings[1] = TITLE_LOWER(chan->title); strncpy(ListElement.id, chan->id, 4); ListElement.casecolor = CustomTitles.getColor("COVERS", ListElement.id, 0xFFFFFF).intVal(); const char *CustomTitle = CustomTitles.getString("TITLES", ListElement.id).c_str(); if(gameTDB.IsLoaded()) { if(ListElement.casecolor == 0xFFFFFF) ListElement.casecolor = gameTDB.GetCaseColor(ListElement.id); ListElement.wifi = gameTDB.GetWifiPlayers(ListElement.id); ListElement.players = gameTDB.GetPlayers(ListElement.id); if(CustomTitle == NULL || CustomTitle[0] == '\0') gameTDB.GetTitle(ListElement.id, CustomTitle); } if(CustomTitle != NULL && CustomTitle[0] != '\0') mbstowcs(ListElement.title, CustomTitle, 63); else wcsncpy(ListElement.title, chan->name, 64); ListElement.type = TYPE_CHANNEL; m_gameList.push_back(ListElement); } }
void tell_cIOS_to_return_to_channel(void) { if (TITLE_UPPER(old_title_id) > 1 && TITLE_LOWER(old_title_id) > 2) // Don't change anything for system menu or no title id { static u64 sm_title_id ATTRIBUTE_ALIGN(32); sm_title_id = old_title_id; // title id to be launched in place of the system menu int ret; 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) { debug("Couldn't open ES module\n"); return; } ret = IOS_Ioctlv(es_fd, 0xA1, 1, 0, vector); debug ("tell_cIOS_to_return_to_channel = %d\n", ret); IOS_Close(es_fd); } }
bool NandTitle::Exists(u64 tid) { char app[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32); tmd* titleTmd = GetTMD(tid); if (!titleTmd) return false; u16 i; bool ok = false; for (i = 0; i < titleTmd->num_contents; i++) { if (!titleTmd->contents[i].index) { ok = true; break; } } if (!ok) return false; snprintf(app, sizeof(app), "/title/%08x/%08x/content/%08x.app", TITLE_UPPER( tid ), TITLE_LOWER( tid ), titleTmd->contents[i].cid); s32 fd = ISFS_Open(app, ISFS_OPEN_READ); if (fd >= 0) ISFS_Close(fd); //gprintf(" fd: %d\n", fd ); return fd >= 0 || fd == -102; //102 means it exists, but we dont have permission to open it }
u64 NandTitle::Next() { u64 ret = 0; //gprintf("Next( %08x, %u )\n", currentType, currentIndex ); u32 i; for (i = currentIndex; i < titleIds.size(); i++) { if (currentType) { if (currentType == TITLE_UPPER( titleIds.at( i ) )) { ret = titleIds.at(i); break; } } else { ret = titleIds.at(i); break; } } currentIndex = i + 1; return ret; }
u32 NandTitle::CountType(u32 type) { u32 ret = 0; for (u32 i = 0; i < titleIds.size(); i++) { if (TITLE_UPPER( titleIds.at( i ) ) == type) { ret++; } } return ret; }
GuiSaveIcon * IconSaveBrowser::GetSaveIcon(int i) { u64 tid = browser->GetItemSaveTid(browser->GetPageIndex() + i); char savepath[MAXPATHLEN]; snprintf(savepath, sizeof(savepath),"/title/%08x/%08x/data/banner.bin", TITLE_UPPER(tid),TITLE_LOWER(tid)); u8* buffer = NULL; u32 size = 0; Nand::LoadFile(savepath, &buffer, &size); GuiSaveIcon * Icon = new GuiSaveIcon(buffer, size); free(buffer); buffer = NULL; return Icon; }
bool PriiloaderCheck(u64 id) { if (TITLE_UPPER(id) == 1 && TITLE_LOWER(id) == 2) { char pl_tmd[ISFS_MAXPATH]; snprintf(pl_tmd, MAX_CHARACTERS(pl_tmd), "/title/00000001/00000002/content/title_or.tmd"); s32 cfd = ISFS_Open(pl_tmd, ISFS_OPEN_READ); if (cfd >= 0) { ISFS_Close(cfd); printf("Priiloader detected in System Menu!\n"); logfile("Priiloader detected in System Menu!\r\n"); return true; } } return false; }
s32 identify(u64 titleid, u32 *ios){ char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(0x20); u8 *tmdBuffer = NULL; u32 tmdSize; signed_blob *tikBuffer = NULL; u32 tikSize; u8 *certBuffer = NULL; u32 certSize; int ret; printf("Reading TMD..."); fflush(stdout); sprintf(filepath, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(titleid), TITLE_LOWER(titleid)); ret = read_file(filepath, &tmdBuffer, &tmdSize); if (ret < 0) { printf("Reading TMD failed\n"); return ret; } printf("done\n"); *ios = (u32)(tmdBuffer[0x18b]); printf("Generating fake ticket..."); fflush(stdout); /* sprintf(filepath, "/ticket/%08x/%08x.tik", TITLE_UPPER(titleid), TITLE_LOWER(titleid)); ret = read_file(filepath, &tikBuffer, &tikSize); if (ret < 0) { printf("Reading ticket failed\n"); free(tmdBuffer); return ret; }*/ Identify_GenerateTik(&tikBuffer,&tikSize); printf("done\n"); printf("Reading certs..."); fflush(stdout); sprintf(filepath, "/sys/cert.sys"); ret = read_file(filepath, &certBuffer, &certSize); if (ret < 0) { printf("Reading certs failed\n"); free(tmdBuffer); free(tikBuffer); return ret; } printf("done\n"); printf("ES_Identify..."); fflush(stdout); ret = ES_Identify((signed_blob*)certBuffer, certSize, (signed_blob*)tmdBuffer, tmdSize, tikBuffer, tikSize, NULL); 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; } free(tmdBuffer); free(tikBuffer); free(certBuffer); return ret; } printf("done\n"); free(tmdBuffer); free(tikBuffer); free(certBuffer); return 0; }
s32 *get_ioslist(u32 *cnt) { u64 *buf = 0; s32 res; u32 i, k = 0, tcnt = 0, icnt = 0; s32 *ioses = NULL; bool skip_title; /* Get stored IOS versions */ res = ES_GetNumTitles(&tcnt); if (res < 0) { printf("\t- ES_GetNumTitles: Error! (result = %ld).\n", res); return 0; } buf = memalign(32, sizeof(u64) * tcnt); if (!buf) { printf("\t- Error allocating titlelist memory buffer!\n"); return 0; } res = ES_GetTitles(buf, tcnt); if (res < 0) { printf("\t- ES_GetTitles: Error! (result = %ld).\n", res); free(buf); return 0; } for (i = 0; i < tcnt; i++) { /* Skip BC, MIOS, System Menu, BootMii IOS, BC-NAND, BC-WFS and stub IOSses */ if ((TITLE_UPPER(buf[i - k]) == 1) && (TITLE_LOWER(buf[i - k]) > 2) && (TITLE_LOWER(buf[i - k]) < 0xFE)) { u32 tmdSize = 0; tmd *iosTMD = NULL; signed_blob *iosTMDBuffer = NULL; /* Get stored TMD size */ res = ES_GetStoredTMDSize(buf[i - k], &tmdSize); if (res < 0) { printf("\t- ES_GetStoredTMDSize: Error! (result = %ld / IOS%lu).\n", res, ((u32)buf[i - k])); break; } iosTMDBuffer = (signed_blob*)memalign(32, (tmdSize+31)&(~31)); if (!iosTMDBuffer) { res = -1; printf("\t- Error allocating IOS%lu TMD buffer (size = %lu bytes).\n", ((u32)buf[i - k]), tmdSize); break; } memset(iosTMDBuffer, 0, tmdSize); /* Get stored TMD */ res = ES_GetStoredTMD(buf[i - k], iosTMDBuffer, tmdSize); if (res < 0) { printf("\t- ES_GetStoredTMD: Error! (result = %ld / IOS%lu).\n", res, ((u32)buf[i - k])); free(iosTMDBuffer); break; } iosTMD = (tmd*)SIGNATURE_PAYLOAD(iosTMDBuffer); /* Calculate title size */ u16 j; u32 titleSize = 0; for (j = 0; j < iosTMD->num_contents; j++) { tmd_content *content = &iosTMD->contents[j]; /* Add content size */ titleSize += content->size; } /* Check if this IOS is a stub */ skip_title = (titleSize < 0x100000); free(iosTMDBuffer); } else { skip_title = true; } if (!skip_title) { icnt++; } else { /* Move around memory blocks */ if ((tcnt - 1) > i) { memmove(&(buf[i - k]), &(buf[i - k + 1]), (sizeof(u64) * (tcnt - i - 1))); k++; } } } if (res < 0) { free(buf); return 0; } if (realloc(buf, sizeof(u64) * icnt) == NULL) { printf("\t- Error reallocating titlelist memory block!\n"); free(buf); return 0; } ioses = (s32 *)malloc(sizeof(s32) * icnt); if (!ioses) { printf("\t- Error allocating IOS memory buffer!\n"); free(buf); return 0; } for (i = 0; i < icnt; i++) ioses[i] = (s32)buf[i]; free(buf); qsort(ioses, icnt, sizeof(s32), __s32Cmp); *cnt = icnt; return ioses; }
s32 extractChannelContents(u64 titleID, char* location) { u32 TitleIDH=TITLE_UPPER(titleID); u32 TitleIDL=TITLE_LOWER(titleID); if(ES_SetUID(titleID)<0) return ERR_UID; u32 tmd_size ATTRIBUTE_ALIGN(32); if(ES_GetStoredTMDSize(titleID, &tmd_size)<0) return ERR_TMDSIZE; signed_blob *TMD = (signed_blob *)memalign( 32, tmd_size ); memset(TMD, 0, tmd_size); if(ES_GetStoredTMD(titleID, TMD, tmd_size)<0) { free(TMD); return ERR_TMD; } u32 cnt ATTRIBUTE_ALIGN(32); if(ES_GetNumTicketViews(titleID, &cnt)<0) { free(TMD); return ERR_TIKCOUNT; } if( cnt <= 0 ) { free(TMD); return ERR_TIKCOUNT; } tikview *views = (tikview *)memalign( 32, sizeof(tikview)*cnt ); if(ES_GetTicketViews(titleID, views, cnt)<0) { free(views); free(TMD); return ERR_TIK; } printf("Allocated and filled views.\n"); sleep(3); Identify_SU(); int z; tmd_content *TMDc = TMD_CONTENTS(((tmd*)(SIGNATURE_PAYLOAD(TMD)))); // OH GOD CREDIAR, WTF WAS THAT MESS! // List format is "XXXXXXXX = YYYYYYYY" where X is index, and Y is cid. char *lookup_list=calloc(21,((tmd*)(SIGNATURE_PAYLOAD(TMD)))->num_contents); ClearScreen(); printf("\nNumber of contents: %d\n",((tmd*)(SIGNATURE_PAYLOAD(TMD)))->num_contents); sleep(1); for(z=0; z < ((tmd*)(SIGNATURE_PAYLOAD(TMD)))->num_contents; z++) { /* Get Content */ char nameDirectory[80]; sprintf(nameDirectory,"/title/%08x/%08x/content/%08x.app",TitleIDH,TitleIDL,TMDc[z].cid); s32 contentFd=ISFS_Open(nameDirectory,ISFS_OPEN_READ); u8 *data=calloc(TMDc[z].size,1); if(contentFd<0) { switch(contentFd) { case ISFS_EINVAL: printf("FAILED! (Invalid Argument %s)\n\tQuitting...\n",nameDirectory); sleep(5); Finish(1); break; case ISFS_ENOMEM: printf("FAILED! (Out of memory %s)\n\tQuitting...\n",nameDirectory); sleep(5); Finish(1); break; default: goto skip; // Finish(1); break; } } int isUnaligned = ((int)data)%32 | TMDc[z].size%32; int alignedLen = (TMDc[z].size+31)&0xffffffe0; unsigned char* alignedBuf; if(isUnaligned) alignedBuf = memalign(32, alignedLen); else alignedBuf = data; ISFS_Seek(contentFd,0,0); ISFS_Read(contentFd, alignedBuf, alignedLen); // If it was unaligned, you have to copy it and clean up if(isUnaligned){ memcpy(data, alignedBuf, TMDc[z].size); free(alignedBuf); } ISFS_Close(contentFd); // Do copying here. // data is the actual content data (use fwrite with it :P). // Copy the file with it's index as it's filename char* destination=calloc(sizeof(location)+14, 1); char lookup_entry[21]; sprintf(destination, "%s/%08x.app",location,TMDc[z].index); sprintf(lookup_entry, "%08x = %08x\n",TMDc[z].index,TMDc[z].cid); strcat(lookup_list, lookup_entry); printf("Got destination as: %s\n", destination); sleep(3); FILE *dfd=fopen(destination,"wb+"); printf("Opened %s\n", destination); sleep(3); // free(destination); fwrite(data, TMDc[z].size, 1, dfd); printf("Wrote data to %s\n", destination); sleep(3); fclose(dfd); printf("Closed %s\n", destination); sleep(2); skip: _nop(); } // Make a file containing the lookups called files.txt char* lookup_file=calloc(sizeof(location)+14, 1); sprintf(lookup_file, "%s/files.txt",location); printf("Got destination as: %s\n", lookup_file); sleep(3); FILE* lfd=fopen(lookup_file,"wb+"); printf("Opened %s\n", lookup_file); sleep(3); // free(lookup_file); fwrite(lookup_list, 21, ((tmd*)SIGNATURE_PAYLOAD(TMD))->num_contents, lfd); printf("Wrote lookups to %s\n", lookup_file); sleep(3); fclose(lfd); printf("Closed %s\n", lookup_file); sleep(2); printf("Freed TMD and views"); sleep(1);
return ERR_NONE; } void changeChannelName(u64 titleID) { printf("Identifying as 00000001-00000000 (SU)!... "); CheckESRetval(ES_Identify(SU_IDENTIFY)); // if(ES_SetUID(titleID)<0) // return; u32 tmd_size ATTRIBUTE_ALIGN(32); if(CheckESRetval(ES_GetStoredTMDSize(titleID, &tmd_size))!=0) return; signed_blob *TMD = (signed_blob *)memalign( 32, tmd_size ); memset(TMD, 0, tmd_size); if(CheckESRetval(ES_GetStoredTMD(titleID, TMD, tmd_size))!=0) { free(TMD); return; } u32 cnt ATTRIBUTE_ALIGN(32); if(CheckESRetval(ES_GetNumTicketViews(titleID, &cnt))!=0) { free(TMD); return; } if( cnt <= 0 ) { free(TMD); return; } tikview *views = (tikview *)memalign( 32, sizeof(tikview)*cnt ); if(CheckESRetval(ES_GetTicketViews(titleID, views, cnt))!=0) { free(views); free(TMD); return; } char *name=calloc((0x54/2),1); int z; for(z=0; z < 1; ++z) { tmd_content *TMDc = TMD_CONTENTS(((tmd*)(SIGNATURE_PAYLOAD(TMD)))); // OH GOD CREDIAR, WTF WAS THAT MESS!!! //printf("%d,",TMDc->index); s32 cfd = ES_OpenTitleContent( titleID, TMDc->index); free(views); if(CheckESRetval(cfd)!=0) { ; //printf("ES_OpenContent(%d) failed\n", cfd); //sleep(10); //exit(0); } else { u64 sz ATTRIBUTE_ALIGN(32) = 0x140; u8 *data = (u8*)memalign(32, sz); if( TMDc->size < sz ) sz = TMDc->size; if( data != NULL ) { if(ES_ReadContent(cfd, data, sz)<0) { free(data); return; } int y; int chan_name_offset=(language_setting*0x54); // Set to WiiMU's language for(y=0;y<(0x54/2);y++) name[y]=data[(0x9C+chan_name_offset)+(y*2)+1]; } if(CheckESRetval(ES_CloseContent(cfd))!=0) { ; //printf("ES_CloseContent failed\n"); //sleep(10); //exit(0); } free(data); } } int wiistring_size; reenter: wiistring_size=type_string_wiimote(name, 0x54/2); if(wiistring_size<=0) { printf("\n\nPlease enter a name!\n"); sleep(3); goto reenter; } name[wiistring_size+1]=0; /* Get Content */ char nameDirectory[80]; tmd_content *TMDc = TMD_CONTENTS(((tmd*)(SIGNATURE_PAYLOAD(TMD)))); sprintf(nameDirectory,"/title/%08x/%08x/content/%08x.app",TITLE_UPPER(titleID),TITLE_LOWER(titleID),TMDc->cid); s32 contentFd=ISFS_Open(nameDirectory,ISFS_OPEN_RW); CheckISFSRetval(contentFd); ClearScreen(); printf("\n\nOpened content!\n"); u8 *data=calloc(TMDc->size,1); int isUnaligned = ((int)data)%32 | TMDc->size%32; int alignedLen = (TMDc->size+31)&0xffffffe0; u8* alignedBuf; if(isUnaligned) alignedBuf = memalign(32, alignedLen); else alignedBuf = data; CheckISFSRetval(ISFS_Seek(contentFd,0,0)); CheckISFSRetval(ISFS_Read(contentFd, alignedBuf, alignedLen)); printf("Read content!\n"); int y; int chan_name_offset=(SYSCONF_GetArea()*0x54); // Edits the one for the Wii's system Menu char* nameOut=calloc(96,1); for(y=0;y<(0x54/2);y++) nameOut[(y*2)+1]=name[y]; printf("Wrote new name! %s\n", name); CheckISFSRetval(ISFS_Seek(contentFd,(0x9C+chan_name_offset),0)); printf("Seeked to location!\n"); if(nameOut==NULL) { printf("FAILED! (Name Out is NULL!)\n"); sleep(5); Finish(1); } if(((u32)nameOut%32)!=0) { isUnaligned = ((int)nameOut)%32 | 0x54%32; alignedLen = (0x54+31)&0xffffffe0; if(isUnaligned){ alignedBuf = memalign(32, alignedLen); memcpy(alignedBuf, nameOut, 0x54); } else alignedBuf = (u8*)nameOut; } CheckISFSRetval(ISFS_Write(contentFd, alignedBuf, 0x54)); printf("Wrote content name!\nReading new Header Chunk!\n"); CheckISFSRetval(ISFS_Seek(contentFd,0,0)); CheckISFSRetval(ISFS_Read(contentFd, alignedBuf, alignedLen)); printf("Read content!\n"); u8* header_chunk=calloc(0x640, 1); int i; for(i=0;i<0x630;i++) header_chunk[i]=alignedBuf[i]; for(i=0x630;i<0x640;i++) header_chunk[i]=0; u8* hash=calloc(0x10,1); md5(header_chunk, 0x640, hash); CheckISFSRetval(ISFS_Seek(contentFd,0x630,0)); printf("Seeked to location!\n"); if(hash==NULL) { printf("FAILED! (Hash is NULL!)\n"); sleep(5); Finish(1); } if(((u32)hash%32)!=0) { isUnaligned = ((int)hash)%32 | 0x10%32; alignedLen = (0x10+31)&0xffffffe0; if(isUnaligned){ alignedBuf = memalign(32, alignedLen); memcpy(alignedBuf, hash, 0x10); } else alignedBuf = hash;
s32 identify(u64 titleid, u32 *ios) { char filepath[ISFS_MAXPATH] ATTRIBUTE_ALIGN(32); u8 *tmdBuffer = NULL; u32 tmdSize; signed_blob *tikBuffer = NULL; u32 tikSize; u8 *certBuffer = NULL; u32 certSize; int ret; debug("Reading TMD..."); fflush(stdout); sprintf(filepath, "/title/%08x/%08x/content/title.tmd", TITLE_UPPER(titleid), TITLE_LOWER(titleid)); ret = read_full_file_from_nand(filepath, &tmdBuffer, &tmdSize); if (ret < 0) { debug("ERR: (identify) Reading TMD failed\n"); return ret; } debug("done\n"); *ios = (u32)(tmdBuffer[0x18b]); debug("Generating fake ticket..."); fflush(stdout); Identify_GenerateTik(&tikBuffer,&tikSize); debug("done\n"); debug("Reading certs..."); fflush(stdout); sprintf(filepath, "/sys/cert.sys"); ret = read_full_file_from_nand(filepath, &certBuffer, &certSize); if (ret < 0) { debug("Reading certs failed, trying to use embedded one\n"); certBuffer = allocate_memory(cert_sys_size); certSize = cert_sys_size; if (certBuffer != NULL) memcpy (certBuffer, cert_sys, cert_sys_size); else { free(tmdBuffer); free(tikBuffer); return ret; } } debug("done\n"); debug("ES_Identify..."); fflush(stdout); ret = ES_Identify((signed_blob*)certBuffer, certSize, (signed_blob*)tmdBuffer, tmdSize, tikBuffer, tikSize, NULL); if (ret < 0) { switch(ret) { case ES_EINVAL: debug("ERR: (identify) ES_Identify (ret = %d;) Data invalid!\n", ret); break; case ES_EALIGN: debug("ERR: (identify) ES_Identify (ret = %d;) Data not aligned!\n", ret); break; case ES_ENOTINIT: debug("ERR: (identify) ES_Identify (ret = %d;) ES not initialized!\n", ret); break; case ES_ENOMEM: debug("ERR: (identify) ES_Identify (ret = %d;) No memory!\n", ret); break; default: debug("ERR: (identify) ES_Identify (ret = %d)\n", ret); break; } free(tmdBuffer); free(tikBuffer); free(certBuffer); sleep (5); return ret; } debug("done\n"); free(tmdBuffer); free(tikBuffer); free(certBuffer); return 0; }
s8 CopyTicket ( ) { s32 fd = 0; char TIK_Path_dest[64]; char TIK_Path_org[64]; memset(TIK_Path_dest,0,64); memset(TIK_Path_org,0,64); sprintf(TIK_Path_dest, "/title/%08x/%08x/content/ticket",TITLE_UPPER(title_id),TITLE_LOWER(title_id)); sprintf(TIK_Path_org, "/ticket/%08x/%08x.tik",TITLE_UPPER(title_id),TITLE_LOWER(title_id)); gprintf("Checking for copy ticket...\n"); fd = ISFS_Open(TIK_Path_dest,ISFS_OPEN_READ); if (fd >= 0) { ISFS_Close(fd); printf("Skipping copy of system menu ticket...\n"); return 1; } switch(fd) { case ISFS_EINVAL: abort("Unable to read ticket.path is wrong/too long or ISFS isn't init yet?"); break; case ISFS_ENOMEM: abort("Unable to read ticket.(Out of memory)"); break; case -102: abort("Unauthorised to get ticket. is ios%d trucha signed?",IOS_GetVersion()); break; default: if(fd < 0) abort("Unable to read ticket. error %d. ",fd); case -106: printf("Priiloader system menu ticket not found.\n\tTrying to read original ticket...\n"); break; } fd = ISFS_Open(TIK_Path_org,ISFS_OPEN_READ); //"/ticket/00000001/00000002.tik" -> original path which should be there on every wii. if (fd < 0) { switch(fd) { case ISFS_EINVAL: abort("Unable to read ticket.path is wrong/too long or ISFS isn't init yet?"); break; case ISFS_ENOMEM: abort("Unable to read ticket.(Out of memory)"); break; case -106: abort("Ticket not found"); break; case -102: abort("Unauthorised to get ticket. is ios%d trucha signed?",IOS_GetVersion()); break; default: abort("Unable to read ticket. error %d. ",fd); break; } } ISFS_Close(fd); printf("Copying system menu ticket..."); Nand_Permissions TikPerm; memset(&TikPerm,0,sizeof(Nand_Permissions)); TikPerm.otherperm = 3; TikPerm.groupperm = 3; TikPerm.ownerperm = 3; if (nand_copy(TIK_Path_org,TIK_Path_dest,TikPerm) < 0) { abort("Unable to copy the system menu ticket"); } printf("Done!\n"); return 1; }
s32 Download_IOS(IOS **ios, u32 iosnr, u32 revision) { s32 ret; ret = Init_IOS(ios); if (ret < 0) { printf("Out of memory\n"); goto err; } tmd *tmd_data = NULL; u32 cnt; //static bool network_initialized = false; char buf[32]; if (!network_initialized) { printf("Initializing network..."); while (1) { ret = net_init (); if (ret < 0) { //if (ret != -EAGAIN) if (ret != -11) { printf ("net_init failed: %d\n", ret); goto err; } } if (!ret) break; usleep(100000); printf("."); } printf("done\n"); network_initialized = true; } printf("Loading certs...\n"); ret = GetCerts(&((*ios)->certs), &((*ios)->certs_size)); if (ret < 0) { printf ("Loading certs from nand failed, ret = %d\n", ret); goto err; } if ((*ios)->certs == NULL || (*ios)->certs_size == 0) { printf("certs error\n"); ret = -1; goto err; } if (!IS_VALID_SIGNATURE((*ios)->certs)) { printf("Error: Bad certs signature!\n"); ret = -1; goto err; } printf("Loading TMD...\n"); sprintf(buf, "tmd.%u", revision); u8 *tmd_buffer = NULL; ret = get_nus_object(1, iosnr, buf, &tmd_buffer, &((*ios)->tmd_size)); if (ret < 0) { printf("Loading tmd failed, ret = %u\n", ret); goto err; } if (tmd_buffer == NULL || (*ios)->tmd_size == 0) { printf("TMD error\n"); ret = -1; goto err; } (*ios)->tmd_size = SIGNED_TMD_SIZE((signed_blob *)tmd_buffer); (*ios)->tmd = MEM2_memalign(32, (*ios)->tmd_size); if ((*ios)->tmd == NULL) { printf("Out of memory\n"); ret = -1; goto err; } memcpy((*ios)->tmd, tmd_buffer, (*ios)->tmd_size); free(tmd_buffer); if (!IS_VALID_SIGNATURE((*ios)->tmd)) { printf("Error: Bad TMD signature!\n"); ret = -1; goto err; } printf("Loading ticket...\n"); u8 *ticket_buffer = NULL; ret = get_nus_object(1, iosnr, "cetk", &ticket_buffer, &((*ios)->ticket_size)); if (ret < 0) { printf("Loading ticket failed, ret = %u\n", ret); goto err; } if (ticket_buffer == NULL || (*ios)->ticket_size == 0) { printf("ticket error\n"); ret = -1; goto err; } (*ios)->ticket_size = SIGNED_TIK_SIZE((signed_blob *)ticket_buffer); (*ios)->ticket = MEM2_memalign(32, (*ios)->ticket_size); if ((*ios)->ticket == NULL) { printf("Out of memory\n"); ret = -1; goto err; } memcpy((*ios)->ticket, ticket_buffer, (*ios)->ticket_size); free(ticket_buffer); if(!IS_VALID_SIGNATURE((*ios)->ticket)) { printf("Error: Bad ticket signature!\n"); ret = -1; goto err; } /* Get TMD info */ tmd_data = (tmd *)SIGNATURE_PAYLOAD((*ios)->tmd); printf("Checking titleid and revision...\n"); if (TITLE_UPPER(tmd_data->title_id) != 1 || TITLE_LOWER(tmd_data->title_id) != iosnr) { printf("IOS has titleid: %08x%08x but expected was: %08x%08x\n", TITLE_UPPER(tmd_data->title_id), TITLE_LOWER(tmd_data->title_id), 1, iosnr); ret = -1; goto err; } if (tmd_data->title_version != revision) { printf("IOS has revision: %u but expected was: %u\n", tmd_data->title_version, revision); ret = -1; goto err; } ret = set_content_count(*ios, tmd_data->num_contents); if (ret < 0) { printf("Out of memory\n"); goto err; } printf("Loading contents"); for (cnt = 0; cnt < tmd_data->num_contents; cnt++) { printf("."); tmd_content *content = &tmd_data->contents[cnt]; /* Encrypted content size */ (*ios)->buffer_size[cnt] = round_up((u32)content->size, 64); sprintf(buf, "%08x", content->cid); ret = get_nus_object(1, iosnr, buf, &((*ios)->encrypted_buffer[cnt]), &((*ios)->buffer_size[cnt])); if ((*ios)->buffer_size[cnt] % 16) { printf("Content %u size is not a multiple of 16\n", cnt); ret = -1; goto err; } if ((*ios)->buffer_size[cnt] < (u32)content->size) { printf("Content %u size is too small\n", cnt); ret = -1; goto err; } (*ios)->decrypted_buffer[cnt] = MEM2_memalign(32, (*ios)->buffer_size[cnt]); if (!(*ios)->decrypted_buffer[cnt]) { printf("Out of memory\n"); ret = -1; goto err; } } printf("done\n"); printf("Reading file into memory complete.\n"); printf("Decrypting IOS...\n"); decrypt_IOS(*ios); tmd_content *p_cr = TMD_CONTENTS(tmd_data); sha1 hash; int i; printf("Checking hashes...\n"); for (i=0;i < (*ios)->content_count;i++) { SHA1((*ios)->decrypted_buffer[i], (u32)p_cr[i].size, hash); if (memcmp(p_cr[i].hash, hash, sizeof hash) != 0) { printf("Wrong hash for content #%u\n", i); ret = -1; goto err; } } goto out; err: free_IOS(ios); out: return ret; }