From 762dce04cd77188b259e7df9a4f04d75e8e4bc83 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Tue, 22 Mar 2016 19:24:21 +0100 Subject: [PATCH] Properly check for slot0x05 crypto & EmuNAND availability --- source/fs.c | 9 ++++----- source/godmode.c | 11 ++++++++++- source/nand/nand.c | 41 ++++++++++++++++++++++++++++++++++------- source/nand/nand.h | 3 ++- source/nand/virtual.c | 12 ++++++++++++ source/nand/virtual.h | 1 + 6 files changed, 63 insertions(+), 14 deletions(-) diff --git a/source/fs.c b/source/fs.c index e081eb6..2df3a59 100644 --- a/source/fs.c +++ b/source/fs.c @@ -534,7 +534,7 @@ bool GetRootDirContentsWorker(DirStruct* contents) { "SYSNAND VIRTUAL", "EMUNAND VIRTUAL" }; static const char* drvnum[] = { - "0", "1", "2", "3", "4", "5", "6", "S", "E" + "0:", "1:", "2:", "3:", "4:", "5:", "6:", "S:", "E:" }; u32 n_entries = 0; @@ -542,11 +542,10 @@ bool GetRootDirContentsWorker(DirStruct* contents) { for (u32 pdrv = 0; (pdrv < MAX_FS+2) && (n_entries < MAX_ENTRIES); pdrv++) { DirEntry* entry = &(contents->entry[n_entries]); if ((pdrv < MAX_FS) && !fs_mounted[pdrv]) continue; - if ((pdrv == MAX_FS+0) && (!fs_mounted[1])) continue; - if ((pdrv == MAX_FS+1) && (!fs_mounted[4])) continue; + else if ((pdrv >= MAX_FS) && (!CheckVirtualPath(drvnum[pdrv]))) continue; memset(entry->path, 0x00, 64); - snprintf(entry->path + 0, 4, "%s:", drvnum[pdrv]); - snprintf(entry->path + 4, 32, "[%s:] %s", drvnum[pdrv], drvname[pdrv]); + snprintf(entry->path + 0, 4, drvnum[pdrv]); + snprintf(entry->path + 4, 32, "[%s] %s", drvnum[pdrv], drvname[pdrv]); entry->name = entry->path + 4; entry->size = GetTotalSpace(entry->path); entry->type = T_ROOT; diff --git a/source/godmode.c b/source/godmode.c index 2715009..d88f7c1 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -2,10 +2,11 @@ #include "draw.h" #include "hid.h" #include "fs.h" +#include "platform.h" #include "nand.h" #include "virtual.h" -#define VERSION "0.1.9" +#define VERSION "0.2.0" #define COLOR_TOP_BAR ((GetWritePermissions() == 0) ? COLOR_WHITE : (GetWritePermissions() == 1) ? COLOR_BRIGHTGREEN : (GetWritePermissions() == 2) ? COLOR_BRIGHTYELLOW : COLOR_RED) #define COLOR_SIDE_BAR COLOR_DARKGREY @@ -151,6 +152,14 @@ u32 GodMode() { InitNandCrypto(); InitNandFS(); + if ((GetUnitPlatform() == PLATFORM_N3DS) && !CheckSlot0x05Crypto()) { + if (!ShowPrompt(true, "Warning: slot0x05 crypto fail\nslot0x05keyY.bin is either corrupt\nor does not exist. Continue?")) { + DeinitNandFS(); + DeinitSDCardFS(); + return exit_mode; + } + } + GetDirContents(current_dir, ""); clipboard->n_entries = 0; while (true) { // this is the main loop diff --git a/source/nand/nand.c b/source/nand/nand.c index f080b99..c8c3f38 100644 --- a/source/nand/nand.c +++ b/source/nand/nand.c @@ -8,6 +8,12 @@ #define NAND_BUFFER ((u8*)0x21100000) #define NAND_BUFFER_SIZE (0x100000) // must be multiple of 0x200 +static u8 slot0x05KeyY[0x10] = { 0x00 }; // need to load this from file +static u8 slot0x05KeyY_sha256[0x20] = { // hash for slot0x05KeyY file + 0x98, 0x24, 0x27, 0x14, 0x22, 0xB0, 0x6B, 0xF2, 0x10, 0x96, 0x9C, 0x36, 0x42, 0x53, 0x7C, 0x86, + 0x62, 0x22, 0x5C, 0xFD, 0x6F, 0xAE, 0x9B, 0x0A, 0x85, 0xA5, 0xCE, 0x21, 0xAA, 0xB6, 0xC8, 0x4D +}; + static u8 nand_magic_n3ds[0x60] = { // NCSD NAND header N3DS magic 0x4E, 0x43, 0x53, 0x44, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, @@ -73,19 +79,39 @@ bool InitNandCrypto(void) use_aeskey(0x03); // part #3: CTRNAND N3DS KEY - if (GetUnitPlatform() == PLATFORM_N3DS) { - u8 CtrNandKeyY[16]; - - if (FileGetData("0:/slot0x05KeyY.bin", CtrNandKeyY, 16, 0)) { - setup_aeskeyY(0x05, CtrNandKeyY); - use_aeskey(0x05); - } + if (FileGetData("0:/slot0x05KeyY.bin", slot0x05KeyY, 16, 0)) { + setup_aeskeyY(0x05, slot0x05KeyY); + use_aeskey(0x05); } return true; } +bool CheckSlot0x05Crypto(void) +{ + // step #1 - check the slot0x05KeyY SHA-256 + u8 shasum[32]; + sha_init(SHA256_MODE); + sha_update(slot0x05KeyY, 16); + sha_get(shasum); + if (memcmp(shasum, slot0x05KeyY_sha256, 32) == 0) + return true; + + // step #2 - check actual CTRNAND magic + const u8 magic[8] = {0xE9, 0x00, 0x00, 0x43, 0x54, 0x52, 0x20, 0x20}; + const u32 sector = 0x05CAD7; + u8 buffer[0x200]; + for (u32 nand = 0; nand < 2; nand++) { + ReadNandSectors(buffer, sector, 1, 0x05, nand); + if (memcmp(buffer, magic, 8) == 0) + return true; + } + + // failed if we arrive here + return false; +} + void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot) { u32 mode = (sector >= (0x0B100000 / 0x200)) ? AES_CNT_CTRNAND_MODE : AES_CNT_TWLNAND_MODE; @@ -184,5 +210,6 @@ bool InitEmuNandBase(void) return true; if (GetPartitionOffsetSector("0:") > getMMCDevice(0)->total_size) + emunand_base_sector = 0x000000; // keep unknown EmuNAND as RedNAND only if space is low return false; } diff --git a/source/nand/nand.h b/source/nand/nand.h index b599d2d..f2b5405 100644 --- a/source/nand/nand.h +++ b/source/nand/nand.h @@ -8,8 +8,9 @@ #define NAND_TYPE_NO3DS (1<<2) bool InitNandCrypto(void); -void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot); +bool CheckSlot0x05Crypto(void); +void CryptNand(u8* buffer, u32 sector, u32 count, u32 keyslot); int ReadNandSectors(u8* buffer, u32 sector, u32 count, u32 keyslot, bool read_emunand); int WriteNandSectors(const u8* buffer, u32 sector, u32 count, u32 keyslot, bool write_emunand); diff --git a/source/nand/virtual.c b/source/nand/virtual.c index 68a0a0d..d118b2e 100644 --- a/source/nand/virtual.c +++ b/source/nand/virtual.c @@ -35,6 +35,16 @@ u32 IsVirtualPath(const char* path) { return 0; } +bool CheckVirtualPath(const char* path) { + u32 vp_nand = IsVirtualPath(path); + if (vp_nand == VRT_SYSNAND) { + return true; // this is safe because we re-check for slot0x05 crypto + } else if (vp_nand == VRT_EMUNAND) { + return GetNandSizeSectors(true); + } + return false; +} + bool FindVirtualFile(VirtualFile* vfile, const char* path) { char* fname = strchr(path, '/'); @@ -68,6 +78,8 @@ bool FindVirtualFile(VirtualFile* vfile, const char* path) memcpy(vfile, curr_template, sizeof(VirtualFile)); // process special flags + if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto()) + return false; // keyslot 0x05 not properly set up if (vfile->flags & VFLAG_NAND_SIZE) { if (on_emunand && (GetNandSizeSectors(false) != GetNandSizeSectors(true))) return false; // EmuNAND is too small diff --git a/source/nand/virtual.h b/source/nand/virtual.h index b84a533..336e7e6 100644 --- a/source/nand/virtual.h +++ b/source/nand/virtual.h @@ -22,6 +22,7 @@ typedef struct { } __attribute__((packed)) VirtualFile; u32 IsVirtualPath(const char* path); +bool CheckVirtualPath(const char* path); bool FindVirtualFile(VirtualFile* vfile, const char* path); int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count); int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count);