mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Added ability to dump tickets in title manager
This commit is contained in:
parent
2cd6acb31e
commit
8fa85437dd
@ -54,6 +54,7 @@
|
|||||||
#define FTYPE_CIABUILD_L(tp) (tp&(GAME_TMD|GAME_CDNTMD|GAME_TIE|GAME_TAD))
|
#define FTYPE_CIABUILD_L(tp) (tp&(GAME_TMD|GAME_CDNTMD|GAME_TIE|GAME_TAD))
|
||||||
#define FTYPE_CIAINSTALL(tp) ((tp&(GAME_NCSD|GAME_NCCH|GAME_CIA|GAME_CDNTMD|GAME_TWLTMD)) || ((tp&GAME_NDS)&&(tp&(FLAG_DSIW))))
|
#define FTYPE_CIAINSTALL(tp) ((tp&(GAME_NCSD|GAME_NCCH|GAME_CIA|GAME_CDNTMD|GAME_TWLTMD)) || ((tp&GAME_NDS)&&(tp&(FLAG_DSIW))))
|
||||||
#define FTYPE_TIKINSTALL(tp) (tp&(GAME_TICKET))
|
#define FTYPE_TIKINSTALL(tp) (tp&(GAME_TICKET))
|
||||||
|
#define FTYPE_TIKDUMP(tp) (tp&(GAME_TIE))
|
||||||
#define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD))
|
#define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD))
|
||||||
#define FTYPE_UNINSTALL(tp) (tp&(GAME_TIE))
|
#define FTYPE_UNINSTALL(tp) (tp&(GAME_TIE))
|
||||||
#define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB))
|
#define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB))
|
||||||
|
@ -1095,6 +1095,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
bool cia_installable = (FTYPE_CIAINSTALL(filetype)) && !(drvtype & DRV_CTRNAND) &&
|
bool cia_installable = (FTYPE_CIAINSTALL(filetype)) && !(drvtype & DRV_CTRNAND) &&
|
||||||
!(drvtype & DRV_TWLNAND) && !(drvtype & DRV_ALIAS) && !(drvtype & DRV_IMAGE);
|
!(drvtype & DRV_TWLNAND) && !(drvtype & DRV_ALIAS) && !(drvtype & DRV_IMAGE);
|
||||||
bool tik_installable = (FTYPE_TIKINSTALL(filetype));
|
bool tik_installable = (FTYPE_TIKINSTALL(filetype));
|
||||||
|
bool tik_dumpable = (FTYPE_TIKDUMP(filetype));
|
||||||
bool uninstallable = (FTYPE_UNINSTALL(filetype));
|
bool uninstallable = (FTYPE_UNINSTALL(filetype));
|
||||||
bool cxi_dumpable = (FTYPE_CXIDUMP(filetype));
|
bool cxi_dumpable = (FTYPE_CXIDUMP(filetype));
|
||||||
bool tik_buildable = (FTYPE_TIKBUILD(filetype)) && !in_output_path;
|
bool tik_buildable = (FTYPE_TIKBUILD(filetype)) && !in_output_path;
|
||||||
@ -1138,7 +1139,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || trimable || transferable ||
|
cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || trimable || transferable ||
|
||||||
hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable ||
|
hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable ||
|
||||||
keyinstallable || bootable || scriptable || fontable || viewable || installable || agbexportable ||
|
keyinstallable || bootable || scriptable || fontable || viewable || installable || agbexportable ||
|
||||||
agbimportable || cia_installable || tik_installable;
|
agbimportable || cia_installable || tik_installable || tik_dumpable;
|
||||||
|
|
||||||
char pathstr[32+1];
|
char pathstr[32+1];
|
||||||
TruncateString(pathstr, file_path, 32, 8);
|
TruncateString(pathstr, file_path, 32, 8);
|
||||||
@ -1338,6 +1339,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
int cxi_dump = (cxi_dumpable) ? ++n_opt : -1;
|
int cxi_dump = (cxi_dumpable) ? ++n_opt : -1;
|
||||||
int cia_install = (cia_installable) ? ++n_opt : -1;
|
int cia_install = (cia_installable) ? ++n_opt : -1;
|
||||||
int tik_install = (tik_installable) ? ++n_opt : -1;
|
int tik_install = (tik_installable) ? ++n_opt : -1;
|
||||||
|
int tik_dump = (tik_dumpable) ? ++n_opt : -1;
|
||||||
int uninstall = (uninstallable) ? ++n_opt : -1;
|
int uninstall = (uninstallable) ? ++n_opt : -1;
|
||||||
int tik_build_enc = (tik_buildable) ? ++n_opt : -1;
|
int tik_build_enc = (tik_buildable) ? ++n_opt : -1;
|
||||||
int tik_build_dec = (tik_buildable) ? ++n_opt : -1;
|
int tik_build_dec = (tik_buildable) ? ++n_opt : -1;
|
||||||
@ -1373,6 +1375,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
if (cxi_dump > 0) optionstr[cxi_dump-1] = "Dump CXI/NDS file";
|
if (cxi_dump > 0) optionstr[cxi_dump-1] = "Dump CXI/NDS file";
|
||||||
if (cia_install > 0) optionstr[cia_install-1] = "Install game image";
|
if (cia_install > 0) optionstr[cia_install-1] = "Install game image";
|
||||||
if (tik_install > 0) optionstr[tik_install-1] = "Install ticket";
|
if (tik_install > 0) optionstr[tik_install-1] = "Install ticket";
|
||||||
|
if (tik_dump > 0) optionstr[tik_dump-1] = "Dump ticket file";
|
||||||
if (uninstall > 0) optionstr[uninstall-1] = "Uninstall title";
|
if (uninstall > 0) optionstr[uninstall-1] = "Uninstall title";
|
||||||
if (tik_build_enc > 0) optionstr[tik_build_enc-1] = "Build " TIKDB_NAME_ENC;
|
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 (tik_build_dec > 0) optionstr[tik_build_dec-1] = "Build " TIKDB_NAME_DEC;
|
||||||
@ -1712,7 +1715,42 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if ((user_select == tik_build_enc) || (user_select == tik_build_dec)) { // -> (Re)Build titlekey database
|
else if (user_select == tik_dump) { // dump ticket file
|
||||||
|
if ((n_marked > 1) && ShowPrompt(true, "Dump for all %lu selected files?", n_marked)) {
|
||||||
|
u32 n_success = 0;
|
||||||
|
u32 n_legit = 0;
|
||||||
|
bool force_legit = true;
|
||||||
|
for (u32 n_processed = 0;; n_processed = 0) {
|
||||||
|
for (u32 i = 0; i < current_dir->n_entries; i++) {
|
||||||
|
const char* path = current_dir->entry[i].path;
|
||||||
|
if (!current_dir->entry[i].marked) continue;
|
||||||
|
if (!ShowProgress(n_processed++, n_marked, path)) break;
|
||||||
|
DrawDirContents(current_dir, (*cursor = i), scroll);
|
||||||
|
if (DumpTicketForGameFile(path, force_legit) == 0) n_success++;
|
||||||
|
else if (IdentifyFileType(path) & filetype & TYPE_BASE) continue;
|
||||||
|
if (force_legit) n_legit++;
|
||||||
|
current_dir->entry[i].marked = false;
|
||||||
|
}
|
||||||
|
if (force_legit && (n_success != n_marked))
|
||||||
|
if (!ShowPrompt(true, "%lu/%lu legit tickets dumped.\n \nAttempt to dump all tickets?",
|
||||||
|
n_legit, n_marked)) break;
|
||||||
|
if (!force_legit) break;
|
||||||
|
force_legit = false;
|
||||||
|
}
|
||||||
|
ShowPrompt(false, "%lu/%lu tickets dumped to %s",
|
||||||
|
n_success, n_marked, OUTPUT_PATH);
|
||||||
|
} else {
|
||||||
|
if (DumpTicketForGameFile(file_path, true) == 0) {
|
||||||
|
ShowPrompt(false, "%s\nTicket dumped to %s", pathstr, OUTPUT_PATH);
|
||||||
|
} else if (ShowPrompt(false, "%s\nLegit ticket not found.\n \nDump anyways?", pathstr)) {
|
||||||
|
if (DumpTicketForGameFile(file_path, false) == 0)
|
||||||
|
ShowPrompt(false, "%s\nTicket dumped to %s", pathstr, OUTPUT_PATH);
|
||||||
|
else ShowPrompt(false, "%s\nDump ticket failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if ((user_select == tik_build_enc) || (user_select == tik_build_dec)) { // -> (re)build titlekey database
|
||||||
bool dec = (user_select == tik_build_dec);
|
bool dec = (user_select == tik_build_dec);
|
||||||
const char* path_out = (dec) ? OUTPUT_PATH "/" TIKDB_NAME_DEC : OUTPUT_PATH "/" TIKDB_NAME_ENC;
|
const char* path_out = (dec) ? OUTPUT_PATH "/" TIKDB_NAME_DEC : OUTPUT_PATH "/" TIKDB_NAME_ENC;
|
||||||
if (BuildTitleKeyInfo(NULL, dec, false) != 0) return 1; // init database
|
if (BuildTitleKeyInfo(NULL, dec, false) != 0) return 1; // init database
|
||||||
|
@ -295,6 +295,35 @@ u32 LoadCdnTicketFile(Ticket** ticket, const char* path_cnt) {
|
|||||||
return LoadTicketFile(ticket, path_cetk);
|
return LoadTicketFile(ticket, path_cetk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 LoadTicketForTitleId(Ticket** ticket, const u64 title_id) {
|
||||||
|
u8 tid[8];
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
tid[7-i] = (title_id >> (i*8)) & 0xFF;
|
||||||
|
|
||||||
|
// ensure remounting the old mount path
|
||||||
|
char path_store[256] = { 0 };
|
||||||
|
char* path_bak = NULL;
|
||||||
|
strncpy(path_store, GetMountPath(), 256);
|
||||||
|
if (*path_store) path_bak = path_store;
|
||||||
|
|
||||||
|
// path to ticket.db
|
||||||
|
char path_ticketdb[32];
|
||||||
|
char* drv = path_store;
|
||||||
|
snprintf(path_ticketdb, 32, "%2.2s/dbs/ticket.db",
|
||||||
|
((*drv == 'A') || (*drv == '2')) ? "1:" :
|
||||||
|
((*drv == 'B') || (*drv == '5')) ? "4:" : drv);
|
||||||
|
|
||||||
|
// load ticket
|
||||||
|
if (!InitImgFS(path_ticketdb) ||
|
||||||
|
((ReadTicketFromDB(PART_PATH, tid, ticket)) != 0))
|
||||||
|
*ticket = NULL;
|
||||||
|
|
||||||
|
// remount old path
|
||||||
|
InitImgFS(path_bak);
|
||||||
|
|
||||||
|
return (*ticket) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
u32 GetTmdContentPath(char* path_content, const char* path_tmd) {
|
u32 GetTmdContentPath(char* path_content, const char* path_tmd) {
|
||||||
// path_content should be 256 bytes in size!
|
// path_content should be 256 bytes in size!
|
||||||
|
|
||||||
@ -2699,6 +2728,9 @@ u64 GetGameFileTitleId(const char* path) {
|
|||||||
TwlHeader twl;
|
TwlHeader twl;
|
||||||
if ((fvx_qread(path, &twl, 0, sizeof(TwlHeader), NULL) == FR_OK) && (twl.unit_code & 0x02))
|
if ((fvx_qread(path, &twl, 0, sizeof(TwlHeader), NULL) == FR_OK) && (twl.unit_code & 0x02))
|
||||||
tid64 = twl.title_id;
|
tid64 = twl.title_id;
|
||||||
|
} else if (filetype & GAME_TIE) {
|
||||||
|
if ((*path == 'T') && (sscanf(path, "T:/%016llx", &tid64) != 1))
|
||||||
|
tid64 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tid64 & 0xFFFFFF0000000000ull) == 0x0003000000000000ull)
|
if ((tid64 & 0xFFFFFF0000000000ull) == 0x0003000000000000ull)
|
||||||
@ -2890,6 +2922,42 @@ u32 InstallTicketFile(const char* path, bool to_emunand) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 DumpTicketForGameFile(const char* path, bool force_legit) {
|
||||||
|
u64 tid64 = GetGameFileTitleId(path);
|
||||||
|
if (!tid64) return 1;
|
||||||
|
|
||||||
|
Ticket* ticket;
|
||||||
|
if (LoadTicketForTitleId(&ticket, tid64) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if ((ValidateTicket(ticket) != 0) ||
|
||||||
|
(force_legit && (ValidateTicketSignature(ticket) != 0))) {
|
||||||
|
free(ticket);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build output name
|
||||||
|
char dest[256];
|
||||||
|
snprintf(dest, 256, OUTPUT_PATH "/");
|
||||||
|
char* dname = dest + strnlen(dest, 256);
|
||||||
|
if (GetGoodName(dname, path, false) != 0)
|
||||||
|
snprintf(dest, 256, "%s/%016llX", OUTPUT_PATH, tid64);
|
||||||
|
|
||||||
|
// replace extension
|
||||||
|
char* dot = strrchr(dest, '.');
|
||||||
|
if (!dot || (dot < strrchr(dest, '/')))
|
||||||
|
dot = dest + strnlen(dest, 256);
|
||||||
|
snprintf(dot, 16, ".%s", force_legit ? "legit.tik" : "tik");
|
||||||
|
|
||||||
|
// dump ticket
|
||||||
|
if (!CheckWritePermissions(dest)) return 1;
|
||||||
|
f_unlink(dest); // remove the file if it already exists
|
||||||
|
fvx_qwrite(dest, ticket, 0, GetTicketSize(ticket), NULL);
|
||||||
|
|
||||||
|
free(ticket);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// this has very limited uses right now
|
// this has very limited uses right now
|
||||||
u32 DumpCxiSrlFromTmdFile(const char* path) {
|
u32 DumpCxiSrlFromTmdFile(const char* path) {
|
||||||
u64 filetype = 0;
|
u64 filetype = 0;
|
||||||
@ -3294,25 +3362,10 @@ u32 ShowCiaTieCheckerInfo(const char* path) {
|
|||||||
tmd = NULL;
|
tmd = NULL;
|
||||||
} else content_found = content_count = getbe16(tmd->content_count);
|
} else content_found = content_count = getbe16(tmd->content_count);
|
||||||
|
|
||||||
// ticket needs some preparation
|
|
||||||
// ensure remounting the old mount path
|
|
||||||
char path_store[256] = { 0 };
|
|
||||||
char* path_bak = NULL;
|
|
||||||
strncpy(path_store, GetMountPath(), 256);
|
|
||||||
if (*path_store) path_bak = path_store;
|
|
||||||
|
|
||||||
char path_ticketdb[32];
|
|
||||||
char* drv = path_store;
|
|
||||||
snprintf(path_ticketdb, 32, "%2.2s/dbs/ticket.db",
|
|
||||||
((*drv == 'A') || (*drv == '2')) ? "1:" :
|
|
||||||
((*drv == 'B') || (*drv == '5')) ? "4:" : drv);
|
|
||||||
|
|
||||||
// load ticket
|
// load ticket
|
||||||
if (!InitImgFS(path_ticketdb) ||
|
u64 tid64 = tmd ? getbe64(tmd->title_id) : 0;
|
||||||
((ReadTicketFromDB(PART_PATH, tmd->title_id, &ticket)) != 0))
|
if (LoadTicketForTitleId(&ticket, tid64) != 0)
|
||||||
ticket = NULL;
|
ticket = NULL;
|
||||||
|
|
||||||
InitImgFS(path_bak);
|
|
||||||
} else if (type & GAME_CIA) {
|
} else if (type & GAME_CIA) {
|
||||||
CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub));
|
CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub));
|
||||||
if (!cia) {
|
if (!cia) {
|
||||||
|
@ -8,6 +8,7 @@ u32 CryptGameFile(const char* path, bool inplace, bool encrypt);
|
|||||||
u32 BuildCiaFromGameFile(const char* path, bool force_legit);
|
u32 BuildCiaFromGameFile(const char* path, bool force_legit);
|
||||||
u32 InstallGameFile(const char* path, bool to_emunand);
|
u32 InstallGameFile(const char* path, bool to_emunand);
|
||||||
u32 InstallTicketFile(const char* path, bool to_emunand);
|
u32 InstallTicketFile(const char* path, bool to_emunand);
|
||||||
|
u32 DumpTicketForGameFile(const char* path, bool force_legit);
|
||||||
u32 DumpCxiSrlFromTmdFile(const char* path);
|
u32 DumpCxiSrlFromTmdFile(const char* path);
|
||||||
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr);
|
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr);
|
||||||
u32 CompressCode(const char* path, const char* path_out);
|
u32 CompressCode(const char* path, const char* path_out);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user