void NandDumper(){ File myFile; int isEmuNand = SYS_NAND; if(checkEmuNAND() && (isEmuNand = NandSwitch()) == UNK_NAND) return; isEmuNand--; ConsoleInit(); ConsoleSetTitle(L"%sNAND Dumper", isEmuNand ? "emu" : "sys"); unsigned char* buf = (void*)0x21000000; unsigned int nsectors = 0x200; //sectors in a row wchar_t ProgressBar[] = L"⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ "; unsigned int progress = 0; /* int BACKCOLOR = */ConsoleGetBackgroundColor(); //can be removed, left only to keep binaries the same if(FileOpen(&myFile, isEmuNand ? "rxTools/nand/EMUNAND.bin" : "rxTools/nand/NAND.bin", 1)){ print(L"Dumping...\n\n"); ConsoleShow(); int x, y; ConsoleGetXY(&x, &y); y += FONT_HEIGHT * 6; x += FONT_HWIDTH * 2; DrawString(BOT_SCREEN, ProgressBar, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); DrawString(BOT_SCREEN, L"Press Ⓑ anytime to abort", x, y + FONT_HEIGHT*2, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); for(int count = 0; count < NAND_SIZE/NAND_SECTOR_SIZE/nsectors; count++){ if(isEmuNand) sdmmc_sdcard_readsectors(count*nsectors, nsectors, buf); else sdmmc_nand_readsectors(count*nsectors, nsectors, buf); FileWrite(&myFile, buf, nsectors*NAND_SECTOR_SIZE, count*NAND_SECTOR_SIZE*nsectors); TryScreenShot(); if((count % (int)(NAND_SIZE/NAND_SECTOR_SIZE/nsectors/16)) == 0 && count != 0){ DrawString(BOT_SCREEN, PROGRESS_OK, x+(FONT_WIDTH*(progress++)), y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); } unsigned int pad = GetInput(); if(pad & BUTTON_B) break; } if(isEmuNand){ sdmmc_sdcard_readsectors(checkEmuNAND()/0x200, 1, buf); FileWrite(&myFile, buf, 0x200, 0); } FileClose(&myFile); print(L"\nFinished dumping!\n"); ConsoleShow(); }else{ print(L"Failed to create the dump.\n"); ConsoleShow(); } print(L"\nPress Ⓐ to exit\n"); ConsoleShow(); WaitForButton(BUTTON_A); }
void DumpNandPartitions(){ int isEmuNand = checkEmuNAND() ? NandSwitch() : 0; if(isEmuNand == -1) return; char* p_name[] = { "twln.bin", "twlp.bin", "agb_save.bin", "firm0.bin", "firm1.bin", "ctrnand.bin" }; unsigned int p_size[] = { 0x08FB5200, 0x020B6600, 0x00030000, 0x00400000, 0x00400000, 0x2F3E3600}; unsigned int p_addr[] = { TWLN, TWLP, AGB_SAVE, FIRM0, FIRM1, CTRNAND }; int sect_row = 0x80; ConsoleInit(); ConsoleAddText(isEmuNand ? "EmuNAND Partitions Decryptor\n \n" : "NAND Partitions Decryptor\n \n"); for(int i = 3; i < 6; i++){ //Cutting out twln, twlp and agb_save. Todo: Properly decrypt them File out; sprintf(myString, isEmuNand ? "nand/emu_%s" : "nand/%s", p_name[i]); FileOpen(&out, myString, 1); sprintf(myString, "Dumping %s ...", p_name[i]); ConsoleAddText(myString); ConsoleShow(); for(int j = 0; j*0x200 < p_size[i]; j += sect_row){ sprintf(myString, "%08X / %08X", j*0x200, p_size[i]); int x, y; ConsoleGetXY(&x, &y); y += CHAR_WIDTH * 4; x += CHAR_WIDTH*2; DrawString(TOP_SCREEN, myString, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); if(isEmuNand) emunand_readsectors(j, sect_row, BUF1, p_addr[i]); else nand_readsectors(j, sect_row, BUF1, p_addr[i]); FileWrite(&out, BUF1, sect_row*0x200, j*0x200); } FileClose(&out); } ConsoleAddText("\nPress A to exit"); ConsoleShow(); WaitForButton(BUTTON_A); }
void rxModeQuickBoot(){ if(!checkEmuNAND()){ rxMode(0); }else{ rxMode(1); } }
void NandDumper(){ File myFile; int isEmuNand = checkEmuNAND() ? NandSwitch() : 0; if(isEmuNand == -1) return; ConsoleInit(); ConsoleAddText(isEmuNand ? "EmuNAND Dumper\n" : "NAND Dumper\n"); unsigned char* buf = 0x21000000; unsigned int nsectors = 0x200; //sectors in a row char ProgressBar[] = "[ ]"; unsigned int progress = 1; int BACKCOLOR = ConsoleGetBackgroundColor(); if(FileOpen(&myFile, isEmuNand ? "/nand/EMUNAND.bin" : "/nand/NAND.bin", 1)){ ConsoleAddText("Dumping...\n"); ConsoleShow(); int x, y; ConsoleGetXY(&x, &y); y += CHAR_WIDTH * 6; x += CHAR_WIDTH*2; DrawString(TOP_SCREEN, ProgressBar, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); DrawString(TOP_SCREEN, "Press B anytime to abort", x, y + CHAR_WIDTH*2, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); for(int count = 0; count < NAND_SIZE/NAND_SECTOR_SIZE/nsectors; count++){ if(isEmuNand) sdmmc_sdcard_readsectors(count*nsectors, nsectors, buf); else sdmmc_nand_readsectors(count*nsectors, nsectors, buf); FileWrite(&myFile, buf, nsectors*NAND_SECTOR_SIZE, count*NAND_SECTOR_SIZE*nsectors); TryScreenShot(); if((count % (int)(NAND_SIZE/NAND_SECTOR_SIZE/nsectors/25)) == 0 && count != 0){ DrawString(TOP_SCREEN, "-", x+(CHAR_WIDTH*(progress++)), y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); } unsigned int pad = GetInput(); if(pad & BUTTON_B) break; } if(isEmuNand){ sdmmc_sdcard_readsectors(checkEmuNAND()/0x200, 1, buf); FileWrite(&myFile, buf, 0x200, 0); } FileClose(&myFile); ConsoleAddText("\nFinished dumping!"); ConsoleShow(); }else{ ConsoleAddText("Failed to create the dump"); ConsoleShow(); } ConsoleAddText("\nPress A to exit"); ConsoleShow(); WaitForButton(BUTTON_A); }
void rxModeEmu(){ if (!checkEmuNAND()) rxModeSys(); else{ sprintf(str, "/rxTools/Theme/%u/boot.bin", cfgs[CFG_THEME].val.i); DrawBottomSplash(str); rxMode(1); sprintf(str, "/rxTools/Theme/%u/bootE.bin", cfgs[CFG_THEME].val.i); DrawBottomSplash(str); WaitForButton(BUTTON_A); } }
void rxModeEmu(){ if(!checkEmuNAND()) rxModeSys(); else{ ConsoleInit(); ConsoleSetTitle("rxMode - Booting in EmuNand"); print("Loading...\n"); ConsoleShow(); rxMode(1); print("Cannot boot in rxMode.\n\nPress A to exit\n"); ConsoleShow(); WaitForButton(BUTTON_A); } }
void setFirmMode(int mode){ //0 : SysNand, 1 : EmuNand if(!checkEmuNAND()) mode = 0; //forcing to SysNand if there is no EmuNand File firm; u32 mmc_original[] = { 0x000D0004, 0x001E0017 }; u32 nat_emuwrite[] = { ARMBXR4, 0x0801A4C0 }; u32 nat_emuread[] = { ARMBXR4, 0x0801A5B0 }; if(FileOpen(&firm, "rxtools/data/0004013800000002.bin", 0)){ FileWrite(&firm, mode ? &nat_emuwrite : &mmc_original, 8, 0xCCF2C); FileWrite(&firm, mode ? &nat_emuread : &mmc_original, 8, 0xCCF6C); FileWrite(&firm, mode ? rxmode_emu_label : rxmode_sys_label, 4, 0x7A5A0); FileClose(&firm); } }
int NandSwitch(){ if(!checkEmuNAND()) return 0; //If No EmuNAND, we force to work on SysNAND ConsoleInit(); print(strings[STR_CHOOSE], strings[STR_NAND]); print(strings[STR_BLANK_BUTTON_ACTION], strings[STR_BUTTON_X], strings[STR_SYSNAND]); print(strings[STR_BLANK_BUTTON_ACTION], strings[STR_BUTTON_Y], strings[STR_EMUNAND]); print(strings[STR_BLANK_BUTTON_ACTION], strings[STR_BUTTON_B], strings[STR_CANCEL]); ConsoleShow(); while (true) { uint32_t pad_state = InputWait(); if(pad_state & BUTTON_X) return SYS_NAND; if(pad_state & BUTTON_Y) return EMU_NAND; if(pad_state & BUTTON_B) return UNK_NAND; } }
void DumpNandPartitions(){ ConsoleSetTitle(strings[STR_DUMP], strings[STR_NAND_PARTITIONS]); int isEmuNand = SYS_NAND; if(checkEmuNAND() && (isEmuNand = NandSwitch()) == UNK_NAND) return; isEmuNand--; ConsoleInit(); ConsoleSetTitle(strings[STR_DUMP], strings[STR_NAND_PARTITIONS]); print(strings[STR_PROCESSING], isEmuNand ? strings[STR_EMUNAND] : strings[STR_SYSNAND]); wchar_t* p_name[] = { L"twln.bin", L"twlp.bin", L"agb_save.bin", L"firm0.bin", L"firm1.bin", L"ctrnand.bin" }; wchar_t* p_descr[] = { strings[STR_TWLN], strings[STR_TWLP], strings[STR_AGB_SAVE], strings[STR_FIRM0], strings[STR_FIRM1], strings[STR_CTRNAND] }; unsigned int p_size[] = { 0x08FB5200, 0x020B6600, 0x00030000, 0x00400000, 0x00400000, getMpInfo() == MPINFO_KTR ? 0x41D2D200 : 0x2F3E3600 }; unsigned int p_addr[] = { TWLN, TWLP, AGB_SAVE, FIRM0, FIRM1, CTRNAND }; int sect_row = 0x80; wchar_t tmp[_MAX_LFN]; for(int i = 3; i < 6; i++){ //Cutting out twln, twlp and agb_save. Todo: Properly decrypt them File out; swprintf(tmp, _MAX_LFN, L"rxTools/nand/%ls%ls", isEmuNand ? L"emu_" : L"", p_name[i]); FileOpen(&out, tmp, 1); print(strings[STR_DUMPING], p_descr[i], tmp); ConsoleShow(); for(int j = 0; j*0x200 < p_size[i]; j += sect_row){ swprintf(tmp, _MAX_LFN, L"%08X / %08X", j*0x200, p_size[i]); int x, y; ConsoleGetXY(&x, &y); y += FONT_HEIGHT * 3; x += FONT_HWIDTH*2; ConsoleShow(); DrawString(BOT_SCREEN, tmp, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); if(isEmuNand) emunand_readsectors(j, sect_row, BUF1, p_addr[i]); else nand_readsectors(j, sect_row, BUF1, p_addr[i]); FileWrite(&out, BUF1, sect_row*0x200, j*0x200); } FileClose(&out); } print(strings[STR_PRESS_BUTTON_ACTION], strings[STR_BUTTON_A], strings[STR_CONTINUE]); ConsoleShow(); WaitForButton(BUTTON_A); }
int NandSwitch(){ if(!checkEmuNAND()) return 0; //If No EmuNAND, we force to work on SysNAND ConsoleInit(); /* freezes ConsoleSetTitle(STR_CHOOSE_NAND[language]); print(STR_PRESS_X_SYSNAND[language]); print(STR_PRESS_Y_EMUNAND[language]); print(STR_PRESS_B_BACK[language]); */ ConsoleSetTitle(L"Choose the NAND you want to use"); print(L"Ⓧ sysNAND\nⓎ emuNAND\nⒷ Cancel\n"); ConsoleShow(); while (true) { u32 pad_state = InputWait(); if(pad_state & BUTTON_X) return SYS_NAND; if(pad_state & BUTTON_Y) return EMU_NAND; if(pad_state & BUTTON_B) return UNK_NAND; } }
int main(){ Initialize(); DrawString(TOP_SCREEN, "SUPPORT THE ORIGINAL, NOT THE IMITATION!", 75, 240-10, GREY, BLACK); //7.X Keys stuff File KeyFile; if(FileOpen(&KeyFile, "/slot0x25KeyX.bin", 0)){ u8 keyX[16]; FileRead(&KeyFile, keyX, 16, 0); FileClose(&KeyFile); setup_aeskeyX(0x25, keyX); DrawString(TOP_SCREEN, " NewKeyX ", 0, 240-8, GREEN, BLACK); }else{ if(GetSystemVersion() < 3){ ConsoleInit(); print("WARNING:\n\nCannot find slot0x25KeyX.bin.\nSome titles decryption will fail,\nand some some EmuNANDs will not boot.\n\nPress A to continue...\n"); ConsoleShow(); WaitForButton(BUTTON_A); } DrawString(TOP_SCREEN, " NewKeyX ", 0, 240-8, RED, BLACK); } DrawString(TOP_SCREEN, " EmuNAND ", 0, 240-16, checkEmuNAND() ? GREEN : RED, BLACK); //That's the Main Menu initialization, easy and cool MenuInit(&MainMenu); MenuShow(); while (true) { DrawString(TOP_SCREEN, "[SELECT] Reboot", 349-18*8, 181-24-8, RED, BLACK); DrawString(TOP_SCREEN, "[START] Shutdown", 349-18*8, 181-24, RED, BLACK); u32 pad_state = InputWait(); if(pad_state & BUTTON_DOWN) MenuNextSelection(); if(pad_state & BUTTON_UP) MenuPrevSelection(); if(pad_state & BUTTON_A) MenuSelect(); if(pad_state & BUTTON_SELECT) returnHomeMenu(); if(pad_state & BUTTON_START) ShutDown(); TryScreenShot(); MenuShow(); } FSDeInit(); return 0; }
void DumpNandPartitions(){ int isEmuNand = SYS_NAND; if(checkEmuNAND() && (isEmuNand = NandSwitch()) == UNK_NAND) return; isEmuNand--; char* p_name[] = { "twln.bin", "twlp.bin", "agb_save.bin", "firm0.bin", "firm1.bin", "ctrnand.bin" }; unsigned int p_size[] = { 0x08FB5200, 0x020B6600, 0x00030000, 0x00400000, 0x00400000, 0x2F3E3600}; unsigned int p_addr[] = { TWLN, TWLP, AGB_SAVE, FIRM0, FIRM1, CTRNAND }; int sect_row = 0x80; ConsoleInit(); ConsoleSetTitle(L"%sNAND Partitions Decryptor", isEmuNand ? "emu" : "sys"); char tmp[256]; wchar_t wtmp[256]; for(int i = 3; i < 6; i++){ //Cutting out twln, twlp and agb_save. Todo: Properly decrypt them File out; sprintf(tmp, "rxTools/nand/%s%s", isEmuNand ? "emu_" : "", p_name[i]); FileOpen(&out, tmp, 1); print(L"Dumping %s ...\n", p_name[i]); ConsoleShow(); for(int j = 0; j*0x200 < p_size[i]; j += sect_row){ swprintf(wtmp, sizeof(wtmp)/sizeof(wtmp[0]), L"%08X / %08X", j*0x200, p_size[i]); int x, y; ConsoleGetXY(&x, &y); y += FONT_HEIGHT * 3; x += FONT_HWIDTH*2; DrawString(BOT_SCREEN, wtmp, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); if(isEmuNand) emunand_readsectors(j, sect_row, BUF1, p_addr[i]); else nand_readsectors(j, sect_row, BUF1, p_addr[i]); FileWrite(&out, BUF1, sect_row*0x200, j*0x200); } FileClose(&out); } print(L"\nPress Ⓐ to exit\n"); ConsoleShow(); WaitForButton(BUTTON_A); }
int rxMode(int emu) { if (!checkEmuNAND() && emu) { ConsoleInit(); ConsoleSetTitle(L"EMUNAND NOT FOUND!"); print(L"The emunand was not found on\n"); print(L"your SDCard. \n"); print(L"\n"); print(L"Press A to boot SYSNAND\n"); ConsoleShow(); WaitForButton(BUTTON_A); emu = 0; char s[32]; sprintf(s, "/rxTools/Theme/%u/boot.bin", cfgs[CFG_THEME].val.i); DrawBottomSplash(s); } static const char patchNandPrefix[] = ".patch.p9.nand"; unsigned int cur, offset, shstrSize; char path[64], shstrtab[512], *sh_name; const char *platformDir; const wchar_t *msg; int r, sector; void *p; Elf32_Ehdr ehdr; Elf32_Shdr shdr; FIL fd, keyxFd; UINT br, fsz; setAgbBios(); getFirmPath(path, getMpInfo() == MPINFO_KTR ? TID_KTR_NATIVE_FIRM : TID_CTR_NATIVE_FIRM); strcpy(path + strlen(path) - 4, "orig.bin"); r = loadFirm(path, &fsz); if (r) { msg = L"Failed to load NATIVE_FIRM: %d\n" L"Reboot rxTools and try again.\n"; goto fail; } r = getMpInfo(); switch (r) { case MPINFO_KTR: platformDir = "ktr"; break; case MPINFO_CTR: platformDir = "ctr"; break; default: msg = L"Unknown Platform: %d"; goto fail; } sprintf(path, SYS_PATH "/patches/%s/native_firm.elf", platformDir); r = f_open(&fd, path, FA_READ); if (r != FR_OK) goto patchFail; r = f_read(&fd, &ehdr, sizeof(ehdr), &br); if (r != FR_OK) goto patchFail; r = f_lseek(&fd, ehdr.e_shoff + ehdr.e_shstrndx * sizeof(Elf32_Shdr)); if (r != FR_OK) goto patchFail; r = f_read(&fd, &shdr, sizeof(shdr), &br); if (r != FR_OK) goto patchFail; r = f_lseek(&fd, shdr.sh_offset); if (r != FR_OK) goto patchFail; r = f_read(&fd, shstrtab, shdr.sh_size > sizeof(shstrtab) ? sizeof(shstrtab) : shdr.sh_size, &shstrSize); if (r != FR_OK) goto patchFail; if (emu) { sector = checkEmuNAND(); if (sector == 0) { msg = L"Failed to find EmuNAND.\n" L"Check your EmuNAND.\n"; goto fail; } } else sector = 0; cur = ehdr.e_shoff; for (; ehdr.e_shnum; ehdr.e_shnum--, cur += sizeof(shdr)) { if (f_lseek(&fd, cur) != FR_OK) continue; if (f_read(&fd, &shdr, sizeof(shdr), &br) != FR_OK) continue; if (!(shdr.sh_flags & SHF_ALLOC) || shdr.sh_name >= shstrSize) continue; offset = locateSecInFirm(&shdr, (FirmHdr *)FIRM_ADDR); if (offset == 0) continue; p = (void *)(FIRM_ADDR + offset); sh_name = shstrtab + shdr.sh_name; if (!strcmp(sh_name, ".rodata.keyx")) { if (sysver >= 7) continue; if (f_open(&keyxFd, "slot0x25KeyX.bin", FA_READ) != FR_OK) continue; f_read(&keyxFd, p, shdr.sh_size, &br); f_close(&keyxFd); } else if (!strcmp(sh_name, ".rodata.nand.sector")) { if (sector) *(uint32_t *)p = (sector / 0x200) - 1; } else if (!strcmp(sh_name, ".rodata.label")) { *(uint32_t *)p = sector ? 'E-XR' : 'S-XR'; } else if (shdr.sh_type == SHT_PROGBITS && (sector || memcmp(sh_name, patchNandPrefix, sizeof(patchNandPrefix) - 1)) && (sysver < 7 || strcmp(sh_name, ".patch.p9.keyx"))) { if (f_lseek(&fd, shdr.sh_offset) != FR_OK) continue; f_read(&fd, p, shdr.sh_size, &br); } } getFirmPath(path, getMpInfo() == MPINFO_KTR ? TID_KTR_NATIVE_FIRM : TID_CTR_NATIVE_FIRM); f_open(&fd, path, FA_WRITE | FA_CREATE_ALWAYS); f_write(&fd, (void *)FIRM_ADDR, fsz, &br); f_close(&fd); r = loadExecReboot(); // This won't return if it succeeds. msg = L"Failed to load reboot.bin: %d\n" L"Check your installation.\n"; fail: ConsoleInit(); ConsoleSetTitle(L"rxMode"); print(msg, r); print(L"\n"); print(strings[STR_PRESS_BUTTON_ACTION], strings[STR_BUTTON_A], strings[STR_CONTINUE]); ConsoleShow(); WaitForButton(BUTTON_A); return r; patchFail: msg = L"Failed to load native_firm.elf: %d\n" L"Check your installation.\n"; goto fail; }
int rxMode(int emu) { wchar_t path[64]; const char *shstrtab; const wchar_t *msg; uint8_t keyx[16]; uint32_t tid; int r, sector; Elf32_Ehdr *ehdr; Elf32_Shdr *shdr, *btm; void *keyxArg; FIL fd; UINT br, fsz; if (emu) { sector = checkEmuNAND(); if (sector == 0) { ConsoleInit(); ConsoleSetTitle(L"EMUNAND NOT FOUND!"); print(L"The emunand was not found on\n"); print(L"your SDCard. \n"); print(L"\n"); print(L"Press A to boot SYSNAND\n"); ConsoleShow(); WaitForButton(BUTTON_A); swprintf(path, _MAX_LFN, L"/rxTools/Theme/%u/boot.bin", cfgs[CFG_THEME].val.i); DrawBottomSplash(path); } } else sector = 0; r = getMpInfo(); switch (r) { case MPINFO_KTR: tid = TID_KTR_NATIVE_FIRM; break; case MPINFO_CTR: tid = TID_CTR_NATIVE_FIRM; break; default: msg = L"Unknown Platform: %d"; goto fail; } setAgbBios(); if (sysver < 7 && f_open(&fd, _T("slot0x25KeyX.bin"), FA_READ) == FR_OK) { f_read(&fd, keyx, sizeof(keyx), &br); f_close(&fd); keyxArg = keyx; } else keyxArg = NULL; getFirmPath(path, tid); r = loadFirm(path, &fsz); if (r) { msg = L"Failed to load NATIVE_FIRM: %d\n" L"Reboot rxTools and try again.\n"; goto fail; } ((FirmHdr *)FIRM_ADDR)->arm9Entry = 0x0801B01C; getFirmPatchPath(path, tid); r = f_open(&fd, path, FA_READ); if (r != FR_OK) goto patchFail; r = f_read(&fd, (void *)PATCH_ADDR, PATCH_SIZE, &br); if (r != FR_OK) goto patchFail; f_close(&fd); ehdr = (void *)PATCH_ADDR; shdr = (void *)(PATCH_ADDR + ehdr->e_shoff); shstrtab = (char *)PATCH_ADDR + shdr[ehdr->e_shstrndx].sh_offset; for (btm = shdr + ehdr->e_shnum; shdr != btm; shdr++) { if (!strcmp(shstrtab + shdr->sh_name, ".patch.p9.reboot.body")) { execReboot(sector, keyxArg, ehdr->e_entry, shdr); __builtin_unreachable(); } } msg = L".patch.p9.reboot.body not found\n" L"Please check your installation.\n"; fail: ConsoleInit(); ConsoleSetTitle(L"rxMode"); print(msg, r); print(L"\n"); print(strings[STR_PRESS_BUTTON_ACTION], strings[STR_BUTTON_A], strings[STR_CONTINUE]); ConsoleShow(); WaitForButton(BUTTON_A); return r; patchFail: msg = L"Failed to load the patch: %d\n" L"Check your installation.\n"; goto fail; }
int InstallData(char* drive){ static const FirmInfo agb_info = { 0x8B800, 0x4CE00, 0x08006800, 0xD600, 0xE200, 0x08020000}; static const FirmInfo twl_info = { 0x153600, 0x4D200, 0x08006800, 0xD600, 0xE200, 0x08020000}; FIL firmfile; unsigned int progressWidth, progressX; wchar_t progressbar[8] = {0,}; wchar_t *progress = progressbar; int i; progressWidth = getMpInfo() == MPINFO_CTR ? 7 : 3; progressX = (BOT_SCREEN_WIDTH - progressWidth * FONT_WIDTH) / 2; for (i = 0; i < progressWidth; i++) wcscat(progressbar, strings[STR_PROGRESS]); print(L"%ls", progressbar); ConsolePrevLine(); //Create the workdir sprintf(tmpstr, "%s:%s", drive, DATAFOLDER); f_mkdir(tmpstr); //Read firmware data if (f_open(&firmfile, "firmware.bin", FA_READ | FA_OPEN_EXISTING) != FR_OK) return CONF_NOFIRMBIN; wcsncpy(progress, strings[STR_PROGRESS_OK], wcslen(strings[STR_PROGRESS_OK])); progress += wcslen(strings[STR_PROGRESS_OK]); DrawString(BOT_SCREEN, progressbar, progressX, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); //Create decrypted native_firm f_read(&firmfile, WORKBUF, NAT_SIZE, &tmpu32); uint8_t* n_firm = decryptFirmTitle(WORKBUF, NAT_SIZE, 0x00000002, 1); wcsncpy(progress, strings[STR_PROGRESS_OK], wcslen(strings[STR_PROGRESS_OK])); progress += wcslen(strings[STR_PROGRESS_OK]); DrawString(BOT_SCREEN, progressbar, progressX, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); getFirmPath(tmpstr, getMpInfo() == MPINFO_KTR ? TID_KTR_NATIVE_FIRM : TID_CTR_NATIVE_FIRM); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, n_firm, NAT_SIZE, 0); FileClose(&tempfile); }else { f_close(&firmfile); return CONF_ERRNFIRM; } wcsncpy(progress, strings[STR_PROGRESS_OK], wcslen(strings[STR_PROGRESS_OK])); progress += wcslen(strings[STR_PROGRESS_OK]); DrawString(BOT_SCREEN, progressbar, progressX, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); if (getMpInfo() != MPINFO_CTR) goto end; //Create AGB patched firmware f_read(&firmfile, WORKBUF, AGB_SIZE, &tmpu32); uint8_t* a_firm = decryptFirmTitle(WORKBUF, AGB_SIZE, 0x00000202, 1); if (!a_firm && checkEmuNAND()) { /* Try to get the Title Key from the EmuNAND */ a_firm = decryptFirmTitle(WORKBUF, AGB_SIZE, 0x00000202, 2); if (!a_firm) { /* If we cannot decrypt it from firmware.bin because of titlekey messed up, it probably means that AGB has been modified in some way. */ //So we read it from his installed ncch... FindApp(0x00040138, 0x00000202, 1); char* path = getContentAppPath(); if (!FileOpen(&tempfile, path, 0) && checkEmuNAND()) { /* Try with EmuNAND */ FindApp(0x00040138, 0x00000202, 2); path = getContentAppPath(); if (!FileOpen(&tempfile, path, 0)) { f_close(&firmfile); return CONF_ERRNFIRM; } } FileRead(&tempfile, WORKBUF, AGB_SIZE, 0); FileClose(&tempfile); a_firm = decryptFirmTitleNcch(WORKBUF, AGB_SIZE); } } if (a_firm) { if (applyPatch(a_firm, "/rxTools/system/patches/ctr/agb_firm.elf", &agb_info)) return CONF_ERRPATCH; getFirmPath(tmpstr, TID_CTR_TWL_FIRM); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, a_firm, AGB_SIZE, 0); FileClose(&tempfile); }else { f_close(&firmfile); return CONF_ERRNFIRM; } wcsncpy(progress, strings[STR_PROGRESS_OK], wcslen(strings[STR_PROGRESS_OK])); progress += wcslen(strings[STR_PROGRESS_OK]); } else { wcsncpy(progress, strings[STR_PROGRESS_FAIL], wcslen(strings[STR_PROGRESS_FAIL])); progress += wcslen(strings[STR_PROGRESS_FAIL]); //If we get here, then we'll play without AGB, lol } DrawString(BOT_SCREEN, progressbar, progressX, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); //Create TWL patched firmware f_read(&firmfile, WORKBUF, TWL_SIZE, &tmpu32); uint8_t* t_firm = decryptFirmTitle(WORKBUF, TWL_SIZE, 0x00000102, 1); if(t_firm){ if (applyPatch(t_firm, "/rxTools/system/patches/ctr/twl_firm.elf", &twl_info)) return CONF_ERRPATCH; getFirmPath(tmpstr, TID_CTR_TWL_FIRM); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, t_firm, TWL_SIZE, 0); FileClose(&tempfile); //FileCopy("0004013800000102.bin", tmpstr); }else { f_close(&firmfile); return CONF_ERRNFIRM; } wcsncpy(progress, strings[STR_PROGRESS_OK], wcslen(strings[STR_PROGRESS_OK])); progress += wcslen(strings[STR_PROGRESS_OK]); }else{ wcsncpy(progress, strings[STR_PROGRESS_FAIL], wcslen(strings[STR_PROGRESS_FAIL])); progress += wcslen(strings[STR_PROGRESS_FAIL]); } DrawString(BOT_SCREEN, progressbar, progressX, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); sprintf(tmpstr, "%s:%s/data.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, __DATE__, 12, 0); FileWrite(&tempfile, __TIME__, 9, 12); FileClose(&tempfile); }else { f_close(&firmfile); return CONF_CANTOPENFILE; } wcsncpy(progress, strings[STR_PROGRESS_OK], wcslen(strings[STR_PROGRESS_OK])); progress += wcslen(strings[STR_PROGRESS_OK]); DrawString(BOT_SCREEN, progressbar, progressX, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); end: f_close(&firmfile); return 0; }
int InstallData(char* drive){ FIL firmfile; char* progressbar = "[ ]"; char* progress = progressbar+1; print("%s", progressbar); ConsolePrevLine(); //Create the workdir sprintf(tmpstr, "%s:%s", drive, DATAFOLDER); f_mkdir(tmpstr); f_chmod(tmpstr, AM_HID, AM_HID); //Read firmware data if(f_open(&firmfile, "firmware.bin", FA_READ | FA_OPEN_EXISTING) == FR_OK){ //... We'll see }else return CONF_NOFIRMBIN; *progress++ = '.'; DrawString(BOT_SCREEN, progressbar, 130, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); //Create patched native_firm f_read(&firmfile, WORKBUF, NAT_SIZE, &tmpu32); u8* n_firm = decryptFirmTitle(WORKBUF, NAT_SIZE, 0x00000002); u8* n_firm_patch = GetFilePack("nat_patch.bin"); applyPatch(n_firm, n_firm_patch); u8 keyx[16] = {0}; if(GetSystemVersion() < 3){ FileOpen(&tempfile, KEYFILENAME, 0); FileRead(&tempfile, &keyx[0], 16, 0); FileClose(&tempfile); } *progress++ = '.'; DrawString(BOT_SCREEN, progressbar, 130, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); for(int i = 0; i < NAT_SIZE; i+=0x4){ if(!strcmp((char*)n_firm + i, "Shit")){ if(1){ memcpy((char*)n_firm + i, rxmode_emu_label, 4); }else{ memcpy((char*)n_firm + i, rxmode_sys_label , 4); } } if(!strcmp((char*)n_firm + i, "InsertKeyXHere!") && keyx[0] != 0){ memcpy(n_firm + i, keyx, 16); } if(*((unsigned int*)(n_firm + i)) == 0xAAAABBBB){ *((unsigned int*)(n_firm + i)) = (checkEmuNAND() / 0x200) - 1; } } *progress++ = '.'; DrawString(BOT_SCREEN, progressbar, 130, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); sprintf(tmpstr, "%s:%s/0004013800000002.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, n_firm, NAT_SIZE, 0); FileClose(&tempfile); //FileCopy("0004013800000002.bin", tmpstr); }else return CONF_ERRNFIRM; *progress++ = '.'; DrawString(BOT_SCREEN, progressbar, 130, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); //Create AGB patched firmware f_read(&firmfile, WORKBUF, AGB_SIZE, &tmpu32); u8* a_firm = decryptFirmTitle(WORKBUF, AGB_SIZE, 0x00000202); u8* a_firm_patch = GetFilePack("agb_patch.bin"); if(a_firm){ applyPatch(a_firm, a_firm_patch); sprintf(tmpstr, "%s:%s/0004013800000202.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, a_firm, AGB_SIZE, 0); FileClose(&tempfile); }else return CONF_ERRNFIRM; *progress++ = '.'; }else{ //If we cannot decrypt it from firmware.bin becouse of titlekey messed up, it probably means that AGB has been modified in some way. //So we read it from his installed ncch... FindApp(0x00040138, 0x00000202, 1); char* path = getContentAppPath(); FileOpen(&tempfile, path, 0); FileRead(&tempfile, WORKBUF, AGB_SIZE, 0); FileClose(&tempfile); a_firm = decryptFirmTitleNcch(WORKBUF, AGB_SIZE); if(a_firm){ applyPatch(a_firm, a_firm_patch); sprintf(tmpstr, "%s:%s/0004013800000202.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, a_firm, AGB_SIZE, 0); FileClose(&tempfile); }else return CONF_ERRNFIRM; *progress++ = '.'; }else{ *progress++ = 'x'; //If we get here, then we'll play without AGB, lol } } DrawString(BOT_SCREEN, progressbar, 130, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); //Create TWL patched firmware f_read(&firmfile, WORKBUF, TWL_SIZE, &tmpu32); u8* t_firm = decryptFirmTitle(WORKBUF, TWL_SIZE, 0x00000102); u8* t_firm_patch = GetFilePack("twl_patch.bin"); if(t_firm){ applyPatch(t_firm, t_firm_patch); sprintf(tmpstr, "%s:%s/0004013800000102.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, t_firm, TWL_SIZE, 0); FileClose(&tempfile); //FileCopy("0004013800000102.bin", tmpstr); }else return CONF_ERRNFIRM; *progress++ = '.'; }else{ *progress++ = 'x'; } DrawString(BOT_SCREEN, progressbar, 130, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); sprintf(tmpstr, "%s:%s/data.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, __DATE__, 12, 0); FileWrite(&tempfile, __TIME__, 9, 12); FileClose(&tempfile); }else return CONF_CANTOPENFILE; *progress++ = '.'; DrawString(BOT_SCREEN, progressbar, 130, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); f_close(&firmfile); return 0; }
int InstallData(char* drive){ static const FirmInfo native_info = { 0x66000, 0x84A00, 0x08006800, 0x35000, 0x31000, 0x1FF80000, 0x15B00, 0x16700, 0x08028000}; static const FirmInfo agb_info = { 0x8B800, 0x4CE00, 0x08006800, 0, 0, 0, 0xD600, 0xE200, 0x08020000}; static const FirmInfo twl_info = { 0x153600, 0x4D200, 0x08006800, 0, 0, 0, 0xD600, 0xE200, 0x08020000}; FIL firmfile; wchar_t *progressbar = L"⬜⬜⬜⬜⬜⬜⬜"; wchar_t *progress = progressbar+0; print(L"%ls", progressbar); ConsolePrevLine(); //Create the workdir sprintf(tmpstr, "%s:%s", drive, DATAFOLDER); f_mkdir(tmpstr); //Read firmware data if (f_open(&firmfile, "firmware.bin", FA_READ | FA_OPEN_EXISTING) != FR_OK) return CONF_NOFIRMBIN; *progress++ = PROGRESS_OK; DrawString(BOT_SCREEN, progressbar, PROGRESS_X, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); //Create patched native_firm f_read(&firmfile, WORKBUF, NAT_SIZE, &tmpu32); u8* n_firm = decryptFirmTitle(WORKBUF, NAT_SIZE, 0x00000002, 1); if (applyPatch(n_firm, "/rxTools/system/patches/native_firm.elf", &native_info)) return CONF_ERRPATCH; u8 keyx[16] = {0}; if(GetSystemVersion() < 3){ if (!FileOpen(&tempfile, KEYFILENAME, 0)) { f_close(&firmfile); return CONF_CANTOPENFILE; } FileRead(&tempfile, &keyx[0], 16, 0); FileClose(&tempfile); } *progress++ = PROGRESS_OK; DrawString(BOT_SCREEN, progressbar, PROGRESS_X, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); for(int i = 0; i < NAT_SIZE; i+=0x4){ if(!strcmp((char*)n_firm + i, "InsertKeyXHere!") && keyx[0] != 0){ memcpy(n_firm + i, keyx, 16); } if(*((unsigned int*)(n_firm + i)) == 0xAAAABBBB){ *((unsigned int*)(n_firm + i)) = (checkEmuNAND() / 0x200) - 1; } } *progress++ = PROGRESS_OK; DrawString(BOT_SCREEN, progressbar, PROGRESS_X, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); sprintf(tmpstr, "%s:%s/0004013800000002.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, n_firm, NAT_SIZE, 0); FileClose(&tempfile); }else { f_close(&firmfile); return CONF_ERRNFIRM; } *progress++ = PROGRESS_OK; DrawString(BOT_SCREEN, progressbar, PROGRESS_X, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); //Create AGB patched firmware f_read(&firmfile, WORKBUF, AGB_SIZE, &tmpu32); u8* a_firm = decryptFirmTitle(WORKBUF, AGB_SIZE, 0x00000202, 1); if (!a_firm && checkEmuNAND()) { /* Try to get the Title Key from the EmuNAND */ a_firm = decryptFirmTitle(WORKBUF, AGB_SIZE, 0x00000202, 2); if (!a_firm) { /* If we cannot decrypt it from firmware.bin because of titlekey messed up, it probably means that AGB has been modified in some way. */ //So we read it from his installed ncch... FindApp(0x00040138, 0x00000202, 1); char* path = getContentAppPath(); if (!FileOpen(&tempfile, path, 0) && checkEmuNAND()) { /* Try with EmuNAND */ FindApp(0x00040138, 0x00000202, 2); path = getContentAppPath(); if (!FileOpen(&tempfile, path, 0)) { f_close(&firmfile); return CONF_ERRNFIRM; } } FileRead(&tempfile, WORKBUF, AGB_SIZE, 0); FileClose(&tempfile); a_firm = decryptFirmTitleNcch(WORKBUF, AGB_SIZE); } } if (a_firm) { if (applyPatch(a_firm, "/rxTools/system/patches/agb_firm.elf", &agb_info)) return CONF_ERRPATCH; sprintf(tmpstr, "%s:%s/0004013800000202.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, a_firm, AGB_SIZE, 0); FileClose(&tempfile); }else { f_close(&firmfile); return CONF_ERRNFIRM; } *progress++ = PROGRESS_OK; } else { *progress++ = PROGRESS_FAIL; //If we get here, then we'll play without AGB, lol } DrawString(BOT_SCREEN, progressbar, PROGRESS_X, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); //Create TWL patched firmware f_read(&firmfile, WORKBUF, TWL_SIZE, &tmpu32); u8* t_firm = decryptFirmTitle(WORKBUF, TWL_SIZE, 0x00000102, 1); if(t_firm){ if (applyPatch(t_firm, "/rxTools/system/patches/twl_firm.elf", &twl_info)) return CONF_ERRPATCH; sprintf(tmpstr, "%s:%s/0004013800000102.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, t_firm, TWL_SIZE, 0); FileClose(&tempfile); //FileCopy("0004013800000102.bin", tmpstr); }else { f_close(&firmfile); return CONF_ERRNFIRM; } *progress++ = PROGRESS_OK; }else{ *progress++ = PROGRESS_FAIL; } DrawString(BOT_SCREEN, progressbar, PROGRESS_X, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); sprintf(tmpstr, "%s:%s/data.bin", drive, DATAFOLDER); if(FileOpen(&tempfile, tmpstr, 1)){ FileWrite(&tempfile, __DATE__, 12, 0); FileWrite(&tempfile, __TIME__, 9, 12); FileClose(&tempfile); }else { f_close(&firmfile); return CONF_CANTOPENFILE; } *progress++ = PROGRESS_OK; DrawString(BOT_SCREEN, progressbar, PROGRESS_X, 50, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); f_close(&firmfile); return 0; }
int rxMode(int emu) { const Elf32_Addr line = 32; wchar_t path[64]; const char *shstrtab; const wchar_t *msg; uint8_t keyx[16]; uint32_t tid; int r, sector; Elf32_Ehdr *ehdr; Elf32_Shdr *shdr, *btmShdr; Elf32_Addr cur, btm; void *keyxArg; FIL fd; UINT br, fsz; if (emu) { sector = checkEmuNAND(); if (sector == 0) { ConsoleInit(); ConsoleSetTitle(L"EMUNAND NOT FOUND!"); print(L"The emunand was not found on\n"); print(L"your SDCard. \n"); print(L"\n"); print(L"Press A to boot SYSNAND\n"); ConsoleShow(); WaitForButton(BUTTON_A); swprintf(path, _MAX_LFN, L"/rxTools/Theme/%u/boot.bin", cfgs[CFG_THEME].val.i); DrawBottomSplash(path); } } else sector = 0; r = getMpInfo(); switch (r) { case MPINFO_KTR: tid = TID_KTR_NATIVE_FIRM; break; case MPINFO_CTR: tid = TID_CTR_NATIVE_FIRM; break; default: msg = L"Unknown Platform: %d"; goto fail; } setAgbBios(); if (sysver < 7 && f_open(&fd, _T("slot0x25KeyX.bin"), FA_READ) == FR_OK) { f_read(&fd, keyx, sizeof(keyx), &br); f_close(&fd); keyxArg = keyx; } else keyxArg = NULL; getFirmPath(path, tid); r = loadFirm(path, &fsz); if (r) { msg = L"Failed to load NATIVE_FIRM: %d\n" L"Reboot rxTools and try again.\n"; goto fail; } ((FirmHdr *)FIRM_ADDR)->arm9Entry = 0x0801B01C; getFirmPatchPath(path, tid); r = f_open(&fd, path, FA_READ); if (r != FR_OK) goto patchFail; r = f_read(&fd, (void *)PATCH_ADDR, PATCH_SIZE, &br); if (r != FR_OK) goto patchFail; f_close(&fd); ehdr = (void *)PATCH_ADDR; shdr = (void *)(PATCH_ADDR + ehdr->e_shoff); shstrtab = (char *)PATCH_ADDR + shdr[ehdr->e_shstrndx].sh_offset; for (btmShdr = shdr + ehdr->e_shnum; shdr != btmShdr; shdr++) { if (!strcmp(shstrtab + shdr->sh_name, ".patch.p9.reboot.body")) { memcpy((void *)ehdr->e_entry, (void *)(PATCH_ADDR + shdr->sh_offset), shdr->sh_size); // Drain write buffer __asm__ volatile ("mcr p15, 0, %0, c7, c10, 4" :: "r"(0)); cur = ehdr->e_entry & ~(line - 1); btm = ehdr->e_entry + shdr->sh_size; while (cur < btm) { __asm__ volatile ( // Clean Dcache "mcr p15, 0, %0, c7, c10, 1\n\t" // Flush Icache "mcr p15, 0, %0, c7, c5, 1" :: "r"(cur)); cur += line; } ((void (*)(uint32_t, void *, uintptr_t))ehdr->e_entry)( sector, keyxArg, 0x1FFFFFF8); __builtin_unreachable(); } }
void NandDumper(){ ConsoleSetTitle(strings[STR_DUMP], strings[STR_NAND]); File myFile; int isEmuNand = SYS_NAND; if(checkEmuNAND() && (isEmuNand = NandSwitch()) == UNK_NAND) return; isEmuNand--; ConsoleInit(); ConsoleSetTitle(strings[STR_DUMP], strings[STR_NAND]); unsigned char* buf = (void*)0x21000000; unsigned int nsectors = 0x200; //sectors in a row wchar_t tmpstr[STR_MAX_LEN]; wchar_t ProgressBar[41] = {0,}; for(int i=0; i<PROGRESS_WIDTH; i++) wcscat(ProgressBar, strings[STR_PROGRESS]); unsigned int progress = 0; wchar_t filename[_MAX_LFN]; swprintf(filename, _MAX_LFN, L"rxTools/nand/%sNAND.bin", isEmuNand ? L"EMU" : L""); if(FileOpen(&myFile, filename, 1)){ print(strings[STR_DUMPING], isEmuNand ? strings[STR_EMUNAND] : strings[STR_SYSNAND], filename); ConsoleShow(); int x, y; ConsoleGetXY(&x, &y); y += FONT_HEIGHT * 6; x += FONT_HWIDTH * 2; DrawString(BOT_SCREEN, ProgressBar, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); swprintf(tmpstr, STR_MAX_LEN, strings[STR_PRESS_BUTTON_ACTION], strings[STR_BUTTON_B], strings[STR_CANCEL]); DrawString(BOT_SCREEN, tmpstr, x, y + FONT_HEIGHT*2, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); for(int count = 0; count < getNandSize()/NAND_SECTOR_SIZE/nsectors; count++){ if(isEmuNand) sdmmc_sdcard_readsectors(count*nsectors, nsectors, buf); else sdmmc_nand_readsectors(count*nsectors, nsectors, buf); FileWrite(&myFile, buf, nsectors*NAND_SECTOR_SIZE, count*NAND_SECTOR_SIZE*nsectors); TryScreenShot(); if((count % (int)(getNandSize()/NAND_SECTOR_SIZE/nsectors/PROGRESS_WIDTH)) == 0 && count != 0){ DrawString(BOT_SCREEN, strings[STR_PROGRESS_OK], x+(FONT_WIDTH*(progress++)), y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); } unsigned int pad = GetInput(); if (pad & BUTTON_B) { FileClose(&myFile); goto end; } } if(isEmuNand){ sdmmc_sdcard_readsectors(checkEmuNAND()/0x200, 1, buf); FileWrite(&myFile, buf, 0x200, 0); } FileClose(&myFile); print(strings[STR_COMPLETED]); ConsoleShow(); }else{ print(strings[STR_FAILED]); ConsoleShow(); } end: print(strings[STR_PRESS_BUTTON_ACTION], strings[STR_BUTTON_A], strings[STR_CONTINUE]); ConsoleShow(); WaitForButton(BUTTON_A); }