diff --git a/arm9/source/common/common.h b/arm9/source/common/common.h index 1bf25b6..583fb92 100644 --- a/arm9/source/common/common.h +++ b/arm9/source/common/common.h @@ -33,11 +33,8 @@ #define STATIC_ASSERT(...) \ _Static_assert((__VA_ARGS__), #__VA_ARGS__) - -// input / output paths -#define SUPPORT_PATH "0:/gm9/support" -#define SCRIPT_PATH "0:/gm9/scripts" -#define PAYLOAD_PATH "0:/gm9/payloads" + +// standard output path (support file paths are in support.h) #define OUTPUT_PATH "0:/gm9/out" // buffer area defines (in use by godmode.c) diff --git a/arm9/source/crypto/keydb.c b/arm9/source/crypto/keydb.c index 30e3ba7..5892e58 100644 --- a/arm9/source/crypto/keydb.c +++ b/arm9/source/crypto/keydb.c @@ -2,7 +2,7 @@ #include "aes.h" #include "sha.h" #include "ff.h" -#include "vram0.h" +#include "support.h" typedef struct { u8 slot; // keyslot, 0x00...0x39 @@ -120,19 +120,7 @@ u32 LoadKeyDb(const char* path_db, AesKeyInfo* keydb, u32 bsize) { fsize = 0; f_close(&fp); } - } else { - // 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); - } - } + } else fsize = LoadSupportFile(KEYDB_NAME, keydb, bsize); // load key database support file u32 nkeys = 0; 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 if (!found && (type != 'I')) { - char path[64]; - FIL fp; - UINT btr; - snprintf(path, 64, "%s/slot0x%02lXKey%s%s.bin", SUPPORT_PATH, keyslot, + char fname[64]; + snprintf(fname, 64, "slot0x%02lXKey%s%s.bin", keyslot, (type == 'X') ? "X" : (type == 'Y') ? "Y" : (type == 'I') ? "IV" : "", (id) ? id : ""); - if (f_open(&fp, path, FA_READ | FA_OPEN_EXISTING) == FR_OK) { - found = ((f_read(&fp, key, 16, &btr) == FR_OK) && (btr == 16)); - f_close(&fp); - } + found = (LoadSupportFile(fname, key, 16) == 16); } // key still not found (duh) @@ -254,7 +237,7 @@ u32 InitKeyDb(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 const u8 recommended_sha[0x20] = { 0x40, 0x76, 0x54, 0x3D, 0xA3, 0xFF, 0x91, 0x1C, 0xE1, 0xCC, 0x4E, 0xC7, 0x2F, 0x92, 0xE4, 0xB7, diff --git a/arm9/source/filesys/support.c b/arm9/source/filesys/support.c new file mode 100644 index 0000000..7e7a544 --- /dev/null +++ b/arm9/source/filesys/support.c @@ -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); +} diff --git a/arm9/source/filesys/support.h b/arm9/source/filesys/support.h new file mode 100644 index 0000000..4ef5d26 --- /dev/null +++ b/arm9/source/filesys/support.h @@ -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); diff --git a/arm9/source/game/ncch.c b/arm9/source/game/ncch.c index 9b28074..6311f13 100644 --- a/arm9/source/game/ncch.c +++ b/arm9/source/game/ncch.c @@ -1,4 +1,5 @@ #include "ncch.h" +#include "support.h" #include "keydb.h" #include "aes.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 u64 titleId = ncch->programId; u32 hash_seed = ncch->hash_seed; - - UINT btr = 0; - FIL file; - char path[128]; u32 sha256sum[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 const u32 seed_offset[2] = {SEEDSAVE_AREA_OFFSETS}; 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 u8 movable_keyy[16]; 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 - if (f_open(&file, SUPPORT_PATH "/" SEEDDB_NAME, FA_READ | FA_OPEN_EXISTING) == FR_OK) { - SeedInfo* seeddb = (SeedInfo*) (TEMP_BUFFER + (TEMP_BUFFER_SIZE/2)); - f_read(&file, seeddb, TEMP_BUFFER_SIZE / 2, &btr); - f_close(&file); - if (seeddb->n_entries <= (btr - 16) / 32) { // check filesize / seeddb size - for (u32 s = 0; s < seeddb->n_entries; s++) { - if (titleId != seeddb->entries[s].titleId) - continue; - memcpy(lseed, seeddb->entries[s].seed, 16); - sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); - if (hash_seed == sha256sum[0]) { - memcpy(seed, lseed, 16); - return 0; // found! - } + SeedInfo* seeddb = (SeedInfo*) (TEMP_BUFFER + (TEMP_BUFFER_SIZE/2)); + size_t len = LoadSupportFile(SEEDDB_NAME, seeddb, (TEMP_BUFFER_SIZE/2)); + if (len && (seeddb->n_entries <= (len - 16) / 32)) { // check filesize / seeddb size + for (u32 s = 0; s < seeddb->n_entries; s++) { + if (titleId != seeddb->entries[s].titleId) + continue; + memcpy(lseed, seeddb->entries[s].seed, 16); + sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); + if (hash_seed == sha256sum[0]) { + memcpy(seed, lseed, 16); + return 0; // found! } } } diff --git a/arm9/source/game/ticket.c b/arm9/source/game/ticket.c index 4b462be..aa49343 100644 --- a/arm9/source/game/ticket.c +++ b/arm9/source/game/ticket.c @@ -1,4 +1,5 @@ #include "ticket.h" +#include "support.h" #include "unittype.h" #include "aes.h" #include "sha.h" @@ -106,15 +107,10 @@ u32 FindTitleKey(Ticket* ticket, u8* title_id) { // when found, add it to the ticket for (u32 enc = 0; (enc <= 1) && !found; enc++) { TitleKeysInfo* tikdb = (TitleKeysInfo*) (TEMP_BUFFER + (TEMP_BUFFER_SIZE/2)); - const char* path = (enc) ? SUPPORT_PATH "/" TIKDB_NAME_ENC : SUPPORT_PATH "/" TIKDB_NAME_DEC; - FIL file; - UINT btr; + u32 len = LoadSupportFile((enc) ? TIKDB_NAME_ENC : TIKDB_NAME_DEC, tikdb, (TEMP_BUFFER_SIZE/2)); - if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) - continue; - f_read(&file, tikdb, TEMP_BUFFER_SIZE / 2, &btr); - f_close(&file); - if (tikdb->n_entries > (btr - 16) / 32) + if (len == 0) continue; // file not found + if (tikdb->n_entries > (len - 16) / 32) continue; // filesize / titlekey db size mismatch for (u32 t = 0; t < tikdb->n_entries; t++) { TitleKeyEntry* tik = tikdb->entries + t; diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index e92fb74..9b4b8fb 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -1,4 +1,5 @@ #include "godmode.h" +#include "support.h" #include "ui.h" #include "hid.h" #include "fs.h" @@ -1843,9 +1844,9 @@ u32 GodMode(int entrypoint) { bootloader = true; } else if (user_select == 2) { 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); - } 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); } else if (user_select == 5) { exit_mode = GODMODE_EXIT_POWEROFF; @@ -2228,8 +2229,8 @@ u32 GodMode(int entrypoint) { u32 n_opt = 0; int poweroff = ++n_opt; int reboot = ++n_opt; - int scripts = (PathExist(SCRIPT_PATH)) ? (int) ++n_opt : -1; - int payloads = (PathExist(PAYLOAD_PATH)) ? (int) ++n_opt : -1; + int scripts = (CheckSupportDir(SCRIPTS_DIR)) ? (int) ++n_opt : -1; + int payloads = (CheckSupportDir(PAYLOADS_DIR)) ? (int) ++n_opt : -1; int more = ++n_opt; if (poweroff > 0) optionstr[poweroff - 1] = "Poweroff system"; if (reboot > 0) optionstr[reboot - 1] = "Reboot system"; @@ -2242,12 +2243,12 @@ u32 GodMode(int entrypoint) { (user_select != poweroff) && (user_select != reboot)) { char loadpath[256]; 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); GetDirContents(current_dir, current_path); ClearScreenF(true, true, COLOR_STD_BG); 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); } }