//--------------------------------------------------------------------------------- s32 install(const signed_blob *s_tmd, const signed_blob *s_certs, u32 certs_len){ //--------------------------------------------------------------------------------- u32 ret, i; tmd *p_tmd = SIGNATURE_PAYLOAD(s_tmd); ret = ES_AddTitleStart(s_tmd, SIGNED_TMD_SIZE(s_tmd), s_certs, certs_len, NULL, 0); if(ret < 0) { ES_AddTitleCancel(); return ret; } for(i=0; i<p_tmd->num_contents; i++) { currentfile = i+1; filecount = p_tmd->num_contents; installios_thread_state = 1; ret = install_nus_object((tmd *)SIGNATURE_PAYLOAD(s_tmd), i); if (ret) return ret; } ret = ES_AddTitleFinish(); if(ret < 0) { ES_AddTitleCancel(); return ret; } return 0; }
s32 Title_GetSize(u64 tid, u32 *outbuf) { signed_blob *p_tmd = NULL; tmd *tmd_data = NULL; u32 cnt, len, size = 0; s32 ret; /* Get title TMD */ ret = Title_GetTMD(tid, &p_tmd, &len); if (ret < 0) return ret; /* Retrieve TMD info */ tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); /* Calculate title size */ for (cnt = 0; cnt < tmd_data->num_contents; cnt++) { tmd_content *content = &tmd_data->contents[cnt]; /* Add content size */ size += content->size; } /* Set values */ *outbuf = size; /* Free memory */ free(p_tmd); return 0; }
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 __Wad_GetTitleID(FILE *fp, wadHeader *header, u64 *tid) { //signed_blob *p_tik = NULL; void *p_tik = NULL; tik *tik_data = NULL; u32 offset = 0; s32 ret; /* Ticket offset */ offset += round_up(header->header_len, 64); offset += round_up(header->certs_len, 64); offset += round_up(header->crl_len, 64); /* Read ticket */ ret = __Wad_ReadAlloc(fp, &p_tik, offset, header->tik_len); if (ret < 0) goto out; /* Ticket data */ tik_data = (tik *)SIGNATURE_PAYLOAD((signed_blob *)p_tik); /* Copy title ID */ *tid = tik_data->titleid; out: /* Free memory */ if (p_tik) free(p_tik); return ret; }
void change_tmd_title_id(signed_blob *s_tmd, u32 titleid1, u32 titleid2) { tmd *p_tmd; u64 title_id = titleid1; title_id <<= 32; title_id |= titleid2; p_tmd = (tmd*)SIGNATURE_PAYLOAD(s_tmd); p_tmd->title_id = title_id; }
u8 IOS_GetType(u8 slot) { /* No more checks needed */ if(neek2o() || Sys_DolphinMode()) return IOS_TYPE_NEEK2O; /* Lets do this */ u32 TMD_Length; signed_blob *TMD_Buffer = GetTMD(slot, &TMD_Length); if(TMD_Buffer == NULL) return IOS_TYPE_STUB; tmd *iosTMD = (tmd*)SIGNATURE_PAYLOAD(TMD_Buffer); if(Title_GetSize_FromTMD(iosTMD) < 0x100000 || iosTMD->title_version == 65280) { MEM2_free(TMD_Buffer); return IOS_TYPE_STUB; } u32 title_rev = iosTMD->title_version; MEM2_free(TMD_Buffer); u8 base = 0; switch(slot) { case 222: case 223: case 224: case 225: if(title_rev == 1) return IOS_TYPE_KWIIRK; else return IOS_TYPE_HERMES; case 245: case 246: case 247: case 248: case 249: case 250: case 251: if(IOS_D2X(slot, &base)) return IOS_TYPE_D2X; else return IOS_TYPE_WANIN; default: if(IOS_D2X(slot, &base)) return IOS_TYPE_D2X; else return IOS_TYPE_NORMAL_IOS; } }
bool isIOSstub(u8 ios_number) { static signed_blob ios_tmd_buf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(32); u32 tmd_size; tmd *ios_tmd; if (ios_number == 249) { ES_GetStoredTMDSize(0x0000000100000000ULL | ios_number, &tmd_size); ES_GetStoredTMD(0x0000000100000000ULL | ios_number, ios_tmd_buf, tmd_size); ios_tmd = SIGNATURE_PAYLOAD(ios_tmd_buf); if (ios_tmd->title_version >= 65280) return TRUE; } return FALSE; }
s32 checkTitle(u64 title_id) { signed_blob *TMD = NULL; tmd *t = NULL; u32 TMD_size = 0; s32 ret = 0; ret = GetTMD(title_id, &TMD, &TMD_size); if (ret == 0) { t = (tmd*)SIGNATURE_PAYLOAD(TMD); return t->title_version; } else { ret = -2; } free(TMD); return ret; }
void get_title_key(signed_blob *s_tik, u8 *key) { static u8 iv[16] ATTRIBUTE_ALIGN(0x20); static u8 keyin[16] ATTRIBUTE_ALIGN(0x20); static u8 keyout[16] ATTRIBUTE_ALIGN(0x20); const tik *p_tik; p_tik = (tik*)SIGNATURE_PAYLOAD(s_tik); u8 *enc_key = (u8 *)&p_tik->cipher_title_key; memcpy(keyin, enc_key, sizeof keyin); memset(keyout, 0, sizeof keyout); memset(iv, 0, sizeof iv); memcpy(iv, &p_tik->titleid, sizeof p_tik->titleid); aes_set_key(commonkey); aes_decrypt(iv, keyin, keyout, sizeof keyin); memcpy(key, keyout, sizeof keyout); }
tmd* NandTitle::GetTMD(u64 tid) { signed_blob *s_tmd = (signed_blob *) tmd_buf; u32 tmd_size; if (ES_GetStoredTMDSize(tid, &tmd_size) < 0) { return NULL; } s32 ret = ES_GetStoredTMD(tid, s_tmd, tmd_size); if (ret < 0) { return NULL; } tmd *t = (tmd*) SIGNATURE_PAYLOAD(s_tmd); return t; }
//--------------------------------------------------------------------------------- int get_title_key(signed_blob *s_tik, u8 *key){ //--------------------------------------------------------------------------------- static u8 iv[16] ATTRIBUTE_ALIGN(0x20); static u8 keyin[16] ATTRIBUTE_ALIGN(0x20); static u8 keyout[16] ATTRIBUTE_ALIGN(0x20); int retval; const tik *p_tik; p_tik = (tik*)SIGNATURE_PAYLOAD(s_tik); u8 *enc_key = (u8 *)&p_tik->cipher_title_key; memcpy(keyin, enc_key, sizeof keyin); memset(keyout, 0, sizeof keyout); memset(iv, 0, sizeof iv); memcpy(iv, &p_tik->titleid, sizeof p_tik->titleid); retval = ES_Decrypt(ES_KEY_COMMON, iv, keyin, sizeof keyin, keyout); if (retval){ // printf("ES_Decrypt returned %d\n", retval); } memcpy(key, keyout, sizeof keyout); return retval; }
void change_ticket_title_id(signed_blob *s_tik, u32 titleid1, u32 titleid2) { static u8 iv[16] ATTRIBUTE_ALIGN(0x20); static u8 keyin[16] ATTRIBUTE_ALIGN(0x20); static u8 keyout[16] ATTRIBUTE_ALIGN(0x20); tik *p_tik; p_tik = (tik*)SIGNATURE_PAYLOAD(s_tik); u8 *enc_key = (u8 *)&p_tik->cipher_title_key; memcpy(keyin, enc_key, sizeof keyin); memset(keyout, 0, sizeof keyout); memset(iv, 0, sizeof iv); memcpy(iv, &p_tik->titleid, sizeof p_tik->titleid); aes_set_key(commonkey); aes_decrypt(iv, keyin, keyout, sizeof keyin); p_tik->titleid = (u64)titleid1 << 32 | (u64)titleid2; memset(iv, 0, sizeof iv); memcpy(iv, &p_tik->titleid, sizeof p_tik->titleid); aes_encrypt(iv, keyout, keyin, sizeof keyout); memcpy(enc_key, keyin, sizeof keyin); }
s32 Title_GetVersion(u64 tid, u16 *outbuf) { signed_blob *p_tmd = NULL; tmd *tmd_data = NULL; u32 len; s32 ret; /* Get title TMD */ ret = Title_GetTMD(tid, &p_tmd, &len); if (ret < 0) return ret; /* Retrieve TMD info */ tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); /* Set values */ *outbuf = tmd_data->title_version; /* Free memory */ free(p_tmd); return 0; }
s32 Wad_Install(FILE *fp) { //////start the gui shit GuiWindow promptWindow(472,320); promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); promptWindow.SetPosition(0, -10); GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume); // because destroy GuiSound must wait while sound playing is finished, we use a global sound if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); // GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume); char imgPath[100]; snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); GuiImageData btnOutline(imgPath, button_dialogue_box_png); snprintf(imgPath, sizeof(imgPath), "%sdialogue_box.png", CFG.theme_path); GuiImageData dialogBox(imgPath, dialogue_box_png); GuiTrigger trigA; trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); GuiImage dialogBoxImg(&dialogBox); if (Settings.wsprompt == yes){ dialogBoxImg.SetWidescreen(CFG.widescreen);} GuiText btn1Txt(tr("OK"), 22, THEME.prompttext); GuiImage btn1Img(&btnOutline); if (Settings.wsprompt == yes){ btn1Txt.SetWidescreen(CFG.widescreen); btn1Img.SetWidescreen(CFG.widescreen);} GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -35, &trigA, &btnSoundOver, btnClick2,1); btn1.SetLabel(&btn1Txt); btn1.SetState(STATE_SELECTED); snprintf(imgPath, sizeof(imgPath), "%sprogressbar_outline.png", CFG.theme_path); GuiImageData progressbarOutline(imgPath, progressbar_outline_png); GuiImage progressbarOutlineImg(&progressbarOutline); if (Settings.wsprompt == yes){ progressbarOutlineImg.SetWidescreen(CFG.widescreen);} progressbarOutlineImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); progressbarOutlineImg.SetPosition(25, 50); snprintf(imgPath, sizeof(imgPath), "%sprogressbar_empty.png", CFG.theme_path); GuiImageData progressbarEmpty(imgPath, progressbar_empty_png); GuiImage progressbarEmptyImg(&progressbarEmpty); progressbarEmptyImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); progressbarEmptyImg.SetPosition(25, 50); progressbarEmptyImg.SetTile(100); snprintf(imgPath, sizeof(imgPath), "%sprogressbar.png", CFG.theme_path); GuiImageData progressbar(imgPath, progressbar_png); GuiImage progressbarImg(&progressbar); progressbarImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); progressbarImg.SetPosition(25, 50); char title[50]; sprintf(title, "%s", tr("Installing wad")); GuiText titleTxt(title, 26, THEME.prompttext); titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); titleTxt.SetPosition(0,40); char msg[50]; sprintf(msg, " "); // sprintf(msg, "%s", tr("Initializing Network")); GuiText msg1Txt(NULL, 20, THEME.prompttext); msg1Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg1Txt.SetPosition(50,75); // char msg2[50] = " "; GuiText msg2Txt(NULL, 20, THEME.prompttext); msg2Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg2Txt.SetPosition(50, 98); GuiText msg3Txt(NULL, 20, THEME.prompttext); msg3Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg3Txt.SetPosition(50, 121); GuiText msg4Txt(NULL, 20, THEME.prompttext); msg4Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg4Txt.SetPosition(50, 144); GuiText msg5Txt(NULL, 20, THEME.prompttext); msg5Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); msg5Txt.SetPosition(50, 167); GuiText prTxt(NULL, 26, THEME.prompttext); prTxt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); prTxt.SetPosition(0, 50); if ((Settings.wsprompt == yes) && (CFG.widescreen)){/////////////adjust for widescreen progressbarOutlineImg.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE); progressbarOutlineImg.SetPosition(0, 50); progressbarEmptyImg.SetPosition(80,50); progressbarEmptyImg.SetTile(78); progressbarImg.SetPosition(80, 50); msg1Txt.SetPosition(90,75); msg2Txt.SetPosition(90, 98); msg3Txt.SetPosition(90, 121); msg4Txt.SetPosition(90, 144); msg5Txt.SetPosition(90, 167); } promptWindow.Append(&dialogBoxImg); promptWindow.Append(&titleTxt); promptWindow.Append(&msg5Txt); promptWindow.Append(&msg4Txt); promptWindow.Append(&msg3Txt); promptWindow.Append(&msg1Txt); promptWindow.Append(&msg2Txt); //promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50); HaltGui(); mainWindow->SetState(STATE_DISABLED); mainWindow->Append(&promptWindow); mainWindow->ChangeFocus(&promptWindow); //sleep(1); ///start the wad shit bool fail = false; wadHeader *header = NULL; void *pvoid; signed_blob *p_certs = NULL, *p_crl = NULL, *p_tik = NULL, *p_tmd = NULL; tmd *tmd_data = NULL; u32 cnt, offset = 0; s32 ret = 666; ResumeGui(); msg1Txt.SetText(tr(">> Reading WAD data...")); HaltGui(); #define SetPointer(a, p) a=(typeof(a))p // WAD header //ret = __Wad_ReadAlloc(fp, (void *)header, offset, sizeof(wadHeader)); ret = __Wad_ReadAlloc(fp, &pvoid, offset, sizeof(wadHeader)); if (ret < 0) goto err; SetPointer(header, pvoid); offset += round_up(header->header_len, 64); // WAD certificates //ret = __Wad_ReadAlloc(fp, (void *)&p_certs, offset, header->certs_len); ret = __Wad_ReadAlloc(fp, &pvoid, offset, header->certs_len); if (ret < 0) goto err; SetPointer(p_certs, pvoid); offset += round_up(header->certs_len, 64); // WAD crl if (header->crl_len) { //ret = __Wad_ReadAlloc(fp, (void *)&p_crl, offset, header->crl_len); ret = __Wad_ReadAlloc(fp, &pvoid, offset, header->crl_len); if (ret < 0) goto err; SetPointer(p_crl, pvoid); offset += round_up(header->crl_len, 64); } // WAD ticket //ret = __Wad_ReadAlloc(fp, (void *)&p_tik, offset, header->tik_len); ret = __Wad_ReadAlloc(fp, &pvoid, offset, header->tik_len); if (ret < 0) goto err; SetPointer(p_tik, pvoid); offset += round_up(header->tik_len, 64); // WAD TMD //ret = __Wad_ReadAlloc(fp, (void *)&p_tmd, offset, header->tmd_len); ret = __Wad_ReadAlloc(fp, &pvoid, offset, header->tmd_len); if (ret < 0) goto err; SetPointer(p_tmd, pvoid); offset += round_up(header->tmd_len, 64); ResumeGui(); msg1Txt.SetText(tr("Reading WAD data... Ok!")); msg2Txt.SetText(tr(">> Installing ticket...")); HaltGui(); // Install ticket ret = ES_AddTicket(p_tik, header->tik_len, p_certs, header->certs_len, p_crl, header->crl_len); if (ret < 0) goto err; ResumeGui(); msg2Txt.SetText(tr("Installing ticket... Ok!")); msg3Txt.SetText(tr(">> Installing title...")); //WindowPrompt(">> Installing title...",0,0,0,0,0,200); HaltGui(); // Install title ret = ES_AddTitleStart(p_tmd, header->tmd_len, p_certs, header->certs_len, p_crl, header->crl_len); if (ret < 0) goto err; // Get TMD info tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd); // Install contents //ResumeGui(); //HaltGui(); promptWindow.Append(&progressbarEmptyImg); promptWindow.Append(&progressbarImg); promptWindow.Append(&progressbarOutlineImg); promptWindow.Append(&prTxt); ResumeGui(); msg3Txt.SetText(tr("Installing title... Ok!")); for (cnt = 0; cnt < tmd_data->num_contents; cnt++) { tmd_content *content = &tmd_data->contents[cnt]; u32 idx = 0, len; s32 cfd; ResumeGui(); //printf("\r\t\t>> Installing content #%02d...", content->cid); // Encrypted content size len = round_up(content->size, 64); // Install content cfd = ES_AddContentStart(tmd_data->title_id, content->cid); if (cfd < 0) { ret = cfd; goto err; } snprintf(imgPath, sizeof(imgPath), "%s%d...",tr(">> Installing content #"),content->cid); msg4Txt.SetText(imgPath); // Install content data while (idx < len) { //VIDEO_WaitVSync (); u32 size; // Data length size = (len - idx); if (size > BLOCK_SIZE) size = BLOCK_SIZE; // Read data ret = __Wad_ReadFile(fp, &wadBuffer, offset, size); if (ret < 0) goto err; // Install data ret = ES_AddContentData(cfd, wadBuffer, size); if (ret < 0) goto err; // Increase variables idx += size; offset += size; //snprintf(imgPath, sizeof(imgPath), "%s%d (%d)...",tr(">> Installing content #"),content->cid,idx); //msg4Txt.SetText(imgPath); prTxt.SetTextf("%i%%", 100*(cnt*len+idx)/(tmd_data->num_contents*len)); if ((Settings.wsprompt == yes) && (CFG.widescreen)) { progressbarImg.SetTile(78*(cnt*len+idx)/(tmd_data->num_contents*len)); } else { progressbarImg.SetTile(100*(cnt*len+idx)/(tmd_data->num_contents*len)); } } // Finish content installation ret = ES_AddContentFinish(cfd); if (ret < 0) goto err; } msg4Txt.SetText(tr("Installing content... Ok!")); msg5Txt.SetText(tr(">> Finishing installation...")); // Finish title install ret = ES_AddTitleFinish(); if (ret >= 0) { // printf(" OK!\n"); goto out; } err: //char titties[100]; ResumeGui(); prTxt.SetTextf("%s%d", tr("Error..."),ret); promptWindow.Append(&prTxt); fail = true; //snprintf(titties, sizeof(titties), "%d", ret); //printf(" ERROR! (ret = %d)\n", ret); //WindowPrompt("ERROR!",titties,"Back",0,0); // Cancel install ES_AddTitleCancel(); goto exit; //return ret; out: // Free memory if (header) free(header); if (p_certs) free(p_certs); if (p_crl) free(p_crl); if (p_tik) free(p_tik); if (p_tmd) free(p_tmd); goto exit; exit: if (!fail)msg5Txt.SetText(tr("Finishing installation... Ok!")); promptWindow.Append(&btn1); while(btn1.GetState() != STATE_CLICKED){ } HaltGui(); mainWindow->Remove(&promptWindow); mainWindow->SetState(STATE_DEFAULT); ResumeGui(); return ret; }
//--------------------------------------------------------------------------------- void forge_tik(signed_blob *s_tik){ //--------------------------------------------------------------------------------- zero_sig(s_tik); brute_tik(SIGNATURE_PAYLOAD(s_tik)); }
//--------------------------------------------------------------------------------- void forge_tmd(signed_blob *s_tmd){ //--------------------------------------------------------------------------------- zero_sig(s_tmd); brute_tmd(SIGNATURE_PAYLOAD(s_tmd)); }
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; }
s32 Install_patched_IOS(u32 iosnr, u32 iosrevision, bool es_trucha_patch, bool es_identify_patch, bool nand_patch, bool version_patch, bool Kill_AntiSysTitleInstall_patch, u32 location, u32 newrevision, bool free) { int ret; /* if (iosnr == location && iosrevision == newrevision && !es_trucha_patch && !es_identify_patch && !nand_patch && !Kill_AntiSysTitleInstall_patch) { ret = install_unpatched_IOS(iosnr, iosrevision, free); return ret; } */ IOS *ios; int index; bool tmd_dirty = false; bool tik_dirty = false; printf("Getting IOS%u revision %u...\n", iosnr, iosrevision); ret = get_IOS(&ios, iosnr, iosrevision); if (ret < 0) { printf("Error reading IOS into memory\n"); return -1; } tmd *p_tmd = (tmd*)SIGNATURE_PAYLOAD(ios->tmd); tmd_content *p_cr = TMD_CONTENTS(p_tmd); index = kernel_index(ios); if (index < 0) { printf("Could not identify kernel\n"); free_IOS(&ios); return -1; } printf("Kernel found at index %d...Patching.\n", index); // before loading this IOS some valid ARM code needs to be written to the beginning of mem2 // or it will crash every time it tries to check kernel debug flags (syscall 0x4b) patch_syscall(ios->decrypted_buffer[index], 0x4b, 0x10000000); // Force the patched module to be not shared tmd_content *content = &p_tmd->contents[index]; content->type = 1; // Update the content hash inside the tmd sha1 hash; SHA1(ios->decrypted_buffer[index], (u32)p_cr[index].size, hash); memcpy(p_cr[index].hash, hash, sizeof hash); tmd_dirty = true; if (es_trucha_patch || es_identify_patch || nand_patch || version_patch || Kill_AntiSysTitleInstall_patch) { index = module_index(ios, "ES:"); if (index < 0) { printf("Could not identify ES module\n"); free_IOS(&ios); return -1; } int trucha = 0; int identify = 0; int nand = 0; int version = 0; int systitle = 0; if (es_trucha_patch) { printf("Patching trucha bug into ES module(#%u)...", index); trucha = patch_hash_check(ios->decrypted_buffer[index], ios->buffer_size[index]); printf("patched %u hash check(s)\n", trucha); } if (es_identify_patch) { printf("Patching ES_Identify in ES module(#%u)...", index); identify = patch_identify_check(ios->decrypted_buffer[index], ios->buffer_size[index]); printf("patch applied %u time(s)\n", identify); } if (nand_patch) { printf("Patching nand permissions in ES module(#%u)...", index); nand = patch_patch_fsperms(ios->decrypted_buffer[index], ios->buffer_size[index]); printf("patch applied %u time(s)\n", nand); } if (version_patch) { printf("Patching version check in ES module(#%u)...", index); version = patch_version_check(ios->decrypted_buffer[index], ios->buffer_size[index]); printf("patch applied %u time(s)\n", version); } if (Kill_AntiSysTitleInstall_patch) { printf("Patching out Systitle Anti-Install Routine in ES module(#%u)...", index); systitle = patch_Kill_AntiSysTitleInstall(ios->decrypted_buffer[index], ios->buffer_size[index]); printf("patch applied %u time(s)\n", systitle); } if (trucha > 0 || identify > 0 || nand > 0 || version > 0 || systitle > 0) { // Force the patched module to be not shared tmd_content *content = &p_tmd->contents[index]; content->type = 1; // Update the content hash inside the tmd sha1 hash; SHA1(ios->decrypted_buffer[index], (u32)p_cr[index].size, hash); memcpy(p_cr[index].hash, hash, sizeof hash); tmd_dirty = true; } } if (iosnr != location) { change_ticket_title_id(ios->ticket, 1, location); change_tmd_title_id(ios->tmd, 1, location); tmd_dirty = true; tik_dirty = true; } if (iosrevision != newrevision) { p_tmd->title_version = newrevision; tmd_dirty = true; } if (tmd_dirty) { printf("Trucha signing the tmd...\n"); forge_tmd(ios->tmd); } if (tik_dirty) { printf("Trucha signing the ticket..\n"); forge_tik(ios->ticket); } printf("Encrypting IOS...\n"); encrypt_IOS(ios); printf("Preparations complete\n\n"); printf("Installing...\n"); /* ret = install_IOS(ios, false); if (ret < 0) { free_IOS(&ios); if (ret == -1017 || ret == -2011) { printf("You need to use an IOS with trucha bug.\n"); printf("That's what the IOS15 downgrade is good for...\n"); } else if (ret == -1035) { printf("Has your installed IOS%u a higher revison than %u?\n", iosnr, iosrevision); } return -1; } */ printf("done\n"); if (free) free_IOS(&ios); 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;
s8 PatchTMD( u8 delete_mode ) { Nand_Permissions Perm; memset(&Perm,0,sizeof(Nand_Permissions)); u8 SaveTmd = 0; SHA1 sha; // SHA-1 class sha.Reset(); u32 FileHash[5]; u8 *TMD_chk = NULL; s32 fd = 0; s32 r = 0; #ifdef _DEBUG gprintf("Path : %s\n",TMD_Path); #endif r = ISFS_GetAttr(TMD_Path, &Perm.owner, &Perm.group, &Perm.attributes, &Perm.ownerperm, &Perm.groupperm, &Perm.otherperm); if(r < 0 ) { //attribute getting failed. returning to default printf("\x1b[%u;%dm", 33, 1); printf("\nWARNING : failed to get file's permissions. using defaults\n"); printf("\x1b[%u;%dm", 37, 1); gprintf("permission failure on desination! error %d\n",r); gprintf("writing with max permissions\n"); Perm.ownerperm = 3; Perm.groupperm = 3; Perm.otherperm = 0; } else { gprintf("r %d owner %d group %d attributes %X perm:%X-%X-%X\n", r, Perm.owner, Perm.group, Perm.attributes, Perm.ownerperm, Perm.groupperm, Perm.otherperm); } if(delete_mode == 0) { gprintf("patching TMD...\n"); printf("Patching TMD..."); } else { //return 1; gprintf("restoring TMD...\n"); printf("Restoring System Menu TMD...\n"); } fd = ISFS_Open(TMD_Path2,ISFS_OPEN_READ); if(fd < 0) { if(delete_mode) { printf("TMD backup not found. leaving TMD alone...\n"); return 1; } else { //got to make tmd copy :) gprintf("Making tmd backup...\n"); r = nand_copy(TMD_Path2,tmd_buf,tmd_size,Perm); if ( r < 0) { gprintf("Failure making TMD backup.error %d\n",r); printf("TMD backup/Patching Failure : error %d",r); goto _return; } } fd = 0; } ISFS_Close(fd); gprintf("TMD backup found\n"); //not so sure why we'd want to delete the tmd modification but ok... if(delete_mode) { if ( nand_copy(TMD_Path2,TMD_Path,Perm) < 0) { if(r == -80) { //checksum issues printf("\x1b[%u;%dm", 33, 1); printf("\nWARNING!!\nInstaller could not calculate the Checksum when restoring the TMD back!\n"); printf("the TMD however was copied...\n"); printf("Do you want to Continue ?\n"); printf("A = Yes B = No\n "); printf("\x1b[%u;%dm", 37, 1); if(!UserYesNoStop()) { nand_copy(TMD_Path,TMD_Path2,Perm); abort("TMD restoring failure."); } } else { printf("\x1b[%u;%dm", 33, 1); printf("UNABLE TO RESTORE THE SYSTEM MENU TMD!!!\n\nTHIS COULD BRICK THE WII SO PLEASE REINSTALL SYSTEM MENU\nWHEN RETURNING TO THE HOMEBREW CHANNEL!!!\n\n"); printf("\x1b[%u;%dm", 37, 1); printf("press A to return to the homebrew channel\n"); nand_copy(TMD_Path,TMD_Path2,Perm); UserYesNoStop(); exit(0); } } else ISFS_Delete(TMD_Path2); return 1; } else { //check if version is the same STACK_ALIGN(fstats,TMDb_status,sizeof(fstats),32); static u8 tmdb_buf[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(32); static signed_blob *mbTMD; static tmd* pbTMD; fd = ISFS_Open(TMD_Path2,ISFS_OPEN_READ); if (fd < 0) { gprintf("TMD bCheck : failed to open source : %s\n",TMD_Path2); goto patch_tmd; } r = ISFS_GetFileStats(fd,TMDb_status); if (r < 0) { gprintf("TMD bCheck : Failed to get information about %s!\n",TMD_Path2); ISFS_Close(fd); goto patch_tmd; } memset(tmdb_buf,0,MAX_SIGNED_TMD_SIZE); r = ISFS_Read(fd,tmdb_buf,TMDb_status->file_length); if (r < 0) { gprintf("TMD bCheck : Failed to Read Data from %s!\n",TMD_Path2); ISFS_Close(fd); goto patch_tmd; } ISFS_Close(fd); mbTMD = (signed_blob *)tmdb_buf; pbTMD = (tmd*)SIGNATURE_PAYLOAD(mbTMD); if (pbTMD->title_version != rTMD->title_version) { gprintf("TMD bCheck : backup TMD version mismatch: %d & %d\n",rTMD->title_version,pbTMD->title_version); //got to make tmd copy :) r = nand_copy(TMD_Path2,tmd_buf,tmd_size,Perm); if ( r < 0) { gprintf("TMD bCheck : Failure making TMD backup.error %d\n",r); printf("TMD backup/Patching Failure : error %d",r); goto _return; } } else gprintf("TMD bCheck : backup TMD is correct\n"); r = 0; } patch_tmd: gprintf("detected access rights : 0x%08X\n",rTMD->access_rights); if(rTMD->access_rights == 0x03) { gprintf("no AHBPROT modification needed\n"); } else { rTMD->access_rights = 0x03; DCFlushRange(rTMD,sizeof(tmd)); if(rTMD->access_rights != 0x03) { gprintf("rights change failure.\n"); goto _return; } SaveTmd++; } gprintf("checking Boot app SHA1 hash...\n"); gprintf("bootapp ( %d ) SHA1 hash = %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",rTMD->boot_index ,rTMD->contents[rTMD->boot_index].hash[0],rTMD->contents[rTMD->boot_index].hash[1],rTMD->contents[rTMD->boot_index].hash[2],rTMD->contents[rTMD->boot_index].hash[3] ,rTMD->contents[rTMD->boot_index].hash[4],rTMD->contents[rTMD->boot_index].hash[5],rTMD->contents[rTMD->boot_index].hash[6],rTMD->contents[rTMD->boot_index].hash[7] ,rTMD->contents[rTMD->boot_index].hash[8],rTMD->contents[rTMD->boot_index].hash[9],rTMD->contents[rTMD->boot_index].hash[10],rTMD->contents[rTMD->boot_index].hash[11] ,rTMD->contents[rTMD->boot_index].hash[12],rTMD->contents[rTMD->boot_index].hash[13],rTMD->contents[rTMD->boot_index].hash[14],rTMD->contents[rTMD->boot_index].hash[15] ,rTMD->contents[rTMD->boot_index].hash[16],rTMD->contents[rTMD->boot_index].hash[17],rTMD->contents[rTMD->boot_index].hash[18],rTMD->contents[rTMD->boot_index].hash[19]); gprintf("generated priiloader SHA1 : "); sha.Reset(); sha.Input(priiloader_app,priiloader_app_size); if (!sha.Result(FileHash)) { gprintf("could not compute Hash of Priiloader!\n"); r = -1; goto _return; } if (!memcmp(rTMD->contents[rTMD->boot_index].hash, FileHash, sizeof(FileHash) ) ) { gprintf("no SHA hash change needed\n"); } else { memcpy(rTMD->contents[rTMD->boot_index].hash,FileHash,sizeof(FileHash)); gprintf("%08x %08x %08x %08x %08x\n",FileHash[0],FileHash[1],FileHash[2],FileHash[3],FileHash[4]); DCFlushRange(rTMD,sizeof(tmd)); SaveTmd++; } if(SaveTmd > 0) { gprintf("saving TMD\n"); r = nand_copy(TMD_Path,tmd_buf,tmd_size,Perm); if(r < 0 ) { gprintf("nand_copy failure. error %d\n",r); if(r == -80) goto _checkreturn; else goto _return; } } else { gprintf("no TMD mod's needed\n"); printf("no TMD modifications needed\n"); goto _return; } printf("Done\n"); _return: if (fd < r) { r = fd; } if(fd) { ISFS_Close(fd); } if (r < 0) { printf("\x1b[%u;%dm", 33, 1); printf("\nWARNING!!\nInstaller couldn't Patch the system menu TMD.\n"); printf("Priiloader could still end up being installed but could end up working differently\n"); printf("Do you want the Continue ?\n"); printf("A = Yes B = No\n "); printf("\x1b[%u;%dm", 37, 1); if(!UserYesNoStop()) { fd = ISFS_Open(TMD_Path2,ISFS_OPEN_RW); if(fd >= 0) { //the backup is there. as safety lets copy it back. ISFS_Close(fd); nand_copy(TMD_Path2,TMD_Path,Perm); } abort("TMD failure"); return -1; } else { nand_copy(TMD_Path2,TMD_Path,Perm); printf("\nDone!\n"); return 1; } return r; } else return 1; _checkreturn: if(fd) { ISFS_Close(fd); } if(TMD_chk) { free(TMD_chk); TMD_chk = NULL; } printf("\x1b[%u;%dm", 33, 1); printf("\nWARNING!!\n Installer could not calculate the Checksum for the TMD!"); printf("\nbut Patch write was successfull.\n"); printf("Do you want the Continue ?\n"); printf("A = Yes B = No\n "); printf("\x1b[%u;%dm", 37, 1); if(!UserYesNoStop()) { printf("reverting changes...\n"); nand_copy(TMD_Path2,TMD_Path,Perm); abort("TMD Patch failure\n"); } else { printf("\nDone!\n"); } return -80; }
s32 install_IOS(IOS *ios, bool skipticket) { int ret; int cfd; if (!skipticket) { ((u8*)(ios->ticket))[0x1F1] = 0x00; /* -1029 fix */ ret = ES_AddTicket(ios->ticket, ios->ticket_size, ios->certs, ios->certs_size, ios->crl, ios->crl_size); if (ret < 0) { printf("ES_AddTicket returned: %d\n", ret); ES_AddTitleCancel(); return ret; } } printf("."); ret = ES_AddTitleStart(ios->tmd, ios->tmd_size, ios->certs, ios->certs_size, ios->crl, ios->crl_size); if (ret < 0) { printf("\nES_AddTitleStart returned: %d\n", ret); ES_AddTitleCancel(); return ret; } printf("."); tmd *tmd_data = (tmd *)SIGNATURE_PAYLOAD(ios->tmd); int i; for (i = 0; i < ios->content_count; i++) { tmd_content *content = &tmd_data->contents[i]; cfd = ES_AddContentStart(tmd_data->title_id, content->cid); if (cfd < 0) { printf("\nES_AddContentStart for content #%u cid %u returned: %d\n", i, content->cid, cfd); ES_AddTitleCancel(); return cfd; } ret = ES_AddContentData(cfd, ios->encrypted_buffer[i], ios->buffer_size[i]); if (ret < 0) { printf("\nES_AddContentData for content #%u cid %u returned: %d\n", i, content->cid, ret); ES_AddTitleCancel(); return ret; } ret = ES_AddContentFinish(cfd); if (ret < 0) { printf("\nES_AddContentFinish for content #%u cid %u returned: %d\n", i, content->cid, ret); ES_AddTitleCancel(); return ret; } printf("."); } ret = ES_AddTitleFinish(); if (ret < 0) { printf("\nES_AddTitleFinish returned: %d\n", ret); ES_AddTitleCancel(); return ret; } printf(".\n"); return 0; }