From f3322bd003062f2333d5aaf2d1d62bb341bf9f63 Mon Sep 17 00:00:00 2001 From: Aurora Date: Fri, 4 Nov 2016 22:28:33 +0100 Subject: [PATCH] Fix config derp, remove 0key encryption/nand ncch encryption/CIA dev common key checks on retail consoles --- injector/source/patcher.c | 14 +++--- source/config.c | 2 +- source/crypto.c | 32 +++++++------ source/firm.c | 13 +++++- source/patches.c | 98 +++++++++++++++++++++++++++++++-------- source/patches.h | 5 +- 6 files changed, 120 insertions(+), 44 deletions(-) diff --git a/injector/source/patcher.c b/injector/source/patcher.c index 4c4f84a..8213db9 100644 --- a/injector/source/patcher.c +++ b/injector/source/patcher.c @@ -59,7 +59,7 @@ static inline void loadCFWInfo(void) } } -static bool secureInfoExists(void) +static inline bool secureInfoExists(void) { static bool exists = false; @@ -76,7 +76,7 @@ static bool secureInfoExists(void) return exists; } -static void loadCustomVerString(u16 *out, u32 *verStringSize, u32 currentNand) +static inline void loadCustomVerString(u16 *out, u32 *verStringSize, u32 currentNand) { static const char *paths[] = { "/luma/customversion_sys.txt", "/luma/customversion_emu.txt", @@ -134,7 +134,7 @@ static void loadCustomVerString(u16 *out, u32 *verStringSize, u32 currentNand) } } -static void loadTitleCodeSection(u64 progId, u8 *code, u32 size) +static inline void loadTitleCodeSection(u64 progId, u8 *code, u32 size) { /* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin" If it exists it should be a decompressed binary code file */ @@ -160,7 +160,7 @@ static void loadTitleCodeSection(u64 progId, u8 *code, u32 size) } } -static void loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) +static inline void loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) { /* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt" If it exists it should contain, for example, "EUR IT" */ @@ -209,7 +209,7 @@ static void loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) } } -static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset) +static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset) { /* HANS: Look for error code which is known to be stored near cfg:u handle @@ -249,7 +249,7 @@ static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset) return NULL; } -static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos) +static inline void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos) { u8 *CFGU_GetConfigInfoBlk2_startPos; //Let's find STMFD SP (there might be a NOP before, but nevermind) @@ -297,7 +297,7 @@ static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetC } } -static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOffset) +static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOffset) { for(u8 *cmdPos = code; cmdPos < code + size - 28; cmdPos += 4) { diff --git a/source/config.c b/source/config.c index 2a539cf..e5d66df 100644 --- a/source/config.c +++ b/source/config.c @@ -373,7 +373,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) } //Preserve the last-used boot options (first 9 bits) - configData.config &= 0x1FF; + configData.config &= 0xFF; //Parse and write the new configuration for(u32 i = 0; i < multiOptionsAmount; i++) diff --git a/source/crypto.c b/source/crypto.c index 43120ad..1fa5d6d 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -383,16 +383,19 @@ int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf) void set6x7xKeys(void) { - const u8 __attribute__((aligned(4))) keyX0x25[AES_BLOCK_SIZE] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3}; - const u8 __attribute__((aligned(4))) keyY0x2F[AES_BLOCK_SIZE] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16}; + if(!ISDEVUNIT) + { + const u8 __attribute__((aligned(4))) keyX0x25[AES_BLOCK_SIZE] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3}; + const u8 __attribute__((aligned(4))) keyY0x2F[AES_BLOCK_SIZE] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16}; - aes_setkey(0x25, keyX0x25, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); - aes_setkey(0x2F, keyY0x2F, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_setkey(0x25, keyX0x25, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_setkey(0x2F, keyY0x2F, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); - /* [3dbrew] The first 0x10-bytes are checked by the v6.0/v7.0 NATIVE_FIRM keyinit function, - when non-zero it clears this block and continues to do the key generation. - Otherwise when this block was already all-zero, it immediately returns. */ - memset32((void *)0x01FFCD00, 0, 0x10); + /* [3dbrew] The first 0x10-bytes are checked by the v6.0/v7.0 NATIVE_FIRM keyinit function, + when non-zero it clears this block and continues to do the key generation. + Otherwise when this block was already all-zero, it immediately returns. */ + memset32((void *)0x01FFCD00, 0, 0x10); + } } bool decryptExeFs(Cxi *cxi) @@ -470,12 +473,15 @@ void kernel9Loader(Arm9Bin *arm9Section) u32 *startOfArm9Bin = (u32 *)((u8 *)arm9Section + 0x800); bool needToDecrypt = *startOfArm9Bin != 0x47704770 && *startOfArm9Bin != 0xB0862000; - if(!ISDEVUNIT && (k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt))) + if(k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt)) { - //Set 0x11 keyslot - const u8 __attribute__((aligned(4))) key1[AES_BLOCK_SIZE] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}; - const u8 __attribute__((aligned(4))) key2[AES_BLOCK_SIZE] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0}; - aes_setkey(0x11, k9lVersion == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); + if(!ISDEVUNIT) + { + //Set 0x11 keyslot + const u8 __attribute__((aligned(4))) key1[AES_BLOCK_SIZE] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}; + const u8 __attribute__((aligned(4))) key2[AES_BLOCK_SIZE] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0}; + aes_setkey(0x11, k9lVersion == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); + } } if(needToDecrypt) diff --git a/source/firm.c b/source/firm.c index 386eb1c..2e15c5b 100755 --- a/source/firm.c +++ b/source/firm.c @@ -104,6 +104,7 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora { if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot."); if(!decryptExeFs((Cxi *)firm)) error("The CTRNAND FIRM is corrupted."); + if(ISDEVUNIT) firmVersion = 0xFFFFFFFF; } return firmVersion; @@ -122,7 +123,7 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo } //Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH or a dev unit - else if(!ISA9LH && !ISFIRMLAUNCH && firmVersion >= 0x29 && !ISDEVUNIT) set6x7xKeys(); + else if(!ISA9LH && !ISFIRMLAUNCH && firmVersion >= 0x29) set6x7xKeys(); //Find the Process9 .code location, size and memory address u32 process9Size, @@ -145,12 +146,20 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo //Apply EmuNAND patches if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, emuHeader, firm->section[2].address); - //Apply FIRM0/1 writes patches on sysNAND to protect A9LH + //Apply FIRM0/1 writes patches on SysNAND to protect A9LH else if(isA9lhInstalled) ret += patchFirmWrites(process9Offset, process9Size); //Apply firmlaunch patches ret += patchFirmlaunches(process9Offset, process9Size, process9MemAddr); + //Apply dev unit check patches related to NCCH and CIA encryption + if(!ISDEVUNIT) + { + ret += patchZeroKeyNcchEncryptionCheck(process9Offset, process9Size); + ret += patchNandNcchEncryptionCheck(process9Offset, process9Size); + ret += patchCheckForDevCommonKey(process9Offset, process9Size); + } + //11.0 FIRM patches if(firmVersion >= (ISN3DS ? 0x21 : 0x52)) { diff --git a/source/patches.c b/source/patches.c index f406b67..f49c3d4 100644 --- a/source/patches.c +++ b/source/patches.c @@ -206,6 +206,84 @@ u32 patchOldFirmWrites(u8 *pos, u32 size) return ret; } +u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion) +{ + const u8 pattern[] = {0xFF, 0x00, 0x00, 0x02}; + u32 ret; + + u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); + + if(off == NULL) ret = firmVersion == 0xFFFFFFFF ? 0 : 1; + else + { + off++; + + memset32(off, 0, 8); //Zero out the first TitleID in the list + + ret = 0; + } + + return ret; +} + +u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x28, 0x2A, 0xD0, 0x08}; + u32 ret; + + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + + if(temp == NULL) ret = 1; + else + { + u16 *off = (u16 *)(temp - 1); + + *off = 0x2001; //mov r0, #1 + + ret = 0; + } + + return ret; +} + +u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x07, 0xD1, 0x28, 0x7A}; + u32 ret; + + u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); + + if(off == NULL) ret = 1; + else + { + off--; + + *off = 0x2001; //mov r0, #1 + + ret = 0; + } + + return ret; +} + +u32 patchCheckForDevCommonKey(u8 *pos, u32 size) +{ + const u8 pattern[] = {0x03, 0x7C, 0x28, 0x00}; + u32 ret; + + u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); + + if(off == NULL) ret = 1; + else + { + *off = 0x2301; //mov r3, #1 + + ret = 0; + } + + return ret; +} + u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space) { u32 ret = 0; @@ -291,26 +369,6 @@ u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **free return ret; } -u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion) -{ - const u8 pattern[] = {0xFF, 0x00, 0x00, 0x02}; - u32 ret; - - u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); - - if(off == NULL) ret = firmVersion == 0xFFFFFFFF ? 0 : 1; - else - { - off++; - - memset32(off, 0, 8); //Zero out the first TitleID in the list - - ret = 0; - } - - return ret; -} - u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) { const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C}; diff --git a/source/patches.h b/source/patches.h index 299bdc4..533ca93 100644 --- a/source/patches.h +++ b/source/patches.h @@ -37,10 +37,13 @@ extern CfgData configData; u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr); u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage); u32 patchSignatureChecks(u8 *pos, u32 size); -u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion); u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr); u32 patchFirmWrites(u8 *pos, u32 size); u32 patchOldFirmWrites(u8 *pos, u32 size); +u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion); +u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size); +u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size); +u32 patchCheckForDevCommonKey(u8 *pos, u32 size); u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space); u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode); u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);