Compare commits

..

27 Commits
v6.5 ... v6.6

Author SHA1 Message Date
Aurora
0b16d88756 Minor stuff 2016-11-12 14:17:42 +01:00
TuxSH
796cb31ed7 Update exceptions.c 2016-11-12 13:18:24 +01:00
Aurora
d7fd2f26c1 Revert "Add support for installing retail 0x3D[0] key-encrypted CIAs on dev units"
This reverts commit 5adb8749de.
2016-11-12 02:52:54 +01:00
TuxSH
5adb8749de Add support for installing retail 0x3D[0] key-encrypted CIAs on dev units
When "UNITINFO" is enabled
2016-11-12 02:14:35 +01:00
Aurora
3474faa4a2 Added support for dev units sysupdater FIRM (untested but should work) 2016-11-12 01:50:43 +01:00
Aurora
acd9c04ff6 Minor stuff 2016-11-11 18:31:38 +01:00
Aurora
833c9406b0 Make it possible to use the reboot patch with the payload on CTRNAND and no SD 2016-11-11 16:31:17 +01:00
Aurora
2f1253e27f Merge pull request #276 from SciresM/patch-1
Add devkit keys.
2016-11-11 15:56:57 +01:00
SciresM
53b847e31c Add devkit keys. 2016-11-11 06:55:29 -08:00
Aurora
7efa33dd7f It seems some games check just for the language 2016-11-11 04:04:12 +01:00
Aurora
4011970a57 Fix derp 2016-11-11 02:16:33 +01:00
TuxSH
a2cfa2be16 Fix same handling bug on arm9 2016-11-11 00:30:49 +01:00
Aurora
c4b691d688 Add another check 2016-11-10 22:41:51 +01:00
Aurora
72a7a8eee5 Minor stuff 2016-11-10 13:17:58 +01:00
Aurora
52d352385f Move dev common key patch to UNITINFO since it breaks SD retail encrypted CIAs 2016-11-10 13:10:02 +01:00
Aurora
c1f85650bd Minor stuff 2016-11-09 22:52:29 +01:00
Aurora
b830909504 Optimize function 2016-11-09 17:01:56 +01:00
Aurora
4ad6b1c220 Attempt to increase the compatibility of language emulation with some rare games, add checks for the functions 2016-11-09 16:33:54 +01:00
Aurora
429488a4ba Fixed New 3DS CPU patch overriding the CPU mode of N3DS exclusives/enhanced titles 2016-11-08 17:52:02 +01:00
Aurora
40c6cc11a5 Minor stuff 2016-11-06 14:52:10 +01:00
Aurora
594881c6ce Do things properly 2016-11-06 14:45:45 +01:00
Aurora
1cc64a0fbc Merge branch 'master' of https://github.com/AuroraWright/Luma3DS 2016-11-06 01:10:18 +01:00
Aurora
f492318e3c The cart update pattern is only present once on NS up to 8.0 2016-11-06 01:09:44 +01:00
TuxSH
4b06bb7795 Fix svcBreak handling bug 2016-11-06 00:05:12 +01:00
Aurora
f7e570383a Add dev unit check 2016-11-05 17:46:47 +01:00
Aurora
896a088199 Fix comment 2016-11-04 22:31:43 +01:00
Aurora
f3322bd003 Fix config derp, remove 0key encryption/nand ncch encryption/CIA dev common key checks on retail consoles 2016-11-04 22:28:33 +01:00
14 changed files with 389 additions and 249 deletions

View File

