diff --git a/source/game/gameutil.c b/source/game/gameutil.c index 390f436..1002e6e 100644 --- a/source/game/gameutil.c +++ b/source/game/gameutil.c @@ -776,7 +776,8 @@ u32 BuildCiaFromTmdFile(const char* path_tmd, const char* path_cia, bool force_l return 1; } } else { - if ((GetTicket(ticket, title_id, false, src_emunand) == 0) && + if ((SearchTitleKeysBin(ticket, title_id) != 0) && + (GetTicket(ticket, title_id, false, src_emunand) == 0) && (getbe32(ticket->console_id) || getbe32(ticket->eshop_id))) { // if ticket found: wipe private data memset(ticket->console_id, 0, 4); // zero out console id @@ -793,12 +794,6 @@ u32 BuildCiaFromTmdFile(const char* path_tmd, const char* path_cia, bool force_l if (!name_content) return 1; // will not happen name_content++; - // try to build metadata - if (content_count) { - snprintf(name_content, 256 - (name_content - path_content), "%08lx.app", getbe32(content_list->id)); - if (LoadNcchMeta(meta, path_content, 0) != 0) meta = NULL; - } else meta = NULL; - // insert contents u8 titlekey[16] = { 0xFF }; if ((GetTitleKey(titlekey, &(cia->ticket)) != 0) && force_legit) return 1; @@ -811,9 +806,12 @@ u32 BuildCiaFromTmdFile(const char* path_tmd, const char* path_cia, bool force_l } } - // try to insert meta, but ignore result - if (meta && (InsertCiaMeta(path_cia, meta) == 0)) - cia->header.size_meta = CIA_META_SIZE; + // try to build & insert meta, but ignore result + if (content_count) { + snprintf(name_content, 256 - (name_content - path_content), "%08lx.app", getbe32(content_list->id)); + if ((LoadNcchMeta(meta, path_content, 0) == 0) && (InsertCiaMeta(path_cia, meta) == 0)) + cia->header.size_meta = CIA_META_SIZE; + } // write the CIA stub (take #2) if ((FixTmdHashes(tmd) != 0) || (WriteCiaStub(cia, path_cia) != 0)) @@ -828,7 +826,7 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit) { u32 ret = 0; // destination path - if (GetOutputPath(dest, path, "cia") != 0) return 1; + if (GetOutputPath(dest, path, force_legit ? "legit.cia" : "cia") != 0) return 1; if (!CheckWritePermissions(dest)) return 1; // ensure the output dir exists @@ -840,8 +838,8 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit) { ret = BuildCiaFromTmdFile(path, dest, force_legit); else ret = 1; - // if (ret != 0) // try to get rid of the borked file - // f_unlink(dest); + if (ret != 0) // try to get rid of the borked file + f_unlink(dest); return ret; } diff --git a/source/game/ticket.c b/source/game/ticket.c index c4c3154..b621ab4 100644 --- a/source/game/ticket.c +++ b/source/game/ticket.c @@ -106,33 +106,12 @@ u32 GetTicket(Ticket* ticket, u8* title_id, bool force_legit, bool emunand) { return (found) ? 0 : 1; } -u32 BuildFakeTicket(Ticket* ticket, u8* title_id) { - const u8 sig_type[4] = { TICKET_SIG_TYPE }; // RSA_2048 SHA256 - const u8 ticket_cnt_index[] = { // whatever this is - 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, - 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - }; - // set ticket all zero for a clean start - memset(ticket, 0x00, sizeof(Ticket)); - // fill ticket values - memcpy(ticket->sig_type, sig_type, 4); - memset(ticket->signature, 0xFF, 0x100); - snprintf((char*) ticket->issuer, 0x40, TICKET_ISSUER); - memset(ticket->ecdsa, 0xFF, 0x3C); - ticket->version = 0x01; - memset(ticket->titlekey, 0xFF, 16); - memcpy(ticket->title_id, title_id, 8); - ticket->commonkey_idx = 0x00; // eshop - ticket->audit = 0x01; // whatever - memcpy(ticket->content_index, ticket_cnt_index, sizeof(ticket_cnt_index)); - +u32 SearchTitleKeysBin(Ticket* ticket, u8* title_id) { + bool found = false; // search for a titlekey inside encTitleKeys.bin / decTitleKeys.bin - for (u32 enc = 0; enc <= 1; enc++) { + // when found, add it to the ticket + for (u32 enc = 0; (enc <= 1) && !found; enc++) { const char* base[] = { INPUT_PATHS }; - bool found = false; for (u32 i = 0; (i < (sizeof(base)/sizeof(char*))) && !found; i++) { TitleKeysInfo* tikdb = (TitleKeysInfo*) (TEMP_BUFFER + (TEMP_BUFFER_SIZE/2)); char path[64]; @@ -158,8 +137,33 @@ u32 BuildFakeTicket(Ticket* ticket, u8* title_id) { break; } } - if (found) break; } + return (found) ? 0 : 1; +} + +u32 BuildFakeTicket(Ticket* ticket, u8* title_id) { + const u8 sig_type[4] = { TICKET_SIG_TYPE }; // RSA_2048 SHA256 + const u8 ticket_cnt_index[] = { // whatever this is + 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + // set ticket all zero for a clean start + memset(ticket, 0x00, sizeof(Ticket)); + // fill ticket values + memcpy(ticket->sig_type, sig_type, 4); + memset(ticket->signature, 0xFF, 0x100); + snprintf((char*) ticket->issuer, 0x40, TICKET_ISSUER); + memset(ticket->ecdsa, 0xFF, 0x3C); + ticket->version = 0x01; + memset(ticket->titlekey, 0xFF, 16); + memcpy(ticket->title_id, title_id, 8); + ticket->commonkey_idx = 0x00; // eshop + ticket->audit = 0x01; // whatever + memcpy(ticket->content_index, ticket_cnt_index, sizeof(ticket_cnt_index)); + return 0; } diff --git a/source/game/ticket.h b/source/game/ticket.h index 876a7bf..b6c040f 100644 --- a/source/game/ticket.h +++ b/source/game/ticket.h @@ -46,4 +46,5 @@ typedef struct { u32 ValidateTicket(Ticket* ticket); u32 GetTitleKey(u8* titlekey, Ticket* ticket); u32 GetTicket(Ticket* ticket, u8* title_id, bool force_legit, bool emunand); +u32 SearchTitleKeysBin(Ticket* ticket, u8* title_id); u32 BuildFakeTicket(Ticket* ticket, u8* title_id);