From 3d7ac49f87f6ffae805b531e1bd6f6261430a675 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Wed, 21 Feb 2018 01:57:35 +0100 Subject: [PATCH] Improved encdecTitlekeys.bin / seeddb.bin builder --- arm9/source/game/ncch.c | 40 +++++++-------------- arm9/source/game/ncch.h | 3 +- arm9/source/game/ticketdb.c | 35 +++++++++--------- arm9/source/game/ticketdb.h | 7 ++-- arm9/source/utils/gameutil.c | 69 ++++++++++++------------------------ 5 files changed, 56 insertions(+), 98 deletions(-) diff --git a/arm9/source/game/ncch.c b/arm9/source/game/ncch.c index 84df277..a8715da 100644 --- a/arm9/source/game/ncch.c +++ b/arm9/source/game/ncch.c @@ -1,5 +1,6 @@ #include "ncch.h" #include "support.h" +#include "disadiff.h" #include "keydb.h" #include "aes.h" #include "sha.h" @@ -64,11 +65,10 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) { } // setup a large enough buffer - u8* buffer = (u8*) malloc(max(STD_BUFFER_SIZE, SEEDSAVE_MAX_ENTRIES*(8+16)*2)); + u8* buffer = (u8*) malloc(max(STD_BUFFER_SIZE, SEEDSAVE_AREA_SIZE)); if (!buffer) return 1; // try to grab the seed from NAND database - const u32 seed_offset[2] = {SEEDSAVE_AREA_OFFSETS}; const char* nand_drv[] = {"1:", "4:"}; // SysNAND and EmuNAND for (u32 i = 0; i < countof(nand_drv); i++) { UINT btr = 0; @@ -90,37 +90,21 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) { nand_drv[i], sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]); // check seedsave for seed - u8* seeddb[2]; - seeddb[0] = buffer; - seeddb[1] = buffer + (SEEDSAVE_MAX_ENTRIES*(8+16)); - if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) + u8* seeddb = buffer; + if (ReadDisaDiffIvfcLvl4(path, NULL, SEEDSAVE_AREA_OFFSET, SEEDSAVE_AREA_SIZE, seeddb) != SEEDSAVE_AREA_SIZE) continue; - f_read(&file, seeddb[0], 0x200, &btr); - u32 p_active = (getle32(seeddb[0] + 0x168)) ? 1 : 0; - - // read both partitions - for (u32 p = 0; p < 2; p++) { - f_lseek(&file, seed_offset[(p + p_active) % 2]); - f_read(&file, seeddb[p], SEEDSAVE_MAX_ENTRIES*(8+16), &btr); - } // search for the seed - for (u32 p = 0; p < 2; p++) { - for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) { - if (titleId != getle64(seeddb[p] + (s*8))) continue; - for (u32 p0 = 0; p0 < 2; p0++) { - memcpy(lseed, seeddb[(p+p0)%2] + (SEEDSAVE_MAX_ENTRIES*8) + (s*16), 16); - sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); - if (hash_seed == sha256sum[0]) { - memcpy(seed, lseed, 16); - f_close(&file); - free(buffer); - return 0; // found! - } - } + for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) { + if (titleId != getle64(seeddb + (s*8))) continue; + memcpy(lseed, seeddb + (SEEDSAVE_MAX_ENTRIES*8) + (s*16), 16); + sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); + if (hash_seed == sha256sum[0]) { + memcpy(seed, lseed, 16); + free(buffer); + return 0; // found! } } - f_close(&file); } // not found -> try seeddb.bin diff --git a/arm9/source/game/ncch.h b/arm9/source/game/ncch.h index 6fcb06f..f798444 100644 --- a/arm9/source/game/ncch.h +++ b/arm9/source/game/ncch.h @@ -20,8 +20,9 @@ #define SEEDDB_NAME "seeddb.bin" #define SEEDDB_SIZE(sdb) (16 + ((sdb)->n_entries * sizeof(SeedInfoEntry))) -#define SEEDSAVE_AREA_OFFSETS 0x7000, 0x5C000 #define SEEDSAVE_MAX_ENTRIES 2000 +#define SEEDSAVE_AREA_OFFSET 0x4000 +#define SEEDSAVE_AREA_SIZE (SEEDSAVE_MAX_ENTRIES * (8+16)) // wrapper defines #define DecryptNcch(data, offset, size, ncch, exefs) CryptNcch(data, offset, size, ncch, exefs, NCCH_NOCRYPTO) diff --git a/arm9/source/game/ticketdb.c b/arm9/source/game/ticketdb.c index 29d6134..776e18d 100644 --- a/arm9/source/game/ticketdb.c +++ b/arm9/source/game/ticketdb.c @@ -1,4 +1,5 @@ #include "ticketdb.h" +#include "disadiff.h" #include "support.h" #include "aes.h" #include "ff.h" @@ -64,29 +65,25 @@ Ticket* TicketFromTickDbChunk(u8* chunk, u8* title_id, bool legit_pls) { u32 FindTicket(Ticket* ticket, u8* title_id, bool force_legit, bool emunand) { const char* path_db = TICKDB_PATH(emunand); // EmuNAND / SysNAND - const u32 area_offsets[] = { TICKDB_AREA_OFFSETS }; - u8 data[0x400]; - FIL file; - UINT btr; + u8* data = (u8*) malloc(TICKDB_AREA_SIZE); + if (!data) return 1; - // parse file, sector by sector - if (f_open(&file, path_db, FA_READ | FA_OPEN_EXISTING) != FR_OK) + // read and decode ticket.db DIFF partition + if (ReadDisaDiffIvfcLvl4(path_db, NULL, TICKDB_AREA_OFFSET, TICKDB_AREA_SIZE, data) != TICKDB_AREA_SIZE) { + free(data); return 1; - bool found = false; - for (u32 p = 0; p < 2; p++) { - u32 area_offset = area_offsets[p]; - for (u32 i = 0; !found && (i < TICKDB_AREA_SIZE); i += 0x200) { - f_lseek(&file, area_offset + i); - if ((f_read(&file, data, 0x400, &btr) != FR_OK) || (btr != 0x400)) break; - Ticket* tick = TicketFromTickDbChunk(data, title_id, force_legit); - if (!tick) continue; - memcpy(ticket, tick, sizeof(Ticket)); - found = true; - break; - } } - f_close(&file); + // parse the decoded data for a ticket + bool found = false; + for (u32 i = 0; !found && (i < TICKDB_AREA_SIZE + 0x400); i += 0x200) { + Ticket* tick = TicketFromTickDbChunk(data + i, title_id, force_legit); + if (!tick) continue; + memcpy(ticket, tick, sizeof(Ticket)); + found = true; + } + + free(data); return (found) ? 0 : 1; } diff --git a/arm9/source/game/ticketdb.h b/arm9/source/game/ticketdb.h index 47f9e3c..4a58f51 100644 --- a/arm9/source/game/ticketdb.h +++ b/arm9/source/game/ticketdb.h @@ -7,9 +7,10 @@ #define TIKDB_NAME_DEC "decTitleKeys.bin" #define TIKDB_SIZE(tdb) (16 + ((tdb)->n_entries * sizeof(TitleKeyEntry))) -#define TICKDB_PATH(emu) ((emu) ? "4:/dbs/ticket.db" : "1:/dbs/ticket.db") // EmuNAND / SysNAND -#define TICKDB_AREA_OFFSETS 0x0137F000, 0x001C0C00 // second partition is more likely to be in use -#define TICKDB_AREA_SIZE 0x00180000 // the actual area size is around 0x0010C600 +#define TICKDB_PATH(emu) ((emu) ? "4:/dbs/ticket.db" : "1:/dbs/ticket.db") // EmuNAND / SysNAND +#define TICKDB_AREA_OFFSET 0xA1C00 // offset inside the decoded DIFF partition +#define TICKDB_AREA_RAW 0x0137F000, 0x001C0C00 // raw offsets inside the file +#define TICKDB_AREA_SIZE 0x00500000 // 5MB, arbitrary (around 1MB is realistic) #define TICKDB_MAGIC 0x44, 0x49, 0x46, 0x46, 0x00, 0x00, 0x03, 0x00, \ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ diff --git a/arm9/source/utils/gameutil.c b/arm9/source/utils/gameutil.c index 4fd9b10..4dd0405 100644 --- a/arm9/source/utils/gameutil.c +++ b/arm9/source/utils/gameutil.c @@ -1,4 +1,5 @@ #include "gameutil.h" +#include "disadiff.h" #include "game.h" #include "hid.h" #include "ui.h" @@ -1881,39 +1882,23 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) { return 1; } } else if (filetype & SYS_TICKDB) { - const u32 area_offsets[] = { TICKDB_AREA_OFFSETS }; - FIL file; + u8* data = (u8*) malloc(TICKDB_AREA_SIZE); + if (!data) return 1; - if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; - u8* data = (u8*) malloc(STD_BUFFER_SIZE); - if (!data) { - fvx_close(&file); + // read and decode ticket.db DIFF partition + if (ReadDisaDiffIvfcLvl4(path_in, NULL, TICKDB_AREA_OFFSET, TICKDB_AREA_SIZE, data) != TICKDB_AREA_SIZE) { + free(data); return 1; } - // parse file, sector by sector - for (u32 p = 0; p < sizeof(area_offsets) / sizeof(u32); p++) { - fvx_lseek(&file, area_offsets[p]); - fvx_sync(&file); - for (u32 i = 0; i < TICKDB_AREA_SIZE; i += (STD_BUFFER_SIZE - 0x200)) { - u32 read_bytes = min(STD_BUFFER_SIZE, TICKDB_AREA_SIZE - i); - - if (fvx_read(&file, data, read_bytes, NULL) != FR_OK) { - fvx_close(&file); - free(data); - return 1; - } - - for (u8* ptr = data; ptr + 0x400 < data + read_bytes; ptr += 0x200) { - Ticket* ticket = TicketFromTickDbChunk(ptr, NULL, true); - if (!ticket || (ticket->commonkey_idx >= 2) || !getbe64(ticket->ticket_id)) continue; - if (TIKDB_SIZE(tik_info) + 32 > STD_BUFFER_SIZE) break; // no error message - AddTicketToInfo(tik_info, ticket, dec); // ignore result - } - } + // parse the decoded data for valid tickets + for (u32 i = 0; i < TICKDB_AREA_SIZE + 0x400; i += 0x200) { + Ticket* ticket = TicketFromTickDbChunk(data + i, NULL, true); + if (!ticket || (ticket->commonkey_idx >= 2) || !getbe64(ticket->ticket_id)) continue; + if (TIKDB_SIZE(tik_info) + 32 > STD_BUFFER_SIZE) break; // no error message + AddTicketToInfo(tik_info, ticket, dec); // ignore result } - fvx_close(&file); free(data); } else if (filetype & BIN_TIKDB) { TitleKeysInfo* tik_info_merge = (TitleKeysInfo*) malloc(STD_BUFFER_SIZE); @@ -2017,32 +2002,22 @@ u32 BuildSeedInfo(const char* path, bool dump) { free(seed_info_merge); } else if (inputtype == 2) { // seed system save input - static const u32 seed_offset[2] = {SEEDSAVE_AREA_OFFSETS}; - u8* seedsave = (u8*) malloc(SEEDSAVE_MAX_ENTRIES*(8+16)); + u8* seedsave = (u8*) malloc(SEEDSAVE_AREA_SIZE); if (!seedsave) return 1; - if (fvx_qread(path_in, seedsave, 0, 0x200, NULL) != FR_OK) { + if (ReadDisaDiffIvfcLvl4(path_in, NULL, SEEDSAVE_AREA_OFFSET, SEEDSAVE_AREA_SIZE, seedsave) != SEEDSAVE_AREA_SIZE) { free(seedsave); return 1; } - u32 p_active = (getle32(seedsave + 0x168)) ? 1 : 0; - for (u32 p = 0; p < 2; p++) { - SeedInfoEntry seed = { 0 }; - - if (fvx_qread(path_in, seedsave, seed_offset[(p + p_active) % 2], SEEDSAVE_MAX_ENTRIES*(8+16), NULL) != FR_OK) { - free(seedsave); - return 1; - } - - for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) { - seed.titleId = getle64(seedsave + (s*8)); - memcpy(seed.seed, seedsave + (SEEDSAVE_MAX_ENTRIES*8) + (s*16), 16); - if (((seed.titleId >> 32) != 0x00040000) || - (!getle64(seed.seed) && !getle64(seed.seed + 8))) continue; - if (SEEDDB_SIZE(seed_info) + 32 > STD_BUFFER_SIZE) break; // no error message - AddSeedToDb(seed_info, &seed); // ignore result - } + SeedInfoEntry seed = { 0 }; + for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) { + seed.titleId = getle64(seedsave + (s*8)); + memcpy(seed.seed, seedsave + (SEEDSAVE_MAX_ENTRIES*8) + (s*16), 16); + if (((seed.titleId >> 32) != 0x00040000) || + (!getle64(seed.seed) && !getle64(seed.seed + 8))) continue; + if (SEEDDB_SIZE(seed_info) + 32 > STD_BUFFER_SIZE) break; // no error message + AddSeedToDb(seed_info, &seed); // ignore result } free(seedsave);