forked from Mirror/GodMode9
Enable building titlekey databases
This commit is contained in:
parent
f856211773
commit
dd377dbf8e
@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
|
|
||||||
// GodMode9 version
|
// GodMode9 version
|
||||||
#define VERSION "1.0.8"
|
#define VERSION "1.0.9"
|
||||||
|
|
||||||
// Maximum payload size (arbitrary value!)
|
// Maximum payload size (arbitrary value!)
|
||||||
#define SELF_MAX_SIZE (320 * 1024) // 320kB
|
#define SELF_MAX_SIZE (320 * 1024) // 320kB
|
||||||
|
@ -9,6 +9,7 @@ u32 IdentifyFileType(const char* path) {
|
|||||||
const u8 romfs_magic[] = { ROMFS_MAGIC };
|
const u8 romfs_magic[] = { ROMFS_MAGIC };
|
||||||
const u8 tickdb_magic[] = { TICKDB_MAGIC };
|
const u8 tickdb_magic[] = { TICKDB_MAGIC };
|
||||||
const u8 smdh_magic[] = { SMDH_MAGIC };
|
const u8 smdh_magic[] = { SMDH_MAGIC };
|
||||||
|
if (!path) return 0; // safety
|
||||||
u8 header[0x200] __attribute__((aligned(32))); // minimum required size
|
u8 header[0x200] __attribute__((aligned(32))); // minimum required size
|
||||||
void* data = (void*) header;
|
void* data = (void*) header;
|
||||||
size_t fsize = FileGetSize(path);
|
size_t fsize = FileGetSize(path);
|
||||||
@ -90,9 +91,11 @@ u32 IdentifyFileType(const char* path) {
|
|||||||
strncpy(ext_cetk, "cetk", 5);
|
strncpy(ext_cetk, "cetk", 5);
|
||||||
if (FileGetSize(path_cetk) > 0)
|
if (FileGetSize(path_cetk) > 0)
|
||||||
return GAME_NUSCDN; // NUS/CDN type 2
|
return GAME_NUSCDN; // NUS/CDN type 2
|
||||||
|
} else if (strncasecmp(fname, TIKDB_NAME_ENC, sizeof(TIKDB_NAME_ENC)) == 0) {
|
||||||
|
return BIN_TIKDB | FLAG_ENC; // titlekey database / encrypted
|
||||||
|
} else if (strncasecmp(fname, TIKDB_NAME_DEC, sizeof(TIKDB_NAME_DEC)) == 0) {
|
||||||
|
return BIN_TIKDB; // titlekey database / decrypted
|
||||||
} else if ((strncasecmp(fname, "seeddb.bin", 11) == 0) ||
|
} else if ((strncasecmp(fname, "seeddb.bin", 11) == 0) ||
|
||||||
(strncasecmp(fname, "encTitlekeys.bin", 17) == 0) ||
|
|
||||||
(strncasecmp(fname, "decTitlekeys.bin", 17) == 0) ||
|
|
||||||
(strncasecmp(fname, "aeskeydb.bin", 13) == 0) ||
|
(strncasecmp(fname, "aeskeydb.bin", 13) == 0) ||
|
||||||
(strncasecmp(fname, "otp.bin", 8) == 0) ||
|
(strncasecmp(fname, "otp.bin", 8) == 0) ||
|
||||||
(strncasecmp(fname, "secret_sector.bin", 18) == 0) ||
|
(strncasecmp(fname, "secret_sector.bin", 18) == 0) ||
|
||||||
|
@ -19,9 +19,11 @@
|
|||||||
#define SYS_TICKDB (1UL<<14)
|
#define SYS_TICKDB (1UL<<14)
|
||||||
#define BIN_NCCHNFO (1UL<<15)
|
#define BIN_NCCHNFO (1UL<<15)
|
||||||
#define BIN_LAUNCH (1UL<<16)
|
#define BIN_LAUNCH (1UL<<16)
|
||||||
#define BIN_SUPPORT (1UL<<17)
|
#define BIN_TIKDB (1UL<<17)
|
||||||
|
#define BIN_SUPPORT (1UL<<18)
|
||||||
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
#define TYPE_BASE 0x00FFFFFF // 24 bit reserved for base types
|
||||||
|
|
||||||
|
#define FLAG_ENC (1UL<<28)
|
||||||
#define FLAG_CTR (1UL<<29)
|
#define FLAG_CTR (1UL<<29)
|
||||||
#define FLAG_NUSCDN (1UL<<30)
|
#define FLAG_NUSCDN (1UL<<30)
|
||||||
#define FLAG_CXI (1UL<<31)
|
#define FLAG_CXI (1UL<<31)
|
||||||
@ -30,8 +32,9 @@
|
|||||||
#define FYTPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
#define FYTPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
||||||
#define FYTPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|GAME_NUSCDN|SYS_FIRM))
|
#define FYTPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|GAME_NUSCDN|SYS_FIRM))
|
||||||
#define FYTPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS))
|
#define FYTPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS))
|
||||||
#define FTYPE_BUILDABLE(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
#define FTYPE_CIABUILD(tp) (tp&(GAME_NCSD|GAME_NCCH|GAME_TMD))
|
||||||
#define FTYPE_BUILDABLE_L(tp) (FTYPE_BUILDABLE(tp) && (tp&(GAME_TMD)))
|
#define FTYPE_CIABUILD_L(tp) (FTYPE_CIABUILD(tp) && (tp&(GAME_TMD)))
|
||||||
|
#define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB))
|
||||||
#define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS))
|
#define FTYPE_TITLEINFO(tp) (tp&(GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS))
|
||||||
#define FTYPE_TRANSFERABLE(tp) ((u32) (tp&(IMG_FAT|FLAG_CTR)) == (u32) (IMG_FAT|FLAG_CTR))
|
#define FTYPE_TRANSFERABLE(tp) ((u32) (tp&(IMG_FAT|FLAG_CTR)) == (u32) (IMG_FAT|FLAG_CTR))
|
||||||
#define FTYPE_HSINJECTABLE(tp) ((u32) (tp&(GAME_NCCH|FLAG_CXI)) == (u32) (GAME_NCCH|FLAG_CXI))
|
#define FTYPE_HSINJECTABLE(tp) ((u32) (tp&(GAME_NCCH|FLAG_CXI)) == (u32) (GAME_NCCH|FLAG_CXI))
|
||||||
|
@ -1662,3 +1662,70 @@ u32 InjectHealthAndSafety(const char* path, const char* destdrv) {
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) {
|
||||||
|
TitleKeysInfo* tik_info = (TitleKeysInfo*) MAIN_BUFFER;
|
||||||
|
const char* path_out = (dec) ? OUTPUT_PATH "/" TIKDB_NAME_DEC : OUTPUT_PATH "/" TIKDB_NAME_ENC;
|
||||||
|
const char* path_in = path;
|
||||||
|
UINT br;
|
||||||
|
|
||||||
|
if (!path_in && !dump) { // no input path given - initialize
|
||||||
|
memset(tik_info, 0, 16);
|
||||||
|
if ((fvx_stat(path_out, NULL) == FR_OK) &&
|
||||||
|
(ShowPrompt(true, "%s\nOutput file already exists.\nUpdate this?", path_out)))
|
||||||
|
path_in = path_out;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 filetype = path_in ? IdentifyFileType(path_in) : 0;
|
||||||
|
if (filetype & GAME_TICKET) {
|
||||||
|
Ticket* ticket = (Ticket*) TEMP_BUFFER;
|
||||||
|
if ((fvx_qread(path_in, ticket, 0, TICKET_SIZE, &br) != FR_OK) || (br != TICKET_SIZE) ||
|
||||||
|
(TIKDB_SIZE(tik_info) + 32 > MAIN_BUFFER_SIZE) || (AddTicketToInfo(tik_info, ticket, dec) != 0)) return 1;
|
||||||
|
} else if (filetype & SYS_TICKDB) {
|
||||||
|
const u32 area_offsets[] = { TICKDB_AREA_OFFSETS };
|
||||||
|
FIL file;
|
||||||
|
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) 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 += (TEMP_BUFFER_SIZE - 0x200)) {
|
||||||
|
u32 read_bytes = min(TEMP_BUFFER_SIZE, TICKDB_AREA_SIZE - i);
|
||||||
|
u8* data = (u8*) TEMP_BUFFER;
|
||||||
|
if ((fvx_read(&file, data, read_bytes, &br) != FR_OK) || (br != read_bytes)) {
|
||||||
|
fvx_close(&file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (; data + TICKET_SIZE < ((u8*) TEMP_BUFFER) + read_bytes; data += 0x200) {
|
||||||
|
Ticket* ticket = TicketFromTickDbChunk(data, NULL, false);
|
||||||
|
if (!ticket || (ticket->commonkey_idx >= 2) || !getbe64(ticket->ticket_id)) continue;
|
||||||
|
if (TIKDB_SIZE(tik_info) + 32 > MAIN_BUFFER_SIZE) return 1;
|
||||||
|
AddTicketToInfo(tik_info, ticket, dec); // ignore result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fvx_close(&file);
|
||||||
|
} else if (filetype & BIN_TIKDB) {
|
||||||
|
TitleKeysInfo* tik_info_merge = (TitleKeysInfo*) TEMP_BUFFER;
|
||||||
|
if ((fvx_qread(path_in, tik_info_merge, 0, TEMP_BUFFER_SIZE, &br) != FR_OK) ||
|
||||||
|
(TIKDB_SIZE(tik_info_merge) != br)) return 1;
|
||||||
|
// merge and rebuild TitleKeyInfo
|
||||||
|
u32 n_entries = tik_info_merge->n_entries;
|
||||||
|
TitleKeyEntry* tik = tik_info_merge->entries;
|
||||||
|
for (u32 i = 0; i < n_entries; i++, tik++) {
|
||||||
|
if (TIKDB_SIZE(tik_info) + 32 > MAIN_BUFFER_SIZE) return 1;
|
||||||
|
AddTitleKeyToInfo(tik_info, tik, !(filetype & FLAG_ENC), dec, false); // ignore result
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dump) {
|
||||||
|
u32 dump_size = TIKDB_SIZE(tik_info);
|
||||||
|
f_unlink(path_out);
|
||||||
|
if ((dump_size <= 16) || (fvx_qwrite(path_out, tik_info, 0, dump_size, &br) != FR_OK) || (br != dump_size))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -10,3 +10,4 @@ u32 ShowGameFileTitleInfo(const char* path);
|
|||||||
u32 BuildNcchInfoXorpads(const char* destdir, const char* path);
|
u32 BuildNcchInfoXorpads(const char* destdir, const char* path);
|
||||||
u32 CheckHealthAndSafetyInject(const char* hsdrv);
|
u32 CheckHealthAndSafetyInject(const char* hsdrv);
|
||||||
u32 InjectHealthAndSafety(const char* path, const char* destdrv);
|
u32 InjectHealthAndSafety(const char* path, const char* destdrv);
|
||||||
|
u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump);
|
||||||
|
@ -4,19 +4,6 @@
|
|||||||
#include "sha.h"
|
#include "sha.h"
|
||||||
#include "ff.h"
|
#include "ff.h"
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u32 commonkey_idx;
|
|
||||||
u8 reserved[4];
|
|
||||||
u8 title_id[8];
|
|
||||||
u8 titlekey[16];
|
|
||||||
} __attribute__((packed)) TitleKeyEntry;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u32 n_entries;
|
|
||||||
u8 reserved[12];
|
|
||||||
TitleKeyEntry entries[256]; // this number is only a placeholder
|
|
||||||
} __attribute__((packed)) TitleKeysInfo;
|
|
||||||
|
|
||||||
u32 ValidateTicket(Ticket* ticket) {
|
u32 ValidateTicket(Ticket* ticket) {
|
||||||
const u8 magic[] = { TICKET_SIG_TYPE };
|
const u8 magic[] = { TICKET_SIG_TYPE };
|
||||||
if ((memcmp(ticket->sig_type, magic, sizeof(magic)) != 0) ||
|
if ((memcmp(ticket->sig_type, magic, sizeof(magic)) != 0) ||
|
||||||
@ -148,20 +135,31 @@ u32 FindTitleKey(Ticket* ticket, u8* title_id) {
|
|||||||
return (found) ? 0 : 1;
|
return (found) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*u32 BuildTitleKeyInfo(TitleKeysInfo* tik_info, TicketInfo* tick_info, bool decrypt) {
|
u32 AddTitleKeyToInfo(TitleKeysInfo* tik_info, TitleKeyEntry* tik_entry, bool decrypted_in, bool decrypted_out, bool devkit) {
|
||||||
memset(tik_info, 0, 16);
|
if (!tik_entry) { // no titlekey entry -> reset database
|
||||||
for (u32 i = 0; i < tick_info->n_entries; i++) {
|
memset(tik_info, 0, 16);
|
||||||
TicketEntry* tick_entry = tick_info->entries + i;
|
return 0;
|
||||||
TitleKeyEntry* tik_entry = tik_info->entries + tik_info->n_entries;
|
|
||||||
if (!getbe64(tick_entry->ticket_id)) continue;
|
|
||||||
tik_entry->commonkey_idx = tick_entry->commonkey_idx;
|
|
||||||
memcpy(tik_entry->title_id, tick_entry->title_id, 8);
|
|
||||||
memcpy(tik_entry->titlekey, tick_entry->titlekey, 16);
|
|
||||||
if (decrypt) CryptTitleKey(tik_entry, false, false);
|
|
||||||
tik_info->n_entries++;
|
|
||||||
}
|
}
|
||||||
|
// check if entry already in DB
|
||||||
|
u32 n_entries = tik_info->n_entries;
|
||||||
|
TitleKeyEntry* tik = tik_info->entries;
|
||||||
|
for (u32 i = 0; i < n_entries; i++, tik++)
|
||||||
|
if (memcmp(tik->title_id, tik_entry->title_id, 8) == 0) return 0;
|
||||||
|
// actually a new titlekey
|
||||||
|
memcpy(tik, tik_entry, sizeof(TitleKeyEntry));
|
||||||
|
if ((decrypted_in != decrypted_out) && (CryptTitleKey(tik, !decrypted_out, devkit) != 0)) return 1;
|
||||||
|
tik_info->n_entries++;
|
||||||
return 0;
|
return 0;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
|
u32 AddTicketToInfo(TitleKeysInfo* tik_info, Ticket* ticket, bool decrypt) { // TODO: check for legit tickets?
|
||||||
|
if (!ticket) return AddTitleKeyToInfo(tik_info, NULL, false, false, false);
|
||||||
|
TitleKeyEntry tik = { 0 };
|
||||||
|
memcpy(tik.title_id, ticket->title_id, 8);
|
||||||
|
memcpy(tik.titlekey, ticket->titlekey, 16);
|
||||||
|
tik.commonkey_idx = ticket->commonkey_idx;
|
||||||
|
return AddTitleKeyToInfo(tik_info, &tik, false, decrypt, TICKET_DEVKIT(ticket));
|
||||||
|
}
|
||||||
|
|
||||||
u32 BuildFakeTicket(Ticket* ticket, u8* title_id) {
|
u32 BuildFakeTicket(Ticket* ticket, u8* title_id) {
|
||||||
const u8 sig_type[4] = { TICKET_SIG_TYPE }; // RSA_2048 SHA256
|
const u8 sig_type[4] = { TICKET_SIG_TYPE }; // RSA_2048 SHA256
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#define TIKDB_NAME_ENC "encTitleKeys.bin"
|
#define TIKDB_NAME_ENC "encTitleKeys.bin"
|
||||||
#define TIKDB_NAME_DEC "decTitleKeys.bin"
|
#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_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_OFFSETS 0x0137F000, 0x001C0C00 // second partition is more likely to be in use
|
||||||
@ -56,10 +57,25 @@ typedef struct {
|
|||||||
u8 content_index[0xAC];
|
u8 content_index[0xAC];
|
||||||
} __attribute__((packed)) Ticket;
|
} __attribute__((packed)) Ticket;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 commonkey_idx;
|
||||||
|
u8 reserved[4];
|
||||||
|
u8 title_id[8];
|
||||||
|
u8 titlekey[16];
|
||||||
|
} __attribute__((packed)) TitleKeyEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 n_entries;
|
||||||
|
u8 reserved[12];
|
||||||
|
TitleKeyEntry entries[256]; // this number is only a placeholder
|
||||||
|
} __attribute__((packed)) TitleKeysInfo;
|
||||||
|
|
||||||
u32 ValidateTicket(Ticket* ticket);
|
u32 ValidateTicket(Ticket* ticket);
|
||||||
u32 GetTitleKey(u8* titlekey, Ticket* ticket);
|
u32 GetTitleKey(u8* titlekey, Ticket* ticket);
|
||||||
Ticket* TicketFromTickDbChunk(u8* chunk, u8* title_id, bool legit_pls);
|
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);
|
||||||
u32 FindTitleKey(Ticket* ticket, u8* title_id);
|
u32 FindTitleKey(Ticket* ticket, u8* title_id);
|
||||||
|
u32 AddTitleKeyToInfo(TitleKeysInfo* tik_info, TitleKeyEntry* tik_entry, bool decrypted_in, bool decrypted_out, bool devkit);
|
||||||
|
u32 AddTicketToInfo(TitleKeysInfo* tik_info, Ticket* ticket, bool decrypt);
|
||||||
u32 BuildFakeTicket(Ticket* ticket, u8* title_id);
|
u32 BuildFakeTicket(Ticket* ticket, u8* title_id);
|
||||||
u32 BuildTicketCert(u8* tickcert);
|
u32 BuildTicketCert(u8* tickcert);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
#include "virtual.h"
|
#include "virtual.h"
|
||||||
#include "vcart.h"
|
#include "vcart.h"
|
||||||
|
#include "game.h"
|
||||||
#include "nandcmac.h"
|
#include "nandcmac.h"
|
||||||
#include "ctrtransfer.h"
|
#include "ctrtransfer.h"
|
||||||
#include "ncchinfo.h"
|
#include "ncchinfo.h"
|
||||||
@ -651,8 +652,9 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
bool decryptable = (FYTPE_DECRYPTABLE(filetype));
|
bool decryptable = (FYTPE_DECRYPTABLE(filetype));
|
||||||
bool encryptable = (FYTPE_ENCRYPTABLE(filetype));
|
bool encryptable = (FYTPE_ENCRYPTABLE(filetype));
|
||||||
bool cryptable_inplace = ((encryptable||decryptable) && !in_output_path && (drvtype & DRV_FAT));
|
bool cryptable_inplace = ((encryptable||decryptable) && !in_output_path && (drvtype & DRV_FAT));
|
||||||
bool buildable = (FTYPE_BUILDABLE(filetype));
|
bool cia_buildable = (FTYPE_CIABUILD(filetype));
|
||||||
bool buildable_legit = (FTYPE_BUILDABLE_L(filetype));
|
bool cia_buildable_legit = (FTYPE_CIABUILD_L(filetype));
|
||||||
|
bool tik_buildable = (FTYPE_TIKBUILD(filetype)) && !in_output_path;
|
||||||
bool titleinfo = (FTYPE_TITLEINFO(filetype));
|
bool titleinfo = (FTYPE_TITLEINFO(filetype));
|
||||||
bool transferable = (FTYPE_TRANSFERABLE(filetype) && IS_A9LH && (drvtype & DRV_FAT));
|
bool transferable = (FTYPE_TRANSFERABLE(filetype) && IS_A9LH && (drvtype & DRV_FAT));
|
||||||
bool hsinjectable = (FTYPE_HSINJECTABLE(filetype));
|
bool hsinjectable = (FTYPE_HSINJECTABLE(filetype));
|
||||||
@ -660,8 +662,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
bool ebackupable = (FTYPE_EBACKUP(filetype));
|
bool ebackupable = (FTYPE_EBACKUP(filetype));
|
||||||
bool xorpadable = (FTYPE_XORPAD(filetype));
|
bool xorpadable = (FTYPE_XORPAD(filetype));
|
||||||
bool launchable = ((FTYPE_PAYLOAD(filetype)) && (drvtype & DRV_FAT));
|
bool launchable = ((FTYPE_PAYLOAD(filetype)) && (drvtype & DRV_FAT));
|
||||||
bool special_opt = mountable || verificable || decryptable || encryptable || buildable || buildable_legit ||
|
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit ||
|
||||||
titleinfo || hsinjectable || restorable || xorpadable || launchable || ebackupable;
|
tik_buildable || titleinfo || hsinjectable || restorable || xorpadable || launchable || ebackupable;
|
||||||
|
|
||||||
char pathstr[32+1];
|
char pathstr[32+1];
|
||||||
TruncateString(pathstr, curr_entry->path, 32, 8);
|
TruncateString(pathstr, curr_entry->path, 32, 8);
|
||||||
@ -697,9 +699,11 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
(filetype & GAME_BOSS ) ? "BOSS file options..." :
|
(filetype & GAME_BOSS ) ? "BOSS file options..." :
|
||||||
(filetype & GAME_NUSCDN)? "Decrypt NUS/CDN file" :
|
(filetype & GAME_NUSCDN)? "Decrypt NUS/CDN file" :
|
||||||
(filetype & GAME_SMDH) ? "Show SMDH title info" :
|
(filetype & GAME_SMDH) ? "Show SMDH title info" :
|
||||||
(filetype & GAME_NDS) ? "Show NDS title info" :
|
(filetype & GAME_NDS) ? "Show NDS title info" :
|
||||||
|
(filetype & GAME_TICKET)? "Ticket options..." :
|
||||||
(filetype & SYS_FIRM ) ? "FIRM image options..." :
|
(filetype & SYS_FIRM ) ? "FIRM image options..." :
|
||||||
(filetype & SYS_TICKDB) ? "Mount as ticket.db" :
|
(filetype & SYS_TICKDB) ? (tik_buildable) ? "Ticket.db options..." : "Mount as ticket.db" :
|
||||||
|
(filetype & BIN_TIKDB) ? "Titlekey options..." :
|
||||||
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
|
(filetype & BIN_NCCHNFO)? "NCCHinfo options..." :
|
||||||
(filetype & BIN_LAUNCH) ? "Launch as arm9 payload" : "???";
|
(filetype & BIN_LAUNCH) ? "Launch as arm9 payload" : "???";
|
||||||
optionstr[hexviewer-1] = "Show in Hexeditor";
|
optionstr[hexviewer-1] = "Show in Hexeditor";
|
||||||
@ -795,8 +799,10 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
int ebackup = (ebackupable) ? ++n_opt : -1;
|
int ebackup = (ebackupable) ? ++n_opt : -1;
|
||||||
int decrypt = (decryptable) ? ++n_opt : -1;
|
int decrypt = (decryptable) ? ++n_opt : -1;
|
||||||
int encrypt = (encryptable) ? ++n_opt : -1;
|
int encrypt = (encryptable) ? ++n_opt : -1;
|
||||||
int build = (buildable) ? ++n_opt : -1;
|
int cia_build = (cia_buildable) ? ++n_opt : -1;
|
||||||
int build_legit = (buildable_legit) ? ++n_opt : -1;
|
int cia_build_legit = (cia_buildable_legit) ? ++n_opt : -1;
|
||||||
|
int tik_build_enc = (tik_buildable) ? ++n_opt : -1;
|
||||||
|
int tik_build_dec = (tik_buildable) ? ++n_opt : -1;
|
||||||
int verify = (verificable) ? ++n_opt : -1;
|
int verify = (verificable) ? ++n_opt : -1;
|
||||||
int ctrtransfer = (transferable) ? ++n_opt : -1;
|
int ctrtransfer = (transferable) ? ++n_opt : -1;
|
||||||
int hsinject = (hsinjectable) ? ++n_opt : -1;
|
int hsinject = (hsinjectable) ? ++n_opt : -1;
|
||||||
@ -809,8 +815,10 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
if (show_info > 0) optionstr[show_info-1] = "Show title info";
|
if (show_info > 0) optionstr[show_info-1] = "Show title info";
|
||||||
if (decrypt > 0) optionstr[decrypt-1] = (cryptable_inplace) ? "Decrypt file (...)" : "Decrypt file (" OUTPUT_PATH ")";
|
if (decrypt > 0) optionstr[decrypt-1] = (cryptable_inplace) ? "Decrypt file (...)" : "Decrypt file (" OUTPUT_PATH ")";
|
||||||
if (encrypt > 0) optionstr[encrypt-1] = (cryptable_inplace) ? "Encrypt file (...)" : "Encrypt file (" OUTPUT_PATH ")";
|
if (encrypt > 0) optionstr[encrypt-1] = (cryptable_inplace) ? "Encrypt file (...)" : "Encrypt file (" OUTPUT_PATH ")";
|
||||||
if (build > 0) optionstr[build-1] = (build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)";
|
if (cia_build > 0) optionstr[cia_build-1] = (cia_build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)";
|
||||||
if (build_legit > 0) optionstr[build_legit-1] = "Build CIA (legit)";
|
if (cia_build_legit > 0) optionstr[cia_build_legit-1] = "Build CIA (legit)";
|
||||||
|
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 (verify > 0) optionstr[verify-1] = "Verify file";
|
if (verify > 0) optionstr[verify-1] = "Verify file";
|
||||||
if (ctrtransfer > 0) optionstr[ctrtransfer-1] = "Transfer image to CTRNAND";
|
if (ctrtransfer > 0) optionstr[ctrtransfer-1] = "Transfer image to CTRNAND";
|
||||||
if (hsinject > 0) optionstr[hsinject-1] = "Inject to H&S";
|
if (hsinject > 0) optionstr[hsinject-1] = "Inject to H&S";
|
||||||
@ -930,8 +938,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
else ShowPrompt(false, "%s\nEncrypted to %s", pathstr, OUTPUT_PATH);
|
else ShowPrompt(false, "%s\nEncrypted to %s", pathstr, OUTPUT_PATH);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else if ((user_select == build) || (user_select == build_legit)) { // -> build CIA
|
} else if ((user_select == cia_build) || (user_select == cia_build_legit)) { // -> build CIA
|
||||||
bool force_legit = (user_select == build_legit);
|
bool force_legit = (user_select == cia_build_legit);
|
||||||
if ((n_marked > 1) && ShowPrompt(true, "Try to process all %lu selected files?", n_marked)) {
|
if ((n_marked > 1) && ShowPrompt(true, "Try to process all %lu selected files?", n_marked)) {
|
||||||
u32 n_success = 0;
|
u32 n_success = 0;
|
||||||
u32 n_other = 0;
|
u32 n_other = 0;
|
||||||
@ -998,6 +1006,33 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
(VerifyGameFile(curr_entry->path) == 0) ? "success" : "failed");
|
(VerifyGameFile(curr_entry->path) == 0) ? "success" : "failed");
|
||||||
}
|
}
|
||||||
return 0;
|
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);
|
||||||
|
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
|
||||||
|
ShowString("Building %s...", (dec) ? TIKDB_NAME_DEC : TIKDB_NAME_ENC);
|
||||||
|
if (n_marked > 1) {
|
||||||
|
u32 n_success = 0;
|
||||||
|
u32 n_other = 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 (!FTYPE_TIKBUILD(IdentifyFileType(path))) {
|
||||||
|
n_other++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current_dir->entry[i].marked = false;
|
||||||
|
if (BuildTitleKeyInfo(path, dec, false) == 0) n_success++; // ignore failures for now
|
||||||
|
}
|
||||||
|
if (BuildTitleKeyInfo(NULL, dec, true) == 0) {
|
||||||
|
if (n_other) ShowPrompt(false, "%s\n%lu/%lu files processed\n%lu/%lu files ignored",
|
||||||
|
path_out, n_success, n_marked, n_other, n_marked);
|
||||||
|
else ShowPrompt(false, "%s\n%lu/%lu files processed", path_out, n_success, n_marked);
|
||||||
|
} else ShowPrompt(false, "%s\nBuild database failed.");
|
||||||
|
} else ShowPrompt(false, "%s\nBuild database %s.", path_out,
|
||||||
|
(BuildTitleKeyInfo(curr_entry->path, dec, true) == 0) ? "success" : "failed");
|
||||||
|
return 0;
|
||||||
} else if (user_select == show_info) { // -> Show title info
|
} else if (user_select == show_info) { // -> Show title info
|
||||||
if (ShowGameFileTitleInfo(curr_entry->path) != 0)
|
if (ShowGameFileTitleInfo(curr_entry->path) != 0)
|
||||||
ShowPrompt(false, "Title info: not found");
|
ShowPrompt(false, "Title info: not found");
|
||||||
@ -1019,7 +1054,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur
|
|||||||
(InjectHealthAndSafety(curr_entry->path, destdrv[user_select-1]) == 0) ? "success" : "failed");
|
(InjectHealthAndSafety(curr_entry->path, destdrv[user_select-1]) == 0) ? "success" : "failed");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else if (user_select == ctrtransfer) { // -> adapt CTRNAND image to SysNAND
|
} else if (user_select == ctrtransfer) { // -> transfer CTRNAND image to SysNAND
|
||||||
char* destdrv[2] = { NULL };
|
char* destdrv[2] = { NULL };
|
||||||
n_opt = 0;
|
n_opt = 0;
|
||||||
if (DriveType("1:")) {
|
if (DriveType("1:")) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user