Improved encdecTitlekeys.bin / seeddb.bin builder

This commit is contained in:
d0k3 2018-02-21 01:57:35 +01:00
parent cabe185016
commit 3d7ac49f87
5 changed files with 56 additions and 98 deletions

View File

@ -1,5 +1,6 @@
#include "ncch.h" #include "ncch.h"
#include "support.h" #include "support.h"
#include "disadiff.h"
#include "keydb.h" #include "keydb.h"
#include "aes.h" #include "aes.h"
#include "sha.h" #include "sha.h"
@ -64,11 +65,10 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) {
} }
// setup a large enough buffer // 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; if (!buffer) return 1;
// try to grab the seed from NAND database // 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 const char* nand_drv[] = {"1:", "4:"}; // SysNAND and EmuNAND
for (u32 i = 0; i < countof(nand_drv); i++) { for (u32 i = 0; i < countof(nand_drv); i++) {
UINT btr = 0; UINT btr = 0;
@ -90,37 +90,21 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) {
nand_drv[i], sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]); nand_drv[i], sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]);
// check seedsave for seed // check seedsave for seed
u8* seeddb[2]; u8* seeddb = buffer;
seeddb[0] = buffer; if (ReadDisaDiffIvfcLvl4(path, NULL, SEEDSAVE_AREA_OFFSET, SEEDSAVE_AREA_SIZE, seeddb) != SEEDSAVE_AREA_SIZE)
seeddb[1] = buffer + (SEEDSAVE_MAX_ENTRIES*(8+16));
if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
continue; 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 // search for the seed
for (u32 p = 0; p < 2; p++) { for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) {
for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) { if (titleId != getle64(seeddb + (s*8))) continue;
if (titleId != getle64(seeddb[p] + (s*8))) continue; memcpy(lseed, seeddb + (SEEDSAVE_MAX_ENTRIES*8) + (s*16), 16);
for (u32 p0 = 0; p0 < 2; p0++) { sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE);
memcpy(lseed, seeddb[(p+p0)%2] + (SEEDSAVE_MAX_ENTRIES*8) + (s*16), 16); if (hash_seed == sha256sum[0]) {
sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); memcpy(seed, lseed, 16);
if (hash_seed == sha256sum[0]) { free(buffer);
memcpy(seed, lseed, 16); return 0; // found!
f_close(&file);
free(buffer);
return 0; // found!
}
}
} }
} }
f_close(&file);
} }
// not found -> try seeddb.bin // not found -> try seeddb.bin

View File

@ -20,8 +20,9 @@
#define SEEDDB_NAME "seeddb.bin" #define SEEDDB_NAME "seeddb.bin"
#define SEEDDB_SIZE(sdb) (16 + ((sdb)->n_entries * sizeof(SeedInfoEntry))) #define SEEDDB_SIZE(sdb) (16 + ((sdb)->n_entries * sizeof(SeedInfoEntry)))
#define SEEDSAVE_AREA_OFFSETS 0x7000, 0x5C000
#define SEEDSAVE_MAX_ENTRIES 2000 #define SEEDSAVE_MAX_ENTRIES 2000
#define SEEDSAVE_AREA_OFFSET 0x4000
#define SEEDSAVE_AREA_SIZE (SEEDSAVE_MAX_ENTRIES * (8+16))
// wrapper defines // wrapper defines
#define DecryptNcch(data, offset, size, ncch, exefs) CryptNcch(data, offset, size, ncch, exefs, NCCH_NOCRYPTO) #define DecryptNcch(data, offset, size, ncch, exefs) CryptNcch(data, offset, size, ncch, exefs, NCCH_NOCRYPTO)

View File

@ -1,4 +1,5 @@
#include "ticketdb.h" #include "ticketdb.h"
#include "disadiff.h"
#include "support.h" #include "support.h"
#include "aes.h" #include "aes.h"
#include "ff.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) { u32 FindTicket(Ticket* ticket, u8* title_id, bool force_legit, bool emunand) {
const char* path_db = TICKDB_PATH(emunand); // EmuNAND / SysNAND const char* path_db = TICKDB_PATH(emunand); // EmuNAND / SysNAND
const u32 area_offsets[] = { TICKDB_AREA_OFFSETS }; u8* data = (u8*) malloc(TICKDB_AREA_SIZE);
u8 data[0x400]; if (!data) return 1;
FIL file;
UINT btr;
// parse file, sector by sector // read and decode ticket.db DIFF partition
if (f_open(&file, path_db, FA_READ | FA_OPEN_EXISTING) != FR_OK) if (ReadDisaDiffIvfcLvl4(path_db, NULL, TICKDB_AREA_OFFSET, TICKDB_AREA_SIZE, data) != TICKDB_AREA_SIZE) {
free(data);
return 1; 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; return (found) ? 0 : 1;
} }

