Fix config derp, remove 0key encryption/nand ncch encryption/CIA dev common key checks on retail consoles
This commit is contained in:
parent
cef947d67d
commit
f3322bd003
@ -59,7 +59,7 @@ static inline void loadCFWInfo(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool secureInfoExists(void)
|
static inline bool secureInfoExists(void)
|
||||||
{
|
{
|
||||||
static bool exists = false;
|
static bool exists = false;
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ static bool secureInfoExists(void)
|
|||||||
return exists;
|
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",
|
static const char *paths[] = { "/luma/customversion_sys.txt",
|
||||||
"/luma/customversion_emu.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"
|
/* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin"
|
||||||
If it exists it should be a decompressed binary code file */
|
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"
|
/* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt"
|
||||||
If it exists it should contain, for example, "EUR IT" */
|
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:
|
/* HANS:
|
||||||
Look for error code which is known to be stored near cfg:u handle
|
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;
|
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)
|
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)
|
for(u8 *cmdPos = code; cmdPos < code + size - 28; cmdPos += 4)
|
||||||
{
|
{
|
||||||
|
@ -373,7 +373,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Preserve the last-used boot options (first 9 bits)
|
//Preserve the last-used boot options (first 9 bits)
|
||||||
configData.config &= 0x1FF;
|
configData.config &= 0xFF;
|
||||||
|
|
||||||
//Parse and write the new configuration
|
//Parse and write the new configuration
|
||||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||||
|
@ -383,6 +383,8 @@ int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf)
|
|||||||
|
|
||||||
void set6x7xKeys(void)
|
void set6x7xKeys(void)
|
||||||
{
|
{
|
||||||
|
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))) 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};
|
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};
|
||||||
|
|
||||||
@ -393,6 +395,7 @@ void set6x7xKeys(void)
|
|||||||
when non-zero it clears this block and continues to do the key generation.
|
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. */
|
Otherwise when this block was already all-zero, it immediately returns. */
|
||||||
memset32((void *)0x01FFCD00, 0, 0x10);
|
memset32((void *)0x01FFCD00, 0, 0x10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool decryptExeFs(Cxi *cxi)
|
bool decryptExeFs(Cxi *cxi)
|
||||||
@ -470,13 +473,16 @@ void kernel9Loader(Arm9Bin *arm9Section)
|
|||||||
u32 *startOfArm9Bin = (u32 *)((u8 *)arm9Section + 0x800);
|
u32 *startOfArm9Bin = (u32 *)((u8 *)arm9Section + 0x800);
|
||||||
bool needToDecrypt = *startOfArm9Bin != 0x47704770 && *startOfArm9Bin != 0xB0862000;
|
bool needToDecrypt = *startOfArm9Bin != 0x47704770 && *startOfArm9Bin != 0xB0862000;
|
||||||
|
|
||||||
if(!ISDEVUNIT && (k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt)))
|
if(k9lVersion == 2 || (k9lVersion == 1 && needToDecrypt))
|
||||||
|
{
|
||||||
|
if(!ISDEVUNIT)
|
||||||
{
|
{
|
||||||
//Set 0x11 keyslot
|
//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))) 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};
|
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);
|
aes_setkey(0x11, k9lVersion == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(needToDecrypt)
|
if(needToDecrypt)
|
||||||
{
|
{
|
||||||
|
@ -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(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(!decryptExeFs((Cxi *)firm)) error("The CTRNAND FIRM is corrupted.");
|
||||||
|
if(ISDEVUNIT) firmVersion = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
return firmVersion;
|
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
|
//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
|
//Find the Process9 .code location, size and memory address
|
||||||
u32 process9Size,
|
u32 process9Size,
|
||||||
@ -145,12 +146,20 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
|
|||||||
//Apply EmuNAND patches
|
//Apply EmuNAND patches
|
||||||
if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, emuHeader, firm->section[2].address);
|
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);
|
else if(isA9lhInstalled) ret += patchFirmWrites(process9Offset, process9Size);
|
||||||
|
|
||||||
//Apply firmlaunch patches
|
//Apply firmlaunch patches
|
||||||
ret += patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
|
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
|
//11.0 FIRM patches
|
||||||
if(firmVersion >= (ISN3DS ? 0x21 : 0x52))
|
if(firmVersion >= (ISN3DS ? 0x21 : 0x52))
|
||||||
{
|
{
|
||||||
|
@ -206,6 +206,84 @@ u32 patchOldFirmWrites(u8 *pos, u32 size)
|
|||||||
return ret;
|
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 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space)
|
||||||
{
|
{
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
@ -291,26 +369,6 @@ u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **free
|
|||||||
return ret;
|
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)
|
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C};
|
const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C};
|
||||||
|
@ -37,10 +37,13 @@ extern CfgData configData;
|
|||||||
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
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 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage);
|
||||||
u32 patchSignatureChecks(u8 *pos, u32 size);
|
u32 patchSignatureChecks(u8 *pos, u32 size);
|
||||||
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion);
|
|
||||||
u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
||||||
u32 patchFirmWrites(u8 *pos, u32 size);
|
u32 patchFirmWrites(u8 *pos, u32 size);
|
||||||
u32 patchOldFirmWrites(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 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space);
|
||||||
u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode);
|
u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode);
|
||||||
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);
|
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);
|
||||||
|
Reference in New Issue
Block a user