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 "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

View File

@ -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)

View File

@ -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;
}

View File

@ -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, \

View File

@ -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);