Rewritten support file handling

Support files are now also accepted from CTRNAND.
This commit is contained in:
d0k3 2017-12-11 02:47:29 +01:00
parent d8521dfdb9
commit 1a63575caa
7 changed files with 124 additions and 61 deletions

View File

@ -34,10 +34,7 @@
#define STATIC_ASSERT(...) \ #define STATIC_ASSERT(...) \
_Static_assert((__VA_ARGS__), #__VA_ARGS__) _Static_assert((__VA_ARGS__), #__VA_ARGS__)
// input / output paths // standard output path (support file paths are in support.h)
#define SUPPORT_PATH "0:/gm9/support"
#define SCRIPT_PATH "0:/gm9/scripts"
#define PAYLOAD_PATH "0:/gm9/payloads"
#define OUTPUT_PATH "0:/gm9/out" #define OUTPUT_PATH "0:/gm9/out"
// buffer area defines (in use by godmode.c) // buffer area defines (in use by godmode.c)

View File

@ -2,7 +2,7 @@
#include "aes.h" #include "aes.h"
#include "sha.h" #include "sha.h"
#include "ff.h" #include "ff.h"
#include "vram0.h" #include "support.h"
typedef struct { typedef struct {
u8 slot; // keyslot, 0x00...0x39 u8 slot; // keyslot, 0x00...0x39
@ -120,19 +120,7 @@ u32 LoadKeyDb(const char* path_db, AesKeyInfo* keydb, u32 bsize) {
fsize = 0; fsize = 0;
f_close(&fp); f_close(&fp);
} }
} else { } else fsize = LoadSupportFile(KEYDB_NAME, keydb, bsize); // load key database support file
// check for hardcoded key database
u64 aeskeydb_bin_size = 0;
void* aeskeydb_bin = FindVTarFileInfo(KEYDB_NAME, &aeskeydb_bin_size);
fsize = (aeskeydb_bin_size <= bsize) ? aeskeydb_bin_size : 0;
if (fsize) memcpy(keydb, aeskeydb_bin, aeskeydb_bin_size);
// try to load aeskeydb.bin file
if (f_open(&fp, SUPPORT_PATH "/" KEYDB_NAME, FA_READ | FA_OPEN_EXISTING) == FR_OK) {
if ((f_read(&fp, keydb, bsize, &fsize) != FR_OK) || (fsize >= bsize)) fsize = 0;
f_close(&fp);
}
}
u32 nkeys = 0; u32 nkeys = 0;
if (fsize && !(fsize % sizeof(AesKeyInfo))) if (fsize && !(fsize % sizeof(AesKeyInfo)))
@ -173,15 +161,10 @@ u32 LoadKeyFromFile(void* key, u32 keyslot, char type, char* id)
// load legacy slot0x??Key?.bin file instead // load legacy slot0x??Key?.bin file instead
if (!found && (type != 'I')) { if (!found && (type != 'I')) {
char path[64]; char fname[64];
FIL fp; snprintf(fname, 64, "slot0x%02lXKey%s%s.bin", keyslot,
UINT btr;
snprintf(path, 64, "%s/slot0x%02lXKey%s%s.bin", SUPPORT_PATH, keyslot,
(type == 'X') ? "X" : (type == 'Y') ? "Y" : (type == 'I') ? "IV" : "", (id) ? id : ""); (type == 'X') ? "X" : (type == 'Y') ? "Y" : (type == 'I') ? "IV" : "", (id) ? id : "");
if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING) == FR_OK) { found = (LoadSupportFile(fname, key, 16) == 16);
found = ((f_read(&fp, key, 16, &btr) == FR_OK) && (btr == 16));
f_close(&fp);
}
} }
// key still not found (duh) // key still not found (duh)
@ -254,7 +237,7 @@ u32 InitKeyDb(const char* path)
u32 CheckRecommendedKeyDb(const char* path) u32 CheckRecommendedKeyDb(const char* path)
{ {
// SHA-256 of the reommended aeskeydb.bin file // SHA-256 of the recommended aeskeydb.bin file
// equals MD5 A5B28945A7C051D7A0CD18AF0E580D1B // equals MD5 A5B28945A7C051D7A0CD18AF0E580D1B
const u8 recommended_sha[0x20] = { const u8 recommended_sha[0x20] = {
0x40, 0x76, 0x54, 0x3D, 0xA3, 0xFF, 0x91, 0x1C, 0xE1, 0xCC, 0x4E, 0xC7, 0x2F, 0x92, 0xE4, 0xB7, 0x40, 0x76, 0x54, 0x3D, 0xA3, 0xFF, 0x91, 0x1C, 0xE1, 0xCC, 0x4E, 0xC7, 0x2F, 0x92, 0xE4, 0xB7,

View File

@ -0,0 +1,75 @@
#include "support.h"
#include "fsutil.h" // only for file selector
#include "vram0.h"
#include "vff.h"
#define SUPPORT_FILE_PATHS "0:/gm9/support", "1:/gm9/support" // we also check the VRAM TAR first
#define SUPPORT_DIR_PATHS "V:", "0:/gm9", "1:/gm9"
bool CheckSupportFile(const char* fname)
{
// try VRAM0 first
if (FindVTarFileInfo(fname, NULL))
return true;
// try support file paths
const char* base_paths[] = { SUPPORT_FILE_PATHS };
for (u32 i = 0; i < countof(base_paths); i++) {
char path[256];
snprintf(path, 256, "%s/%s", base_paths[i], fname);
if (fvx_stat(path, NULL) == FR_OK)
return true;
}
return false;
}
size_t LoadSupportFile(const char* fname, void* buffer, size_t max_len)
{
// try VRAM0 first
u64 len64 = 0;
void* data = FindVTarFileInfo(fname, &len64);
if (data && len64 && (len64 < max_len)) {
memcpy(buffer, data, len64);
return (size_t) len64;
}
// try support file paths
const char* base_paths[] = { SUPPORT_FILE_PATHS };
for (u32 i = 0; i < countof(base_paths); i++) {
UINT len32;
char path[256];
snprintf(path, 256, "%s/%s", base_paths[i], fname);
if (fvx_qread(path, buffer, 0, max_len, &len32) == FR_OK)
return len32;
}
return 0;
}
bool GetSupportDir(char* path, const char* dname)
{
const char* base_paths[] = { SUPPORT_DIR_PATHS };
for (u32 i = 0; i < countof(base_paths); i++) {
FILINFO fno;
snprintf(path, 256, "%s/%s", base_paths[i], dname);
if ((fvx_stat(path, &fno) == FR_OK) && (fno.fattrib & AM_DIR))
return true;
}
return false;
}
bool CheckSupportDir(const char* dname)
{
char path[256];
return GetSupportDir(path, dname);
}
bool FileSelectorSupport(char* result, const char* text, const char* dname, const char* pattern, bool hide_ext, bool no_dirs)
{
char path[256];
if (!GetSupportDir(path, dname)) return false;
return FileSelector(result, text, path, pattern, hide_ext, no_dirs);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "common.h"
// scripts / payloads dir names
#define SCRIPTS_DIR "scripts"
#define PAYLOADS_DIR "payloads"
bool CheckSupportFile(const char* fname);
size_t LoadSupportFile(const char* fname, void* buffer, size_t max_len);
bool CheckSupportDir(const char* fpath);
bool FileSelectorSupport(char* result, const char* text, const char* dname, const char* pattern, bool hide_ext, bool no_dirs);

View File

@ -1,4 +1,5 @@
#include "ncch.h" #include "ncch.h"
#include "support.h"
#include "keydb.h" #include "keydb.h"
#include "aes.h" #include "aes.h"
#include "sha.h" #include "sha.h"
@ -53,10 +54,6 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) {
static u8 lseed[16+8] = { 0 }; // seed plus title ID for easy validation static u8 lseed[16+8] = { 0 }; // seed plus title ID for easy validation
u64 titleId = ncch->programId; u64 titleId = ncch->programId;
u32 hash_seed = ncch->hash_seed; u32 hash_seed = ncch->hash_seed;
UINT btr = 0;
FIL file;
char path[128];
u32 sha256sum[8]; u32 sha256sum[8];
memcpy(lseed+16, &(ncch->programId), 8); memcpy(lseed+16, &(ncch->programId), 8);
@ -69,7 +66,11 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) {
// 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 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 < (sizeof(nand_drv)/sizeof(char*)); i++) { for (u32 i = 0; i < countof(nand_drv); i++) {
UINT btr = 0;
FIL file;
char path[128];
// grab the key Y from movable.sed // grab the key Y from movable.sed
u8 movable_keyy[16]; u8 movable_keyy[16];
snprintf(path, 128, "%s/private/movable.sed", nand_drv[i]); snprintf(path, 128, "%s/private/movable.sed", nand_drv[i]);
@ -118,20 +119,17 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) {
} }
// not found -> try seeddb.bin // not found -> try seeddb.bin
if (f_open(&file, SUPPORT_PATH "/" SEEDDB_NAME, FA_READ | FA_OPEN_EXISTING) == FR_OK) { SeedInfo* seeddb = (SeedInfo*) (TEMP_BUFFER + (TEMP_BUFFER_SIZE/2));
SeedInfo* seeddb = (SeedInfo*) (TEMP_BUFFER + (TEMP_BUFFER_SIZE/2)); size_t len = LoadSupportFile(SEEDDB_NAME, seeddb, (TEMP_BUFFER_SIZE/2));
f_read(&file, seeddb, TEMP_BUFFER_SIZE / 2, &btr); if (len && (seeddb->n_entries <= (len - 16) / 32)) { // check filesize / seeddb size
f_close(&file); for (u32 s = 0; s < seeddb->n_entries; s++) {
if (seeddb->n_entries <= (btr - 16) / 32) { // check filesize / seeddb size if (titleId != seeddb->entries[s].titleId)
for (u32 s = 0; s < seeddb->n_entries; s++) { continue;
if (titleId != seeddb->entries[s].titleId) memcpy(lseed, seeddb->entries[s].seed, 16);
continue; sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE);
memcpy(lseed, seeddb->entries[s].seed, 16); if (hash_seed == sha256sum[0]) {
sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); memcpy(seed, lseed, 16);
if (hash_seed == sha256sum[0]) { return 0; // found!
memcpy(seed, lseed, 16);
return 0; // found!
}
} }
} }
} }

View File

@ -1,4 +1,5 @@
#include "ticket.h" #include "ticket.h"
#include "support.h"
#include "unittype.h" #include "unittype.h"
#include "aes.h" #include "aes.h"
#include "sha.h" #include "sha.h"
@ -106,15 +107,10 @@ u32 FindTitleKey(Ticket* ticket, u8* title_id) {
// when found, add it to the ticket // when found, add it to the ticket
for (u32 enc = 0; (enc <= 1) && !found; enc++) { for (u32 enc = 0; (enc <= 1) && !found; enc++) {
TitleKeysInfo* tikdb = (TitleKeysInfo*) (TEMP_BUFFER + (TEMP_BUFFER_SIZE/2)); TitleKeysInfo* tikdb = (TitleKeysInfo*) (TEMP_BUFFER + (TEMP_BUFFER_SIZE/2));
const char* path = (enc) ? SUPPORT_PATH "/" TIKDB_NAME_ENC : SUPPORT_PATH "/" TIKDB_NAME_DEC; u32 len = LoadSupportFile((enc) ? TIKDB_NAME_ENC : TIKDB_NAME_DEC, tikdb, (TEMP_BUFFER_SIZE/2));
FIL file;
UINT btr;
if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) if (len == 0) continue; // file not found
continue; if (tikdb->n_entries > (len - 16) / 32)
f_read(&file, tikdb, TEMP_BUFFER_SIZE / 2, &btr);
f_close(&file);
if (tikdb->n_entries > (btr - 16) / 32)
continue; // filesize / titlekey db size mismatch continue; // filesize / titlekey db size mismatch
for (u32 t = 0; t < tikdb->n_entries; t++) { for (u32 t = 0; t < tikdb->n_entries; t++) {
TitleKeyEntry* tik = tikdb->entries + t; TitleKeyEntry* tik = tikdb->entries + t;

View File

@ -1,4 +1,5 @@
#include "godmode.h" #include "godmode.h"
#include "support.h"
#include "ui.h" #include "ui.h"
#include "hid.h" #include "hid.h"
#include "fs.h" #include "fs.h"
@ -1843,9 +1844,9 @@ u32 GodMode(int entrypoint) {
bootloader = true; bootloader = true;
} else if (user_select == 2) { } else if (user_select == 2) {
godmode9 = true; godmode9 = true;
} else if ((user_select == 3) && (FileSelector(loadpath, "Bootloader payloads menu.\nSelect payload:", PAYLOAD_PATH, "*.firm", true, false))) { } else if ((user_select == 3) && (FileSelectorSupport(loadpath, "Bootloader payloads menu.\nSelect payload:", PAYLOADS_DIR, "*.firm", true, false))) {
BootFirmHandler(loadpath, false, false); BootFirmHandler(loadpath, false, false);
} else if ((user_select == 4) && (FileSelector(loadpath, "Bootloader scripts menu.\nSelect script:", SCRIPT_PATH, "*.gm9", true, false))) { } else if ((user_select == 4) && (FileSelectorSupport(loadpath, "Bootloader scripts menu.\nSelect script:", SCRIPTS_DIR, "*.gm9", true, false))) {
ExecuteGM9Script(loadpath); ExecuteGM9Script(loadpath);
} else if (user_select == 5) { } else if (user_select == 5) {
exit_mode = GODMODE_EXIT_POWEROFF; exit_mode = GODMODE_EXIT_POWEROFF;
@ -2228,8 +2229,8 @@ u32 GodMode(int entrypoint) {
u32 n_opt = 0; u32 n_opt = 0;
int poweroff = ++n_opt; int poweroff = ++n_opt;
int reboot = ++n_opt; int reboot = ++n_opt;
int scripts = (PathExist(SCRIPT_PATH)) ? (int) ++n_opt : -1; int scripts = (CheckSupportDir(SCRIPTS_DIR)) ? (int) ++n_opt : -1;
int payloads = (PathExist(PAYLOAD_PATH)) ? (int) ++n_opt : -1; int payloads = (CheckSupportDir(PAYLOADS_DIR)) ? (int) ++n_opt : -1;
int more = ++n_opt; int more = ++n_opt;
if (poweroff > 0) optionstr[poweroff - 1] = "Poweroff system"; if (poweroff > 0) optionstr[poweroff - 1] = "Poweroff system";
if (reboot > 0) optionstr[reboot - 1] = "Reboot system"; if (reboot > 0) optionstr[reboot - 1] = "Reboot system";
@ -2242,12 +2243,12 @@ u32 GodMode(int entrypoint) {
(user_select != poweroff) && (user_select != reboot)) { (user_select != poweroff) && (user_select != reboot)) {
char loadpath[256]; char loadpath[256];
if ((user_select == more) && (HomeMoreMenu(current_path) == 0)) break; // more... menu if ((user_select == more) && (HomeMoreMenu(current_path) == 0)) break; // more... menu
else if ((user_select == scripts) && (FileSelector(loadpath, "HOME scripts... menu.\nSelect script:", SCRIPT_PATH, "*.gm9", true, false))) { else if ((user_select == scripts) && (FileSelectorSupport(loadpath, "HOME scripts... menu.\nSelect script:", SCRIPTS_DIR, "*.gm9", true, false))) {
ExecuteGM9Script(loadpath); ExecuteGM9Script(loadpath);
GetDirContents(current_dir, current_path); GetDirContents(current_dir, current_path);
ClearScreenF(true, true, COLOR_STD_BG); ClearScreenF(true, true, COLOR_STD_BG);
break; break;
} else if ((user_select == payloads) && (FileSelector(loadpath, "HOME payloads... menu.\nSelect payload:", PAYLOAD_PATH, "*.firm", true, false))) { } else if ((user_select == payloads) && (FileSelectorSupport(loadpath, "HOME payloads... menu.\nSelect payload:", PAYLOADS_DIR, "*.firm", true, false))) {
BootFirmHandler(loadpath, false, false); BootFirmHandler(loadpath, false, false);
} }
} }