View File

@ -7,9 +7,10 @@
#define TIKDB_NAME_DEC "decTitleKeys.bin" #define TIKDB_NAME_DEC "decTitleKeys.bin"
#define TIKDB_SIZE(tdb) (16 + ((tdb)->n_entries * sizeof(TitleKeyEntry))) #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_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_OFFSET 0xA1C00 // offset inside the decoded DIFF partition
#define TICKDB_AREA_SIZE 0x00180000 // the actual area size is around 0x0010C600 #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, \ #define TICKDB_MAGIC 0x44, 0x49, 0x46, 0x46, 0x00, 0x00, 0x03, 0x00, \
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \

View File

@ -1,4 +1,5 @@
#include "gameutil.h" #include "gameutil.h"
#include "disadiff.h"
#include "game.h" #include "game.h"
#include "hid.h" #include "hid.h"
#include "ui.h" #include "ui.h"
@ -1881,39 +1882,23 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) {
return 1; return 1;
} }
} else if (filetype & SYS_TICKDB) { } else if (filetype & SYS_TICKDB) {
const u32 area_offsets[] = { TICKDB_AREA_OFFSETS }; u8* data = (u8*) malloc(TICKDB_AREA_SIZE);
FIL file; if (!data) return 1;
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; // read and decode ticket.db DIFF partition
u8* data = (u8*) malloc(STD_BUFFER_SIZE); if (ReadDisaDiffIvfcLvl4(path_in, NULL, TICKDB_AREA_OFFSET, TICKDB_AREA_SIZE, data) != TICKDB_AREA_SIZE) {
if (!data) { free(data);
fvx_close(&file);
return 1; return 1;
} }
// parse file, sector by sector // parse the decoded data for valid tickets
for (u32 p = 0; p < sizeof(area_offsets) / sizeof(u32); p++) { for (u32 i = 0; i < TICKDB_AREA_SIZE + 0x400; i += 0x200) {
fvx_lseek(&file, area_offsets[p]); Ticket* ticket = TicketFromTickDbChunk(data + i, NULL, true);
fvx_sync(&file); if (!ticket || (ticket->commonkey_idx >= 2) || !getbe64(ticket->ticket_id)) continue;
for (u32 i = 0; i < TICKDB_AREA_SIZE; i += (STD_BUFFER_SIZE - 0x200)) { if (TIKDB_SIZE(tik_info) + 32 > STD_BUFFER_SIZE) break; // no error message
u32 read_bytes = min(STD_BUFFER_SIZE, TICKDB_AREA_SIZE - i); AddTicketToInfo(tik_info, ticket, dec); // ignore result
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
}
}
} }
fvx_close(&file);
free(data); free(data);
} else if (filetype & BIN_TIKDB) { } else if (filetype & BIN_TIKDB) {
TitleKeysInfo* tik_info_merge = (TitleKeysInfo*) malloc(STD_BUFFER_SIZE); TitleKeysInfo* tik_info_merge = (TitleKeysInfo*) malloc(STD_BUFFER_SIZE);
@ -2017,32 +2002,22 @@ u32 BuildSeedInfo(const char* path, bool dump) {
free(seed_info_merge); free(seed_info_merge);
} else if (inputtype == 2) { // seed system save input } else if (inputtype == 2) { // seed system save input
static const u32 seed_offset[2] = {SEEDSAVE_AREA_OFFSETS}; u8* seedsave = (u8*) malloc(SEEDSAVE_AREA_SIZE);
u8* seedsave = (u8*) malloc(SEEDSAVE_MAX_ENTRIES*(8+16));
if (!seedsave) return 1; 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); free(seedsave);
return 1; return 1;
} }
u32 p_active = (getle32(seedsave + 0x168)) ? 1 : 0; SeedInfoEntry seed = { 0 };
for (u32 p = 0; p < 2; p++) { for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) {
SeedInfoEntry seed = { 0 }; seed.titleId = getle64(seedsave + (s*8));
memcpy(seed.seed, seedsave + (SEEDSAVE_MAX_ENTRIES*8) + (s*16), 16);
if (fvx_qread(path_in, seedsave, seed_offset[(p + p_active) % 2], SEEDSAVE_MAX_ENTRIES*(8+16), NULL) != FR_OK) { if (((seed.titleId >> 32) != 0x00040000) ||
free(seedsave); (!getle64(seed.seed) && !getle64(seed.seed + 8))) continue;
return 1; if (SEEDDB_SIZE(seed_info) + 32 > STD_BUFFER_SIZE) break; // no error message
} AddSeedToDb(seed_info, &seed); // ignore result
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); free(seedsave);