From a6fa7042d5689a593a23ce3217b9653330157c5a Mon Sep 17 00:00:00 2001 From: d0k3 Date: Wed, 17 May 2017 01:16:24 +0200 Subject: [PATCH] Allow dumping CXIs from TMDs --- source/common/common.h | 2 +- source/fs/filetype.h | 1 + source/game/gameutil.c | 23 ++++++++++++++++++++++- source/game/gameutil.h | 1 + source/godmode.c | 24 +++++++++++++++--------- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/source/common/common.h b/source/common/common.h index a077195..7eca95a 100644 --- a/source/common/common.h +++ b/source/common/common.h @@ -49,7 +49,7 @@ #endif // GodMode9 version -#define VERSION "1.1.5" +#define VERSION "1.1.6" // Maximum payload size (arbitrary value!) #define SELF_MAX_SIZE (320 * 1024) // 320kB diff --git a/source/fs/filetype.h b/source/fs/filetype.h index ae08999..3ef1bf1 100644 --- a/source/fs/filetype.h +++ b/source/fs/filetype.h @@ -36,6 +36,7 @@ #define FYTPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|BIN_KEYDB)) #define FTYPE_CIABUILD(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD)) #define FTYPE_CIABUILD_L(tp) (FTYPE_CIABUILD(tp) && (tp&(GAME_TMD))) +#define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD)) #define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB)) #define FTYPE_KEYBUILD(tp) (tp&(BIN_KEYDB|BIN_LEGKEY)) #define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS)) diff --git a/source/game/gameutil.c b/source/game/gameutil.c index 9782df5..eb3d25d 100644 --- a/source/game/gameutil.c +++ b/source/game/gameutil.c @@ -755,7 +755,7 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 u32 ret = 0; if (!ShowProgress(offset, fsize, dest)) ret = 1; - if (mode & (GAME_NCCH|GAME_NCSD|GAME_BOSS|SYS_FIRM)) { // for NCCH / NCSD / BOSS / FIRM files + if (mode & (GAME_NCCH|GAME_NCSD|GAME_BOSS|SYS_FIRM|GAME_NDS)) { // for NCCH / NCSD / BOSS / FIRM files for (u64 i = 0; (i < size) && (ret == 0); i += MAIN_BUFFER_SIZE) { u32 read_bytes = min(MAIN_BUFFER_SIZE, (size - i)); UINT bytes_read, bytes_written; @@ -1375,6 +1375,27 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit) { return ret; } +// this has very limited uses right now +u32 DumpCxiSrlFromTmdFile(const char* path) { + u32 filetype = 0; + char path_cxi[256]; + char dest[256]; + + // prepare output name + snprintf(dest, 256, OUTPUT_PATH "/"); + char* dname = dest + strnlen(dest, 256); + + // get path to CXI/SRL and decrypt (if encrypted) + if ((strncmp(path + 1, ":/title/", 8) != 0) || + (GetTmdContentPath(path_cxi, path) != 0) || + (!((filetype = IdentifyFileType(path_cxi)) & (GAME_NCCH|GAME_NDS))) || + (GetGoodName(dname, path_cxi, false) != 0) || + (CryptNcchNcsdBossFirmFile(path_cxi, dest, filetype, CRYPTO_DECRYPT, 0, 0, NULL, NULL) != 0)) + return 1; + + return 0; +} + u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) { u32 filetype = IdentifyFileType(path); diff --git a/source/game/gameutil.h b/source/game/gameutil.h index 564c7bb..0d233e0 100644 --- a/source/game/gameutil.h +++ b/source/game/gameutil.h @@ -6,6 +6,7 @@ u32 VerifyGameFile(const char* path); u32 CheckEncryptedGameFile(const char* path); u32 CryptGameFile(const char* path, bool inplace, bool encrypt); u32 BuildCiaFromGameFile(const char* path, bool force_legit); +u32 DumpCxiSrlFromTmdFile(const char* path); u32 ShowGameFileTitleInfo(const char* path); u32 BuildNcchInfoXorpads(const char* destdir, const char* path); u32 CheckHealthAndSafetyInject(const char* hsdrv); diff --git a/source/godmode.c b/source/godmode.c index 1d8dc86..e1db100 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -668,6 +668,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur bool cryptable_inplace = ((encryptable||decryptable) && !in_output_path && (drvtype & DRV_FAT)); bool cia_buildable = (FTYPE_CIABUILD(filetype)); bool cia_buildable_legit = (FTYPE_CIABUILD_L(filetype)); + bool cxi_dumpable = (FTYPE_CXIDUMP(filetype)); bool tik_buildable = (FTYPE_TIKBUILD(filetype)) && !in_output_path; bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path; bool titleinfo = (FTYPE_TITLEINFO(filetype)); @@ -818,6 +819,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur int encrypt = (encryptable) ? ++n_opt : -1; int cia_build = (cia_buildable) ? ++n_opt : -1; int cia_build_legit = (cia_buildable_legit) ? ++n_opt : -1; + int cxi_dump = (cxi_dumpable) ? ++n_opt : -1; int tik_build_enc = (tik_buildable) ? ++n_opt : -1; int tik_build_dec = (tik_buildable) ? ++n_opt : -1; int key_build = (key_buildable) ? ++n_opt : -1; @@ -835,6 +837,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur if (encrypt > 0) optionstr[encrypt-1] = (cryptable_inplace) ? "Encrypt file (...)" : "Encrypt file (" OUTPUT_PATH ")"; if (cia_build > 0) optionstr[cia_build-1] = (cia_build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)"; if (cia_build_legit > 0) optionstr[cia_build_legit-1] = "Build CIA (legit)"; + if (cxi_dump > 0) optionstr[cxi_dump-1] = "Dump CXI/NDS file"; if (tik_build_enc > 0) optionstr[tik_build_enc-1] = "Build " TIKDB_NAME_ENC; if (tik_build_dec > 0) optionstr[tik_build_dec-1] = "Build " TIKDB_NAME_DEC; if (key_build > 0) optionstr[key_build-1] = "Build " KEYDB_NAME; @@ -966,7 +969,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur else ShowPrompt(false, "%s\nEncrypted to %s", pathstr, OUTPUT_PATH); } return 0; - } else if ((user_select == cia_build) || (user_select == cia_build_legit)) { // -> build CIA + } else if ((user_select == cia_build) || (user_select == cia_build_legit) || (user_select == cxi_dump)) { // -> build CIA / dump CXI + char* type = (user_select == cxi_dump) ? "CXI" : "CIA"; bool force_legit = (user_select == cia_build_legit); if ((n_marked > 1) && ShowPrompt(true, "Try to process all %lu selected files?", n_marked)) { u32 n_success = 0; @@ -980,24 +984,26 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur continue; } current_dir->entry[i].marked = false; - if (BuildCiaFromGameFile(path, force_legit) == 0) n_success++; + if (((user_select != cxi_dump) && (BuildCiaFromGameFile(path, force_legit) == 0)) || + ((user_select == cxi_dump) && (DumpCxiSrlFromTmdFile(path) == 0))) n_success++; else { // on failure: set *cursor on failed title, break; TruncateString(pathstr, path, 32, 8); - ShowPrompt(false, "%s\nBuild CIA failed", pathstr); + ShowPrompt(false, "%s\nBuild %s failed", pathstr, type); *cursor = i; break; } } - if (n_other) ShowPrompt(false, "%lu/%lu CIAs built ok\n%lu/%lu not of same type", - n_success, n_marked, n_other, n_marked); - else ShowPrompt(false, "%lu/%lu CIAs built ok", n_success, n_marked); + if (n_other) ShowPrompt(false, "%lu/%lu %ss built ok\n%lu/%lu not of same type", + n_success, n_marked, type, n_other, n_marked); + else ShowPrompt(false, "%lu/%lu %ss built ok", n_success, n_marked, type); if (n_success) ShowPrompt(false, "%lu files written to %s", n_success, OUTPUT_PATH); if (n_success && in_output_path) GetDirContents(current_dir, current_path); } else { - if (BuildCiaFromGameFile(curr_entry->path, force_legit) == 0) { - ShowPrompt(false, "%s\nCIA built to %s", pathstr, OUTPUT_PATH); + if (((user_select != cxi_dump) && (BuildCiaFromGameFile(curr_entry->path, force_legit) == 0)) || + ((user_select == cxi_dump) && (DumpCxiSrlFromTmdFile(curr_entry->path) == 0))) { + ShowPrompt(false, "%s\n%s built to %s", pathstr, type, OUTPUT_PATH); if (in_output_path) GetDirContents(current_dir, current_path); - } else ShowPrompt(false, "%s\nCIA build failed", pathstr); + } else ShowPrompt(false, "%s\n%s build failed", pathstr, type); } return 0; } else if (user_select == verify) { // -> verify game / nand file