@@ -83,7 +83,8 @@ _commonHandler:
cps #0x13 @ switch to supervisor mode
cmp r10, #0
addne sp, #0x28
ldr r2, [sp, #0x1c] @ implementation details of the official svc handler
ldmfd sp, {r8-r11}^ @ implementation details of the official svc handler
ldr r2, [sp, #0x1c]
ldr r4, [sp, #0x18]
msr cpsr_c, r3 @ restore processor mode
tst r2, #0x20

View File

@@ -62,6 +62,7 @@ _commonHandler:
bic r5, r3, #0xf
orr r5, #0x3
msr cpsr_c, r5 @ switch to supervisor mode
ldmfd sp, {r8-r11}^
ldr r2, [sp, #0x1c] @ implementation details of the official svc handler
ldr r4, [sp, #0x18]
msr cpsr_c, r3 @ restore processor mode

View File

@@ -7,13 +7,15 @@
static CFWInfo info;
static void patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
{
for(u32 i = 0; i < count; i++)
u32 i;
for(i = 0; i < count; i++)
{
u8 *found = memsearch(start, pattern, size, patSize);
if(found == NULL) svcBreak(USERBREAK_ASSERT);
if(found == NULL) break;
memcpy(found + offset, replace, repSize);
@@ -24,6 +26,8 @@ static void patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, i
size -= at + patSize;
start = found + patSize;
}
return i;
}
static Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags)
@@ -59,7 +63,7 @@ static inline void loadCFWInfo(void)
}
}
static bool secureInfoExists(void)
static inline bool secureInfoExists(void)
{
static bool exists = false;
@@ -76,7 +80,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 +138,7 @@ static void loadCustomVerString(u16 *out, u32 *verStringSize, u32 currentNand)
}
}
static void loadTitleCodeSection(u64 progId, u8 *code, u32 size)
static inline u32 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 */
@@ -143,24 +147,27 @@ static void loadTitleCodeSection(u64 progId, u8 *code, u32 size)
progIdToStr(path + 35, progId);
IFile file;
u32 ret = 0;
if(R_SUCCEEDED(openLumaFile(&file, path)))
{
u64 fileSize;
if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize <= size)
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = 1;
else
{
u64 total;
IFile_Read(&file, &total, code, fileSize);
if(total != fileSize) svcBreak(USERBREAK_ASSERT);
if(R_FAILED(IFile_Read(&file, &total, code, fileSize)) || total != fileSize) ret = 1;
}
IFile_Close(&file);
}
return ret;
}
static void loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
static inline u32 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" */
@@ -169,19 +176,25 @@ static void loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
progIdToStr(path + 29, progId);
IFile file;
u32 ret = 0;
if(R_SUCCEEDED(openLumaFile(&file, path)))
{
u64 fileSize;
if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize > 5 && fileSize < 9)
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 6 || fileSize > 8) ret = 1;
else
{
char buf[fileSize];
u64 total;
if(R_SUCCEEDED(IFile_Read(&file, &total, buf, fileSize)))
if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) ret = 1;
else
{
for(u32 i = 0; i < 7; i++)
u32 i,
j;
for(i = 0; i < 7; i++)
{
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
@@ -192,24 +205,28 @@ static void loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
}
}
for(u32 i = 0; i < 12; i++)
for(j = 0; j < 12; j++)
{
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
if(memcmp(buf + 4, languages[i], 2) == 0)
if(memcmp(buf + 4, languages[j], 2) == 0)
{
*languageId = (u8)i;
*languageId = (u8)j;
break;
}
}
if(i == 7 || j == 12) ret = 1;
}
}
IFile_Close(&file);
}
return ret;
}
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
@@ -228,94 +245,105 @@ static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
}
}
for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4)
if(n > 0)
{
static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082};
//There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want
u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos;
if(cmp[0] == CFGU_GetConfigInfoBlk2_endPattern[0] && cmp[1] == CFGU_GetConfigInfoBlk2_endPattern[1])
for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4)
{
*CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2);
static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082};
for(u32 i = 0; i < n; i++)
if(possible[i] == *CFGUHandleOffset) return CFGU_GetConfigInfoBlk2_endPos;
//There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want
u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos;
CFGU_GetConfigInfoBlk2_endPos += 4;
if(cmp[0] == CFGU_GetConfigInfoBlk2_endPattern[0] && cmp[1] == CFGU_GetConfigInfoBlk2_endPattern[1])
{
*CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2);
for(u32 i = 0; i < n; i++)
if(possible[i] == *CFGUHandleOffset) return CFGU_GetConfigInfoBlk2_endPos;
CFGU_GetConfigInfoBlk2_endPos += 4;
}
}
}
return NULL;
}
static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos)
static inline u32 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)
for(CFGU_GetConfigInfoBlk2_startPos = CFGU_GetConfigInfoBlk2_endPos - 4;
CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D;
CFGU_GetConfigInfoBlk2_startPos -= 2);
CFGU_GetConfigInfoBlk2_startPos -= 4);
for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4)
if(CFGU_GetConfigInfoBlk2_startPos >= code)
{
if(*(u32 *)languageBlkIdPos == 0xA0002)
for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4)
{
for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough
if(*(u32 *)languageBlkIdPos == 0xA0002)
{
if(instr[3] == 0xEB) //We're looking for BL
for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough
{
u8 *calledFunction = instr;
u32 i = 0;
bool found;
do
if(instr[3] == 0xEB) //We're looking for BL
{
u32 low24 = (*(u32 *)calledFunction & 0x00FFFFFF) << 2;
u32 signMask = (u32)(-(low24 >> 25)) & 0xFC000000; //Sign extension
s32 offset = (s32)(low24 | signMask) + 8; //Branch offset + 8 for prefetch
u8 *calledFunction = instr;
u32 i = 0;
bool found;
calledFunction += offset;
do
{
u32 low24 = (*(u32 *)calledFunction & 0x00FFFFFF) << 2;
u32 signMask = (u32)(-(low24 >> 25)) & 0xFC000000; //Sign extension
s32 offset = (s32)(low24 | signMask) + 8; //Branch offset + 8 for prefetch
found = calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos;
i++;
}
while(i < 2 && !found && calledFunction[3] == 0xEA);
calledFunction += offset;
if(found)
{
*((u32 *)instr - 1) = 0xE3A00000 | languageId; //mov r0, sp => mov r0, =languageId
*(u32 *)instr = 0xE5CD0000; //bl CFGU_GetConfigInfoBlk2 => strb r0, [sp]
*((u32 *)instr + 1) = 0xE3B00000; //(1 or 2 instructions) => movs r0, 0 (result code)
found = calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos;
i++;
}
while(i < 2 && !found && calledFunction[3] == 0xEA);
//We're done
return;
if(found)
{
*((u32 *)instr - 1) = 0xE3A00000 | languageId; //mov r0, sp => mov r0, =languageId
*(u32 *)instr = 0xE5CD0000; //bl CFGU_GetConfigInfoBlk2 => strb r0, [sp]
*((u32 *)instr + 1) = 0xE3B00000; //(1 or 2 instructions) => movs r0, 0 (result code)
//We're done
return 0;
}
}
}
}
}
}
return 1;
}
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)
{
static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D4F70, 0xE3A00802, 0xE5A40080};
static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D0F70, 0xE3A00802};
u32 *cmp = (u32 *)cmdPos;
if(cmp[0] == cfgSecureInfoGetRegionCmdPattern[0] && cmp[1] == cfgSecureInfoGetRegionCmdPattern[1] &&
cmp[2] == cfgSecureInfoGetRegionCmdPattern[2] && *((u16 *)cmdPos + 7) == 0xE59F &&
*(u32 *)(cmdPos + 20 + *((u16 *)cmdPos + 6)) == CFGUHandleOffset)
if(*cmp == cfgSecureInfoGetRegionCmdPattern[1])
{
*((u32 *)cmdPos + 4) = 0xE3A00000 | regionId; //mov r0, =regionId
*((u32 *)cmdPos + 5) = 0xE5C40008; //strb r0, [r4, 8]
*((u32 *)cmdPos + 6) = 0xE3B00000; //movs r0, 0 (result code) ('s' not needed but nvm)
*((u32 *)cmdPos + 7) = 0xE5840004; //str r0, [r4, 4]
for(u32 i = 1; i < 3; i++)
if((*(cmp - i) & 0xFFFF0FFF) == cfgSecureInfoGetRegionCmdPattern[0] && *((u16 *)cmdPos + 5) == 0xE59F &&
*(u32 *)(cmdPos + 16 + *((u16 *)cmdPos + 4)) == CFGUHandleOffset)
{
cmp[3] = 0xE3A00000 | regionId; //mov r0, =regionId
cmp[4] = 0xE5C40008; //strb r0, [r4, #8]
cmp[5] = 0xE3A00000; //mov r0, #0 (result code)
cmp[6] = 0xE5840004; //str r0, [r4, #4]
//The remaining, not patched, function code will do the rest for us
break;
//The remaining, not patched, function code will do the rest for us
return;
}
}
}
}
@@ -323,6 +351,7 @@ static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOff
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
{
loadCFWInfo();
u32 res = 0;
if(((progId == 0x0004003000008F02LL || //USA Home Menu
progId == 0x0004003000008202LL || //JPN Home Menu
@@ -333,36 +362,36 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
progId == 0x000400300000A102LL || //CHN Home Menu
progId == 0x000400300000B102LL) //TWN Home Menu
{
static const u8 regionFreePattern[] = {
static const u8 pattern[] = {
0x0A, 0x0C, 0x00, 0x10
},
regionFreePatch[] = {
patch[] = {
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
};
//Patch SMDH region checks
patchMemory(code, size,
regionFreePattern,
sizeof(regionFreePattern), -31,
regionFreePatch,
sizeof(regionFreePatch), 1
);
if(!patchMemory(code, size,
pattern,
sizeof(pattern), -31,
patch,
sizeof(patch), 1
)) res++;
}
else if(progId == 0x0004013000003202LL) //FRIENDS
{
static const u8 fpdVerPattern[] = {
static const u8 pattern[] = {
0x42, 0xE0, 0x1E, 0xFF
};
u8 mostRecentFpdVer = 8;
u8 *off = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern));
u8 *off = memsearch(code, pattern, size, sizeof(pattern));
if(off == NULL) svcBreak(USERBREAK_ASSERT);
if(off == NULL) res++;
//Allow online access to work with old friends modules
if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer;
else if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer;
}
else if((progId == 0x0004001000021000LL || //USA MSET
@@ -373,18 +402,18 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
progId == 0x0004001000028000LL) //TWN MSET
&& CONFIG(PATCHVERSTRING))
{
static const u16 verPattern[] = u"Ve";
static u16 *verString;
u32 verStringSize = 0,
static const u16 pattern[] = u"Ve";
static u16 *patch;
u32 patchSize = 0,
currentNand = BOOTCFG_NAND;
u16 customVerString[19];
loadCustomVerString(customVerString, &verStringSize, currentNand);
loadCustomVerString(customVerString, &patchSize, currentNand);
if(verStringSize != 0) verString = customVerString;
if(patchSize != 0) patch = customVerString;
else
{
verStringSize = 8;
patchSize = 8;
u32 currentFirm = BOOTCFG_FIRM;
static u16 *verStringsNands[] = { u" Sys",
@@ -403,37 +432,39 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
u"SyE3",
u"SyE4" };
verString = (currentFirm != 0) == (currentNand != 0) ? verStringsNands[currentNand] :
(!currentNand ? verStringsSysEmu[currentFirm - 1] : verStringsEmuSys[currentNand - 1]);
patch = (currentFirm != 0) == (currentNand != 0) ? verStringsNands[currentNand] :
(!currentNand ? verStringsSysEmu[currentFirm - 1] : verStringsEmuSys[currentNand - 1]);
}
//Patch Ver. string
patchMemory(code, size,
verPattern,
sizeof(verPattern) - 2, 0,
verString,
verStringSize, 1
);
if(!patchMemory(code, size,
pattern,
sizeof(pattern) - 2, 0,
patch,
patchSize, 1
)) res++;
}
else if(progId == 0x0004013000008002LL) //NS
{
if(progVer > 4)
{
static const u8 stopCartUpdatesPattern[] = {
static const u8 pattern[] = {
0x0C, 0x18, 0xE1, 0xD8
},
stopCartUpdatesPatch[] = {
patch[] = {
0x0B, 0x18, 0x21, 0xC8
};
//Disable updates from foreign carts (makes carts region-free)
patchMemory(code, size,
stopCartUpdatesPattern,
sizeof(stopCartUpdatesPattern), 0,
stopCartUpdatesPatch,
sizeof(stopCartUpdatesPatch), 2
);
u32 ret = patchMemory(code, size,
pattern,
sizeof(pattern), 0,
patch,
sizeof(patch), 2
);
if(ret == 0 || (ret == 1 && progVer > 0xB)) res++;
}
if(LOADERFLAG(ISN3DS))
@@ -442,140 +473,147 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
if(cpuSetting != 0)
{
static const u8 cfgN3dsCpuPattern[] = {
static const u8 pattern[] = {
0x0C, 0x00, 0x94, 0x15
};
u32 *off = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
u32 *off = (u32 *)memsearch(code, pattern, size, sizeof(pattern));
if(off == NULL) svcBreak(USERBREAK_ASSERT);
//Patch N3DS CPU Clock and L2 cache setting
*(off - 4) = 0xE1A00000;
*(off + 3) = 0xE3A00000 | cpuSetting;
if(off == NULL) res++;
else
{
//Patch N3DS CPU Clock and L2 cache setting
*(off - 4) = *(off - 3);
*(off - 3) = *(off - 1);
memcpy(off - 1, off, 16);
*(off + 3) = 0xE3800000 | cpuSetting;
}
}
}
}
else if(progId == 0x0004013000001702LL) //CFG
{
static const u8 secureinfoSigCheckPattern[] = {
static const u8 pattern[] = {
0x06, 0x46, 0x10, 0x48
},
secureinfoSigCheckPatch[] = {
patch[] = {
0x00, 0x26
};
//Disable SecureInfo signature check
patchMemory(code, size,
secureinfoSigCheckPattern,
sizeof(secureinfoSigCheckPattern), 0,
secureinfoSigCheckPatch,
sizeof(secureinfoSigCheckPatch), 1
);
if(!patchMemory(code, size,
pattern,
sizeof(pattern), 0,
patch,
sizeof(patch), 1
)) res++;
if(secureInfoExists())
{
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_",
secureinfoFilenamePatch[] = u"C";
static const u16 pattern[] = u"Sec",
patch[] = u"C";
//Use SecureInfo_C
patchMemory(code, size,
secureinfoFilenamePattern,
sizeof(secureinfoFilenamePattern) - 2,
sizeof(secureinfoFilenamePattern) - 2,
secureinfoFilenamePatch,
sizeof(secureinfoFilenamePatch) - 2, 2
);
if(patchMemory(code, size,
pattern,
sizeof(pattern) - 2, 22,
patch,
sizeof(patch) - 2, 2
) != 2) res++;
}
}
else if(progId == 0x0004013000003702LL && progVer > 0) //RO
{
static const u8 sigCheckPattern[] = {
static const u8 pattern[] = {
0x20, 0xA0, 0xE1, 0x8B
},
sha256ChecksPattern1[] = {
pattern2[] = {
0xE1, 0x30, 0x40, 0x2D
},
sha256ChecksPattern2[] = {
pattern3[] = {
0x2D, 0xE9, 0x01, 0x70
},
stub[] = {
patch[] = {
0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 //mov r0, #0; bx lr
};
//Disable CRR0 signature (RSA2048 with SHA256) check
patchMemory(code, size,
sigCheckPattern,
sizeof(sigCheckPattern), -9,
stub,
sizeof(stub), 1
);
if(!patchMemory(code, size,
pattern,
sizeof(pattern), -9,
patch,
sizeof(patch), 1
)) res++;
//Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
patchMemory(code, size,
sha256ChecksPattern1,
sizeof(sha256ChecksPattern1), 1,
stub,
sizeof(stub), 1
);
if(!patchMemory(code, size,
pattern2,
sizeof(pattern2), 1,
patch,
sizeof(patch), 1
)) res++;
patchMemory(code, size,
sha256ChecksPattern2,
sizeof(sha256ChecksPattern2), -2,
stub,
sizeof(stub), 1
);
if(!patchMemory(code, size,
pattern3,
sizeof(pattern3), -2,
patch,
sizeof(patch), 1
)) res++;
}
else if(progId == 0x0004003000008A02LL && MULTICONFIG(DEVOPTIONS) == 1) //ErrDisp
{
static const u8 unitinfoCheckPattern1[] = {
static const u8 pattern[] = {
0x00, 0xD0, 0xE5, 0xDB
},
unitinfoCheckPattern2[] = {
pattern2[] = {
0x14, 0x00, 0xD0, 0xE5, 0x01
},
unitinfoCheckPatch[] = {
patch[] = {
0x00, 0x00, 0xA0, 0xE3
};
patchMemory(code, size,
unitinfoCheckPattern1,
sizeof(unitinfoCheckPattern1), -1,
unitinfoCheckPatch,
sizeof(unitinfoCheckPatch), 1
);
//Patch UNITINFO checks to make ErrDisp more verbose
if(!patchMemory(code, size,
pattern,
sizeof(pattern), -1,
patch,
sizeof(patch), 1
)) res++;
patchMemory(code, size,
unitinfoCheckPattern2,
sizeof(unitinfoCheckPattern2), 0,
unitinfoCheckPatch,
sizeof(unitinfoCheckPatch), 3
);
if(patchMemory(code, size,
pattern2,
sizeof(pattern2), 0,
patch,
sizeof(patch), 3
) != 3) res++;
}
else if(CONFIG(USELANGEMUANDCODE) && (u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000)
{
//External .code section loading
loadTitleCodeSection(progId, code, size);
res += loadTitleCodeSection(progId, code, size);
//Language emulation
u8 regionId = 0xFF,
languageId = 0xFF;
loadTitleLocaleConfig(progId, &regionId, &languageId);
languageId;
res += loadTitleLocaleConfig(progId, &regionId, &languageId);
if(regionId != 0xFF || regionId != 0xFF)
if(!res && regionId != 0xFF)
{
u32 CFGUHandleOffset;
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
if(CFGU_GetConfigInfoBlk2_endPos != NULL)
if(CFGU_GetConfigInfoBlk2_endPos == NULL) res++;
else
{
if(languageId != 0xFF) patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
if(regionId != 0xFF) patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
res += patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
}
}
}
if(res != 0) svcBreak(USERBREAK_ASSERT);
}

View File

@@ -4,7 +4,6 @@
payload_addr equ 0x23F00000 ; Brahma payload address
payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeBrah supports)
sd_notmounted equ 0xC8804465 ; Error code returned when SD is not mounted
.create "build/reboot.bin", 0
.arm
@@ -28,6 +27,8 @@ sd_notmounted equ 0xC8804465 ; Error code returned when SD is not mounted
cmp r0, r2
bne pxi_wait_recv
mov r4, #2
open_payload:
; Open file
add r0, r7, #8
@@ -38,9 +39,8 @@ sd_notmounted equ 0xC8804465 ; Error code returned when SD is not mounted
blx r6
cmp r0, #0
beq read_payload
ldr r2, =sd_notmounted
cmp r0, r2
bne panic
subs r4, r4, #1
beq panic
adr r0, fname
adr r1, nand_mount
mov r2, #8

View File

@@ -113,7 +113,8 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
"(refer to the wiki for instructions).",
"Select the New 3DS CPU mode.\n\n"
"It will be always enabled.\n\n"
"This won't apply to\n"
"New 3DS exclusive/enhanced games.\n\n"
"'Clock+L2' can cause issues with some\n"
"games.",
@@ -126,7 +127,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
"always detected as a development unit\n"
"(which breaks online features and\n"
"allows booting some developer\n"
"software).\n\n"
"software and installing dev CIAs).\n\n"
"Only change this if you know what you\n"
"are doing!",
@@ -373,7 +374,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++)

View File

@@ -299,18 +299,18 @@ static void sha(void *res, const void *src, u32 size, u32 mode)
/*****************************************************************/
static u8 __attribute__((aligned(4))) nandCtr[AES_BLOCK_SIZE];
__attribute__((aligned(4))) static u8 nandCtr[AES_BLOCK_SIZE],
shaHashBackup[SHA_256_HASH_SIZE];
static u8 nandSlot;
static u32 fatStart;
static u8 __attribute__((aligned(4))) shaHashBackup[SHA_256_HASH_SIZE];
static bool didShaHashBackup = false;
FirmwareSource firmSource;
void ctrNandInit(void)
{
u8 __attribute__((aligned(4))) cid[AES_BLOCK_SIZE];
u8 __attribute__((aligned(4))) shaSum[SHA_256_HASH_SIZE];
__attribute__((aligned(4))) u8 cid[AES_BLOCK_SIZE],
shaSum[SHA_256_HASH_SIZE];
sdmmc_get_cid(1, (u32 *)cid);
sha(shaSum, cid, sizeof(cid), SHA_256_MODE);
@@ -318,7 +318,7 @@ void ctrNandInit(void)
if(ISN3DS)
{
u8 __attribute__((aligned(4))) keyY0x5[AES_BLOCK_SIZE] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
__attribute__((aligned(4))) u8 keyY0x5[AES_BLOCK_SIZE] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
nandSlot = 0x05;
@@ -333,7 +333,7 @@ void ctrNandInit(void)
int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
{
u8 __attribute__((aligned(4))) tmpCtr[sizeof(nandCtr)];
__attribute__((aligned(4))) u8 tmpCtr[sizeof(nandCtr)];
memcpy(tmpCtr, nandCtr, sizeof(nandCtr));
aes_advctr(tmpCtr, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
@@ -359,7 +359,7 @@ int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf)
u8 *buffer = (u8 *)0x23000000;
u32 bufferSize = 0xF00000;
u8 __attribute__((aligned(4))) tmpCtr[sizeof(nandCtr)];
__attribute__((aligned(4))) u8 tmpCtr[sizeof(nandCtr)];
memcpy(tmpCtr, nandCtr, sizeof(nandCtr));
aes_advctr(tmpCtr, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(nandSlot);
@@ -383,15 +383,21 @@ 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};
__attribute__((aligned(4))) const u8 keyX0x25s[2][AES_BLOCK_SIZE] = {
{0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3},
{0x81, 0x90, 0x7A, 0x4B, 0x6F, 0x1B, 0x47, 0x32, 0x3A, 0x67, 0x79, 0x74, 0xCE, 0x4A, 0xD7, 0x1B}
},
keyY0x2Fs[2][AES_BLOCK_SIZE] = {
{0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16},
{0x73, 0x25, 0xC4, 0xEB, 0x14, 0x3A, 0x0D, 0x5F, 0x5D, 0xB6, 0xE5, 0xC5, 0x7A, 0x21, 0x95, 0xAC}
};
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, keyX0x25s[ISDEVUNIT ? 1 : 0], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setkey(0x2F, keyY0x2Fs[ISDEVUNIT ? 1 : 0], 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. */
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);
}
@@ -405,7 +411,7 @@ bool decryptExeFs(Cxi *cxi)
u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200;
u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200;
u8 __attribute__((aligned(4))) ncchCtr[AES_BLOCK_SIZE] = {0};
__attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0};
for(u32 i = 0; i < 8; i++)
ncchCtr[7 - i] = cxi->ncch.partitionId[i];
@@ -429,9 +435,9 @@ bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
{
isTicket = true;
const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C};
u8 __attribute__((aligned(4))) titleKey[AES_BLOCK_SIZE];
u8 __attribute__((aligned(4))) cetkIv[AES_BLOCK_SIZE] = {0};
__attribute__((aligned(4))) const u8 keyY0x3D[AES_BLOCK_SIZE] = {0x0C, 0x76, 0x72, 0x30, 0xF0, 0x99, 0x8F, 0x1C, 0x46, 0x82, 0x82, 0x02, 0xFA, 0xAC, 0xBE, 0x4C};
__attribute__((aligned(4))) u8 titleKey[AES_BLOCK_SIZE],
cetkIv[AES_BLOCK_SIZE] = {0};
memcpy(titleKey, ticket->titleKey, sizeof(titleKey));
memcpy(cetkIv, ticket->titleId, sizeof(ticket->titleId));
@@ -439,7 +445,7 @@ bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize)
aes_use_keyslot(0x3D);
aes(titleKey, titleKey, 1, cetkIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
u8 __attribute__((aligned(4))) ncchIv[AES_BLOCK_SIZE] = {0};
__attribute__((aligned(4))) u8 ncchIv[AES_BLOCK_SIZE] = {0};
aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x16);
@@ -470,12 +476,19 @@ 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);
__attribute__((aligned(4))) const u8 key1s[2][AES_BLOCK_SIZE] = {
{0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},
{0xA2, 0xF4, 0x00, 0x3C, 0x7A, 0x95, 0x10, 0x25, 0xDF, 0x4E, 0x9E, 0x74, 0xE3, 0x0C, 0x92, 0x99}
},
key2s[2][AES_BLOCK_SIZE] = {
{0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0},
{0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25}
};
aes_setkey(0x11, k9lVersion == 2 ? key2s[ISDEVUNIT ? 1 : 0] : key1s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
}
if(needToDecrypt)
@@ -488,19 +501,19 @@ void kernel9Loader(Arm9Bin *arm9Section)
arm9BinSlot = 0x16;
//Set keyX
u8 __attribute__((aligned(4))) keyX[AES_BLOCK_SIZE];
__attribute__((aligned(4))) u8 keyX[AES_BLOCK_SIZE];
aes_use_keyslot(0x11);
aes(keyX, arm9Section->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(0x16, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
}
//Set keyY
u8 __attribute__((aligned(4))) keyY[AES_BLOCK_SIZE];
__attribute__((aligned(4))) u8 keyY[AES_BLOCK_SIZE];
memcpy(keyY, arm9Section->keyY, sizeof(keyY));
aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
//Set CTR
u8 __attribute__((aligned(4))) arm9BinCtr[AES_BLOCK_SIZE];
__attribute__((aligned(4))) u8 arm9BinCtr[AES_BLOCK_SIZE];
memcpy(arm9BinCtr, arm9Section->ctr, sizeof(arm9BinCtr));
//Decrypt ARM9 binary
@@ -513,8 +526,8 @@ void kernel9Loader(Arm9Bin *arm9Section)
//Set >=9.6 KeyXs
if(k9lVersion == 2)
{
u8 __attribute__((aligned(4))) keyData[AES_BLOCK_SIZE] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
u8 __attribute__((aligned(4))) decKey[sizeof(keyData)];
__attribute__((aligned(4))) u8 keyData[AES_BLOCK_SIZE] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98},
decKey[sizeof(keyData)];
//Set keys 0x19..0x1F keyXs
aes_use_keyslot(0x11);
@@ -528,11 +541,11 @@ void kernel9Loader(Arm9Bin *arm9Section)
void computePinHash(u8 *outbuf, const u8 *inbuf)
{
u8 __attribute__((aligned(4))) cid[AES_BLOCK_SIZE];
u8 __attribute__((aligned(4))) cipherText[AES_BLOCK_SIZE];
__attribute__((aligned(4))) u8 cid[AES_BLOCK_SIZE],
cipherText[AES_BLOCK_SIZE];
sdmmc_get_cid(1, (u32 *)cid);
aes_use_keyslot(4); //Console-unique keyslot whose keys are set by the ARM9 bootROM
aes_use_keyslot(0x04); //Console-unique keyslot whose keys are set by the ARM9 bootROM
aes(cipherText, inbuf, 1, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
sha(outbuf, cipherText, sizeof(cipherText), SHA_256_MODE);
}

View File

@@ -51,13 +51,13 @@ u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffse
u32 *endPos = exceptionsPage + 0x400;
u32 *initFPU;
for(initFPU = exceptionsPage; *initFPU != 0xE1A0D002 && initFPU < endPos; initFPU++);
for(initFPU = exceptionsPage; initFPU < endPos && *initFPU != 0xE1A0D002; initFPU++);
u32 *freeSpace;
for(freeSpace = initFPU; *freeSpace != 0xFFFFFFFF && freeSpace < endPos; freeSpace++);
for(freeSpace = initFPU; freeSpace < endPos && *freeSpace != 0xFFFFFFFF; freeSpace++);
u32 *mcuReboot;
for(mcuReboot = exceptionsPage; *mcuReboot != 0xE3A0A0C2 && mcuReboot < endPos; mcuReboot++);
for(mcuReboot = exceptionsPage; mcuReboot < endPos && *mcuReboot != 0xE3A0A0C2; mcuReboot++);
if(initFPU == endPos || freeSpace == endPos || mcuReboot == endPos || *(u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 36) != 0xFFFFFFFF) ret = 1;
else

View File

@@ -58,7 +58,7 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora
bool mustLoadFromStorage = false;
if(!ISN3DS && *firmType == NATIVE_FIRM)
if(!ISN3DS && *firmType == NATIVE_FIRM && !ISDEVUNIT)
{
if(firmVersion < 0x18)
{
@@ -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;
@@ -121,8 +122,8 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
firm->arm9Entry = (u8 *)0x801B01C;
}
//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();
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH
else if(!ISA9LH && !ISFIRMLAUNCH && firmVersion >= 0x29) set6x7xKeys();
//Find the Process9 .code location, size and memory address
u32 process9Size,
@@ -145,12 +146,19 @@ 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 encryption
if(!ISDEVUNIT)
{
ret += patchZeroKeyNcchEncryptionCheck(process9Offset, process9Size);
ret += patchNandNcchEncryptionCheck(process9Offset, process9Size);
}
//11.0 FIRM patches
if(firmVersion >= (ISN3DS ? 0x21 : 0x52))
{
@@ -163,8 +171,12 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
ret += implementSvcGetCFWInfo(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space, isSafeMode);
//Apply UNITINFO patch
if(devMode == 2) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
//Apply UNITINFO patches
if(devMode == 2)
{
ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
if(!ISDEVUNIT) ret += patchCheckForDevCommonKey(process9Offset, process9Size);
}
if(devMode != 0 && isA9lhInstalled)
{

View File

@@ -185,7 +185,8 @@ u32 firmRead(void *dest, u32 firmType)
const char *firmFolders[][2] = {{ "00000002", "20000002" },
{ "00000102", "20000102" },
{ "00000202", "20000202" },
{ "00000003", "20000003" }};
{ "00000003", "20000003" },
{ "00000001", "20000001" }};
char path[48] = "1:/title/00040138/";
concatenateStrings(path, firmFolders[firmType][ISN3DS ? 1 : 0]);

View File

@@ -62,8 +62,18 @@ void main(void)
{
if(needConfig == CREATE_CONFIGURATION) mcuPowerOff();
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
firmType = launchedFirmTidLow[7] == u'3' ? SAFE_FIRM : (FirmwareType)(launchedFirmTidLow[5] - u'0');
switch(launchedFirmTidLow[7])
{
case u'2':
firmType = (FirmwareType)(launchedFirmTidLow[5] - u'0');
break;
case u'3':
firmType = SAFE_FIRM;
break;
case u'1':
firmType = SYSUPDATER_FIRM;
break;
}
nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM;
@@ -238,16 +248,17 @@ void main(void)
case NATIVE_FIRM:
res = patchNativeFirm(firmVersion, nandType, emuHeader, isA9lhInstalled, isSafeMode, devMode);
break;
case SAFE_FIRM:
case NATIVE_FIRM1X2X:
res = isA9lhInstalled ? patch1x2xNativeAndSafeFirm(devMode) : 0;
break;
case TWL_FIRM:
res = patchTwlFirm(firmVersion, devMode);
break;
case AGB_FIRM:
res = patchAgbFirm(devMode);
break;
case SAFE_FIRM:
case SYSUPDATER_FIRM:
case NATIVE_FIRM1X2X:
res = isA9lhInstalled ? patch1x2xNativeAndSafeFirm(devMode) : 0;
break;
}
if(res != 0)

View File

@@ -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};

View File

@@ -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);

View File

@@ -56,7 +56,7 @@ void newPin(bool allowSkipping, u32 pinMode)
drawCharacter('0' + length, true, 10 + 5 * SPACING_X, 10 + 2 * SPACING_Y, COLOR_WHITE);
//Pad to AES block length with zeroes
u8 __attribute__((aligned(4))) enteredPassword[AES_BLOCK_SIZE] = {0};
__attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0};
u8 cnt = 0;
u32 charDrawPos = 16 * SPACING_X;
@@ -90,8 +90,8 @@ void newPin(bool allowSkipping, u32 pinMode)
pin.formatVersionMajor = PIN_VERSIONMAJOR;
pin.formatVersionMinor = PIN_VERSIONMINOR;
u8 __attribute__((aligned(4))) tmp[SHA_256_HASH_SIZE];
u8 __attribute__((aligned(4))) lengthBlock[AES_BLOCK_SIZE] = {0};
__attribute__((aligned(4))) u8 tmp[SHA_256_HASH_SIZE],
lengthBlock[AES_BLOCK_SIZE] = {0};
lengthBlock[0] = length;
computePinHash(tmp, lengthBlock);
@@ -114,8 +114,8 @@ bool verifyPin(u32 pinMode)
pin.formatVersionMinor != PIN_VERSIONMINOR)
return false;
u8 __attribute__((aligned(4))) tmp[SHA_256_HASH_SIZE];
u8 __attribute__((aligned(4))) lengthBlock[AES_BLOCK_SIZE] = {0};
__attribute__((aligned(4))) u8 tmp[SHA_256_HASH_SIZE],
lengthBlock[AES_BLOCK_SIZE] = {0};
lengthBlock[0] = 4 + 2 * (pinMode - 1);
computePinHash(tmp, lengthBlock);
@@ -126,7 +126,7 @@ bool verifyPin(u32 pinMode)
initScreens();
//Pad to AES block length with zeroes
u8 __attribute__((aligned(4))) enteredPassword[AES_BLOCK_SIZE] = {0};
__attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0};
bool unlock = false;
u8 cnt = 0;

View File

@@ -97,6 +97,7 @@ typedef enum FirmwareType
TWL_FIRM,
AGB_FIRM,
SAFE_FIRM,
SYSUPDATER_FIRM,
NATIVE_FIRM1X2X
} FirmwareType;