From 513bd804b1c3c06bce41472d1c7bcf88d6fc4131 Mon Sep 17 00:00:00 2001 From: suchmememanyskill Date: Mon, 28 Dec 2020 02:29:58 +0100 Subject: [PATCH] Add fw dumping - also fatfs is stupid - also close files properly on a failed copy - also check for errors during folder readouts - also make sure holding vol- doesn't dump the keys anyway --- bdk/libs/fatfs/ff.c | 3 +- source/fs/fscopy.c | 9 ++- source/fs/fsutils.c | 11 ++- source/fs/fsutils.h | 3 +- source/fs/menus/explorer.c | 19 +++--- source/fs/menus/filemenu.c | 8 +-- source/fs/readers/folderReader.c | 16 +++-- source/fs/readers/folderReader.h | 3 +- source/gfx/gfxutils.c | 9 +++ source/gfx/gfxutils.h | 3 +- source/keys/nca.c | 31 +++++++++ source/keys/nca.h | 12 ++++ source/main.c | 3 +- source/storage/gptmenu.c | 1 + source/storage/mountmanager.c | 4 ++ source/tegraexplorer/mainmenu.c | 2 + source/tegraexplorer/tools.c | 111 +++++++++++++++++++++++++++++++ source/tegraexplorer/tools.h | 3 +- 18 files changed, 222 insertions(+), 29 deletions(-) create mode 100644 source/keys/nca.c create mode 100644 source/keys/nca.h diff --git a/bdk/libs/fatfs/ff.c b/bdk/libs/fatfs/ff.c index 9035f35..94f4522 100644 --- a/bdk/libs/fatfs/ff.c +++ b/bdk/libs/fatfs/ff.c @@ -4048,7 +4048,8 @@ FRESULT f_write ( } if (clst == 0) { EFSPRINTF("DSKFULL"); - break; /* Could not allocate a new cluster (disk full) */ + fp->flag |= FA_MODIFIED; + ABORT(fs, FR_DISK_ERR); /* Could not allocate a new cluster (disk full) */ } if (clst == 1) { EFSPRINTF("CCHK"); diff --git a/source/fs/fscopy.c b/source/fs/fscopy.c index 2ce23ba..794dbea 100644 --- a/source/fs/fscopy.c +++ b/source/fs/fscopy.c @@ -13,6 +13,7 @@ ErrCode_t FileCopy(const char *locin, const char *locout, u8 options){ u64 sizeRemaining, toCopy; u8 *buff; u32 x, y; + ErrCode_t err = newErrCode(0); int res = 0; gfx_con_getpos(&x, &y); @@ -47,11 +48,13 @@ ErrCode_t FileCopy(const char *locin, const char *locout, u8 options){ toCopy = MIN(sizeRemaining, TConf.FSBuffSize); if ((res = f_read(&in, buff, toCopy, NULL))){ - return newErrCode(res); + err = newErrCode(res); + break; } if ((res = f_write(&out, buff, toCopy, NULL))){ - return newErrCode(res); + err = newErrCode(res); + break; } sizeRemaining -= toCopy; @@ -74,5 +77,5 @@ ErrCode_t FileCopy(const char *locin, const char *locout, u8 options){ f_chmod(locout, in_info.fattrib, 0x3A); //f_stat(locin, &in_info); //somehow stops fatfs from being weird - return newErrCode(0); + return err; } \ No newline at end of file diff --git a/source/fs/fsutils.c b/source/fs/fsutils.c index a54ae25..dc9d8b1 100644 --- a/source/fs/fsutils.c +++ b/source/fs/fsutils.c @@ -42,4 +42,13 @@ char *GetFileAttribs(FSEntry_t entry){ char *ret = CpyStr("RHSVDA"); MaskIn(ret, entry.optionUnion, '-'); return ret; -} \ No newline at end of file +} + +bool FileExists(char* path){ + FRESULT fr; + FILINFO fno; + + fr = f_stat(path, &fno); + + return !(fr & FR_NO_FILE); +} diff --git a/source/fs/fsutils.h b/source/fs/fsutils.h index 1824550..094a146 100644 --- a/source/fs/fsutils.h +++ b/source/fs/fsutils.h @@ -5,4 +5,5 @@ u64 GetFileSize(char *path); char *EscapeFolder(const char *current); char *CombinePaths(const char *current, const char *add); -char *GetFileAttribs(FSEntry_t entry); \ No newline at end of file +char *GetFileAttribs(FSEntry_t entry); +bool FileExists(char* path); \ No newline at end of file diff --git a/source/fs/menus/explorer.c b/source/fs/menus/explorer.c index 94951cc..e57279c 100644 --- a/source/fs/menus/explorer.c +++ b/source/fs/menus/explorer.c @@ -30,13 +30,7 @@ MenuEntry_t MakeMenuOutFSEntry(FSEntry_t entry){ return out; } -void clearFileVector(Vector_t *v){ - vecPDefArray(FSEntry_t*, entries, v); - for (int i = 0; i < v->count; i++) - free(entries[i].name); - - free(v->data); -} + void FileExplorer(char *path){ char *storedPath = CpyStr(path); @@ -48,8 +42,15 @@ void FileExplorer(char *path){ gfx_clearscreen(); gfx_printf("Loading...\r"); - //gfx_printf(" "); - Vector_t fileVec = ReadFolder(storedPath); + + int readRes = 0; + Vector_t fileVec = ReadFolder(storedPath, &readRes); + if (readRes){ + clearFileVector(&fileVec); + DrawError(newErrCode(readRes)); + return; + } + vecDefArray(FSEntry_t*, fsEntries, fileVec); topEntries[0].name = storedPath; diff --git a/source/fs/menus/filemenu.c b/source/fs/menus/filemenu.c index 7479a99..cf8a6c2 100644 --- a/source/fs/menus/filemenu.c +++ b/source/fs/menus/filemenu.c @@ -10,6 +10,7 @@ #include "../../hid/hid.h" #include #include "../../utils/utils.h" +#include "../../keys/nca.h" MenuEntry_t FileMenuEntries[] = { // Still have to think up the options @@ -50,17 +51,12 @@ void MoveClipboard(char *path, FSEntry_t entry){ free(thing); } -MenuEntry_t DeleteEntries[] = { - {.optionUnion = COLORTORGB(COLOR_YELLOW), .name = "No"}, - {.R = 255, .name = "Yes"} -}; - void DeleteFile(char *path, FSEntry_t entry){ gfx_con_setpos(384 + 16, 200 + 16 + 10 * 16); SETCOLOR(COLOR_RED, COLOR_DARKGREY); gfx_printf("Are you sure? "); - if (!MakeHorizontalMenu(DeleteEntries, 2, 3, COLOR_DARKGREY)) + if (!MakeYesNoHorzMenu(3, COLOR_DARKGREY)) return; char *thing = CombinePaths(path, entry.name); diff --git a/source/fs/readers/folderReader.c b/source/fs/readers/folderReader.c index b6096e0..c1e6e79 100644 --- a/source/fs/readers/folderReader.c +++ b/source/fs/readers/folderReader.c @@ -1,19 +1,27 @@ #include "folderReader.h" #include #include "../../utils/utils.h" +#include -Vector_t /* of type FSEntry_t */ ReadFolder(char *path){ +void clearFileVector(Vector_t *v){ + vecPDefArray(FSEntry_t*, entries, v); + for (int i = 0; i < v->count; i++) + free(entries[i].name); + + free(v->data); +} + +Vector_t /* of type FSEntry_t */ ReadFolder(char *path, int *res){ Vector_t out = newVec(sizeof(FSEntry_t), 16); // we may want to prealloc with the same size as the folder DIR dir; FILINFO fno; - int res; - if ((res = f_opendir(&dir, path))){ + if ((*res = f_opendir(&dir, path))){ // Err! return out; } - while (!f_readdir(&dir, &fno) && fno.fname[0]) { + while (!(*res = f_readdir(&dir, &fno)) && fno.fname[0]) { FSEntry_t newEntry = {.optionUnion = fno.fattrib, .name = CpyStr(fno.fname)}; if (!newEntry.isDir){ diff --git a/source/fs/readers/folderReader.h b/source/fs/readers/folderReader.h index ff722cc..b875757 100644 --- a/source/fs/readers/folderReader.h +++ b/source/fs/readers/folderReader.h @@ -3,4 +3,5 @@ #include "../../utils/vector.h" #include "../fstypes.h" -Vector_t /* of type FSEntry_t */ ReadFolder(char *path); \ No newline at end of file +void clearFileVector(Vector_t *v); +Vector_t /* of type FSEntry_t */ ReadFolder(char *path, int *res); \ No newline at end of file diff --git a/source/gfx/gfxutils.c b/source/gfx/gfxutils.c index 9347a43..5227f14 100644 --- a/source/gfx/gfxutils.c +++ b/source/gfx/gfxutils.c @@ -19,6 +19,15 @@ void gfx_clearscreen(){ RESETCOLOR; } +MenuEntry_t YesNoEntries[] = { + {.optionUnion = COLORTORGB(COLOR_YELLOW), .name = "No"}, + {.R = 255, .name = "Yes"} +}; + +int MakeYesNoHorzMenu(int spacesBetween, u32 bg){ + return MakeHorizontalMenu(YesNoEntries, ARR_LEN(YesNoEntries), spacesBetween, bg); +} + int MakeHorizontalMenu(MenuEntry_t *entries, int len, int spacesBetween, u32 bg){ u32 initialX = 0, initialY = 0; u32 highlight = 0; diff --git a/source/gfx/gfxutils.h b/source/gfx/gfxutils.h index 66b20a8..ca448b7 100644 --- a/source/gfx/gfxutils.h +++ b/source/gfx/gfxutils.h @@ -14,4 +14,5 @@ #define RGBUnionToU32(optionUnion) (optionUnion | 0xFF000000) void gfx_clearscreen(); -int MakeHorizontalMenu(MenuEntry_t *entries, int len, int spacesBetween, u32 bg); \ No newline at end of file +int MakeHorizontalMenu(MenuEntry_t *entries, int len, int spacesBetween, u32 bg); +int MakeYesNoHorzMenu(int spacesBetween, u32 bg); \ No newline at end of file diff --git a/source/keys/nca.c b/source/keys/nca.c new file mode 100644 index 0000000..3123a0c --- /dev/null +++ b/source/keys/nca.c @@ -0,0 +1,31 @@ +#include "nca.h" +#include "keys.h" +#include +#include +#include + +// Thanks switchbrew https://switchbrew.org/wiki/NCA_Format +// This function is hacky, should change it but am lazy +int GetNcaType(char *path){ + FIL fp; + u32 read_bytes = 0; + + if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING)) + return -1; + + u8 *dec_header = (u8*)malloc(0x400); + + if (f_lseek(&fp, 0x200) || f_read(&fp, dec_header, 32, &read_bytes) || read_bytes != 32){ + f_close(&fp); + free(dec_header); + return -1; + } + + se_aes_xts_crypt(7,6,0,1, dec_header + 0x200, dec_header, 32, 1); + + u8 ContentType = dec_header[0x205]; + + f_close(&fp); + free(dec_header); + return ContentType; +} \ No newline at end of file diff --git a/source/keys/nca.h b/source/keys/nca.h new file mode 100644 index 0000000..133c389 --- /dev/null +++ b/source/keys/nca.h @@ -0,0 +1,12 @@ +#pragma once + +enum NcaTypes { + Porgram = 0, + Meta, + Control, + Manual, + Data, + PublicData +}; + +int GetNcaType(char *path); \ No newline at end of file diff --git a/source/main.c b/source/main.c index 9ecbe78..359455c 100644 --- a/source/main.c +++ b/source/main.c @@ -271,6 +271,7 @@ void ipl_main() emu_cfg.enabled = !h_cfg.emummc_force_disable; h_cfg.emummc_force_disable = 1; + TConf.pkg1ID = "Unk"; hidInit(); @@ -290,7 +291,7 @@ void ipl_main() int res = -1; - if (DumpKeys() || btn_read() & BTN_VOL_DOWN) + if (btn_read() & BTN_VOL_DOWN || DumpKeys()) res = GetKeysFromFile("sd:/switch/prod.keys"); TConf.keysDumped = (res > 0) ? 0 : 1; diff --git a/source/storage/gptmenu.c b/source/storage/gptmenu.c index 78295cd..0e0cf60 100644 --- a/source/storage/gptmenu.c +++ b/source/storage/gptmenu.c @@ -82,6 +82,7 @@ void GptMenu(u8 MMCType){ else { if (TConf.curExplorerLoc > LOC_SD) ResetCopyParams(); + TConf.curExplorerLoc = LOC_EMMC; FileExplorer("bis:/"); } diff --git a/source/storage/mountmanager.c b/source/storage/mountmanager.c index e977e98..3c3d2a5 100644 --- a/source/storage/mountmanager.c +++ b/source/storage/mountmanager.c @@ -18,6 +18,10 @@ void SetKeySlots(){ se_aes_key_set(3, dumpedKeys.bis_key[1] + AES_128_KEY_SIZE, AES_128_KEY_SIZE); se_aes_key_set(4, dumpedKeys.bis_key[2], AES_128_KEY_SIZE); se_aes_key_set(5, dumpedKeys.bis_key[2] + AES_128_KEY_SIZE, AES_128_KEY_SIZE); + + // Not for bis but whatever + se_aes_key_set(6, dumpedKeys.header_key + 0x00, 0x10); + se_aes_key_set(7, dumpedKeys.header_key + 0x10, 0x10); } } diff --git a/source/tegraexplorer/mainmenu.c b/source/tegraexplorer/mainmenu.c index 358332c..fc21878 100644 --- a/source/tegraexplorer/mainmenu.c +++ b/source/tegraexplorer/mainmenu.c @@ -20,6 +20,7 @@ MenuEntry_t mainMenuEntries[] = { {.optionUnion = COLORTORGB(COLOR_YELLOW), .name = "Emummc"}, {.B = 255, .G = 255, .name = "Test Controllers"}, {.R = 255, .name = "Cause an exception"}, + {.optionUnion = COLORTORGB(COLOR_BLUE), .name = "Dump Firmware"}, {.optionUnion = COLORTORGB(COLOR_ORANGE), .name = "View dumped keys"}, {.R = 255, .name = "Reboot to payload"} }; @@ -73,6 +74,7 @@ menuPaths mainMenuPaths[] = { HandleEMUMMC, TestControllers, CrashTE, + DumpSysFw, ViewKeys, RebootToPayload }; diff --git a/source/tegraexplorer/tools.c b/source/tegraexplorer/tools.c index 0965c49..1edf682 100644 --- a/source/tegraexplorer/tools.c +++ b/source/tegraexplorer/tools.c @@ -3,6 +3,20 @@ #include "../gfx/gfxutils.h" #include "../gfx/menu.h" #include "../hid/hid.h" +#include +#include "../keys/keys.h" +#include "../keys/nca.h" +#include +#include "../fs/fsutils.h" +#include +#include "../storage/mountmanager.h" +#include "../err.h" +#include +#include +#include "../tegraexplorer/tconf.h" +#include "../fs/readers/folderReader.h" +#include +#include "../fs/fscopy.h" void TestControllers(){ gfx_clearscreen(); @@ -26,4 +40,101 @@ extern int launch_payload(char *path); void RebootToPayload(){ launch_payload("atmosphere/reboot_payload.bin"); +} + +void DumpSysFw(){ + char sysPath[25 + 36 + 3 + 1]; // 24 for "bis:/Contents/registered", 36 for ncaName.nca, 3 for /00, and 1 to make sure :) + char *baseSdPath; + + u32 timer = get_tmr_s(); + + if (!sd_mount()) + return; + + if (connectMMC(MMC_CONN_EMMC)) + return; + + if (!TConf.keysDumped) + return; + + ErrCode_t err = mountMMCPart("SYSTEM"); + if (err.err){ + DrawError(err); + return; + } + + baseSdPath = malloc(36 + 16); + sprintf(baseSdPath, "sd:/tegraexplorer/Firmware/%d (%s)", TConf.pkg1ver, TConf.pkg1ID); + int baseSdPathLen = strlen(baseSdPath); + + f_mkdir("sd:/tegraexplorer"); + f_mkdir("sd:/tegraexplorer/Firmware"); + + gfx_clearscreen(); + + gfx_printf("Pkg1 id: '%s', kb %d\n", TConf.pkg1ID, TConf.pkg1ver); + if (FileExists(baseSdPath)){ + SETCOLOR(COLOR_ORANGE, COLOR_DEFAULT); + gfx_printf("Destination already exists. Replace? "); + if (!MakeYesNoHorzMenu(3, COLOR_DEFAULT)){ + free(baseSdPath); + return; + } + RESETCOLOR; + gfx_printf("\nReminder! delete the folder. i can't delete recursively yet"); + gfx_putc('\n'); + } + + f_mkdir(baseSdPath); + + gfx_printf("Out: %s\nReading entries...\n", baseSdPath); + int readRes = 0; + Vector_t fileVec = ReadFolder("bis:/Contents/registered", &readRes); + if (readRes){ + DrawError(newErrCode(readRes)); + free(baseSdPath); + return; + } + + gfx_printf("Starting dump...\n"); + SETCOLOR(COLOR_GREEN, COLOR_DEFAULT); + + int res = 0; + int total = 1; + vecDefArray(FSEntry_t*, fsEntries, fileVec); + for (int i = 0; i < fileVec.count; i++){ + sprintf(sysPath, (fsEntries[i].isDir) ? "%s/%s/00" : "%s/%s", "bis:/Contents/registered", fsEntries[i].name); + int contentType = GetNcaType(sysPath); + + if (contentType < 0){ + res = 1; + break; + } + + char *sdPath = malloc(baseSdPathLen + 45); + sprintf(sdPath, "%s/%s", baseSdPath, fsEntries[i].name); + if (contentType == Meta) + memcpy(sdPath + strlen(sdPath) - 4, ".cnmt.nca", 10); + + gfx_printf("[%3d / %3d] %s\r", total, fileVec.count, fsEntries[i].name); + total++; + err = FileCopy(sysPath, sdPath, 0); + free(sdPath); + if (err.err){ + DrawError(err); + res = 1; + break; + } + } + clearFileVector(&fileVec); + + RESETCOLOR; + + if (res){ + gfx_printf("\nDump failed...\n"); + } + + gfx_printf("\n\nDone! Time taken: %ds\nPress any key to exit", get_tmr_s() - timer); + free(baseSdPath); + hidWait(); } \ No newline at end of file diff --git a/source/tegraexplorer/tools.h b/source/tegraexplorer/tools.h index 3763ef1..49ce2bf 100644 --- a/source/tegraexplorer/tools.h +++ b/source/tegraexplorer/tools.h @@ -1,4 +1,5 @@ #pragma once void RebootToPayload(); -void TestControllers(); \ No newline at end of file +void TestControllers(); +void DumpSysFw(); \ No newline at end of file