diff --git a/injector/source/patcher.c b/injector/source/patcher.c index 2cc88a1..708b30f 100644 --- a/injector/source/patcher.c +++ b/injector/source/patcher.c @@ -51,30 +51,28 @@ static inline void loadCFWInfo(void) { static bool infoLoaded = false; - if(!infoLoaded) - { - svcGetCFWInfo(&info); + if(infoLoaded) return; - IFile file; - if(LOADERFLAG(ISSAFEMODE) && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted - IFile_Close(&file); + svcGetCFWInfo(&info); - infoLoaded = true; - } + IFile file; + if(LOADERFLAG(ISSAFEMODE) && R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ))) //Init SD card if SAFE_MODE is being booted + IFile_Close(&file); + + infoLoaded = true; } static inline bool secureInfoExists(void) { static bool exists = false; - if(!exists) + if(exists) return true; + + IFile file; + if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ))) { - IFile file; - if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ))) - { - exists = true; - IFile_Close(&file); - } + exists = true; + IFile_Close(&file); } return exists; @@ -90,52 +88,50 @@ static inline void loadCustomVerString(u16 *out, u32 *verStringSize, u32 current IFile file; - if(R_SUCCEEDED(openLumaFile(&file, paths[currentNand]))) + if(R_FAILED(openLumaFile(&file, paths[currentNand]))) return; + + u64 fileSize; + + if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > 62) goto exit; + + u8 buf[62]; + u64 total; + + if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) goto exit; + + static const u8 bom[] = {0xEF, 0xBB, 0xBF}; + u32 finalSize = 0; + + //Convert from UTF-8 to UTF-16 (Nintendo doesn't support 4-byte UTF-16, so 4-byte UTF-8 is unsupported) + for(u32 increase, fileSizeTmp = (u32)fileSize, i = (fileSizeTmp > 2 && memcmp(buf, bom, 3) == 0) ? 3 : 0; + i < fileSizeTmp && finalSize < 19; i += increase, finalSize++) { - u64 fileSize; - - if(R_SUCCEEDED(IFile_GetSize(&file, &fileSize)) && fileSize <= 62) + if((buf[i] & 0x80) == 0 && !(buf[i] == 0xA || buf[i] == 0xD)) { - u8 buf[fileSize]; - u64 total; - - if(R_SUCCEEDED(IFile_Read(&file, &total, buf, fileSize))) - { - static const u8 bom[] = {0xEF, 0xBB, 0xBF}; - u32 finalSize = 0; - - //Convert from UTF-8 to UTF-16 (Nintendo doesn't support 4-byte UTF-16, so 4-byte UTF-8 is unsupported) - for(u32 increase, fileSizeTmp = (u32)fileSize, i = (fileSizeTmp > 2 && memcmp(buf, bom, 3) == 0) ? 3 : 0; - i < fileSizeTmp && finalSize < 19; i += increase, finalSize++) - { - if((buf[i] & 0x80) == 0 && !(buf[i] == 0xA || buf[i] == 0xD)) - { - increase = 1; - out[finalSize] = (u16)buf[i]; - } - else if((buf[i] & 0xE0) == 0xC0 && i + 1 < fileSizeTmp && (buf[i + 1] & 0xC0) == 0x80) - { - increase = 2; - out[finalSize] = (u16)(((buf[i] & 0x1F) << 6) | (buf[i + 1] & 0x3F)); - } - else if((buf[i] & 0xF0) == 0xE0 && i + 2 < fileSizeTmp && (buf[i + 1] & 0xC0) == 0x80 && (buf[i + 2] & 0xC0) == 0x80) - { - increase = 3; - out[finalSize] = (u16)(((buf[i] & 0xF) << 12) | ((buf[i + 1] & 0x3F) << 6) | (buf[i + 2] & 0x3F)); - } - else break; - } - - if(finalSize > 0) - { - if(finalSize > 5 && finalSize < 19) out[finalSize++] = 0; - *verStringSize = finalSize * 2; - } - } + increase = 1; + out[finalSize] = (u16)buf[i]; } - - IFile_Close(&file); + else if((buf[i] & 0xE0) == 0xC0 && i + 1 < fileSizeTmp && (buf[i + 1] & 0xC0) == 0x80) + { + increase = 2; + out[finalSize] = (u16)(((buf[i] & 0x1F) << 6) | (buf[i + 1] & 0x3F)); + } + else if((buf[i] & 0xF0) == 0xE0 && i + 2 < fileSizeTmp && (buf[i + 1] & 0xC0) == 0x80 && (buf[i + 2] & 0xC0) == 0x80) + { + increase = 3; + out[finalSize] = (u16)(((buf[i] & 0xF) << 12) | ((buf[i + 1] & 0x3F) << 6) | (buf[i + 2] & 0x3F)); + } + else break; } + + if(finalSize > 0) + { + if(finalSize > 5 && finalSize < 19) out[finalSize++] = 0; + *verStringSize = finalSize * 2; + } + +exit: + IFile_Close(&file); } static inline u32 loadTitleCodeSection(u64 progId, u8 *code, u32 size) @@ -147,23 +143,23 @@ static inline u32 loadTitleCodeSection(u64 progId, u8 *code, u32 size) progIdToStr(path + 35, progId); IFile file; - u32 ret = 0; - if(R_SUCCEEDED(openLumaFile(&file, path))) + if(R_FAILED(openLumaFile(&file, path))) return 0; + + u32 ret; + u64 fileSize; + + if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = 1; + else { - u64 fileSize; + u64 total; - if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = 1; - else - { - u64 total; - - if(R_FAILED(IFile_Read(&file, &total, code, fileSize)) || total != fileSize) ret = 1; - } - - IFile_Close(&file); + if(R_FAILED(IFile_Read(&file, &total, code, fileSize)) || total != fileSize) ret = 1; + else ret = 0; } + IFile_Close(&file); + return ret; } @@ -176,53 +172,58 @@ static inline u32 loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId progIdToStr(path + 29, progId); IFile file; - u32 ret = 0; - if(R_SUCCEEDED(openLumaFile(&file, path))) + if(R_FAILED(openLumaFile(&file, path))) return 0; + + u32 ret; + u64 fileSize; + + if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 6 || fileSize > 8) { - u64 fileSize; - - if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 6 || fileSize > 8) ret = 1; - else - { - char buf[fileSize]; - u64 total; - - if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) ret = 1; - else - { - u32 i, - j; - - for(i = 0; i < 7; i++) - { - static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"}; - - if(memcmp(buf, regions[i], 3) == 0) - { - *regionId = (u8)i; - break; - } - } - - 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[j], 2) == 0) - { - *languageId = (u8)j; - break; - } - } - - if(i == 7 || j == 12) ret = 1; - } - } - - IFile_Close(&file); + ret = 1; + goto exit; } + char buf[8]; + u64 total; + + if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) + { + ret = 1; + goto exit; + } + + u32 i, + j; + + for(i = 0; i < 7; i++) + { + static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"}; + + if(memcmp(buf, regions[i], 3) == 0) + { + *regionId = (u8)i; + break; + } + } + + 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[j], 2) == 0) + { + *languageId = (u8)j; + break; + } + } + + if(i == 7 || j == 12) ret = 1; + else ret = 0; + +exit: + IFile_Close(&file); + return ret; } @@ -238,32 +239,29 @@ static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset) for(u8 *pos = code + 4; n < 24 && pos < code + size - 4; pos += 4) { - if(*(u32 *)pos == 0xD8A103F9) - { - for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++) - if(*l <= 0x10000000) possible[n++] = *l; - } + if(*(u32 *)pos != 0xD8A103F9) continue; + + for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++) + if(*l <= 0x10000000) possible[n++] = *l; } - if(n > 0) + if(!n) return NULL; + + for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4) { - for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4) - { - static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082}; + 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; + //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]) - { - *CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2); + if(cmp[0] != CFGU_GetConfigInfoBlk2_endPattern[0] || cmp[1] != CFGU_GetConfigInfoBlk2_endPattern[1]) continue; - for(u32 i = 0; i < n; i++) - if(possible[i] == *CFGUHandleOffset) return CFGU_GetConfigInfoBlk2_endPos; + *CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2); - CFGU_GetConfigInfoBlk2_endPos += 4; - } - } + for(u32 i = 0; i < n; i++) + if(possible[i] == *CFGUHandleOffset) return CFGU_GetConfigInfoBlk2_endPos; + + CFGU_GetConfigInfoBlk2_endPos += 4; } return NULL; @@ -277,45 +275,41 @@ static inline u32 patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFG CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D; CFGU_GetConfigInfoBlk2_startPos -= 4); - if(CFGU_GetConfigInfoBlk2_startPos >= code) + if(CFGU_GetConfigInfoBlk2_startPos < code) return 1; + + for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4) { - for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4) + if(*(u32 *)languageBlkIdPos != 0xA0002) continue; + + for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough { - if(*(u32 *)languageBlkIdPos == 0xA0002) + if(instr[3] != 0xEB) continue; //We're looking for BL + + u8 *calledFunction = instr; + u32 i = 0; + bool found; + + do { - for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough + 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 + + calledFunction += offset; + + if(calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos) { - if(instr[3] == 0xEB) //We're looking for BL - { - u8 *calledFunction = instr; - u32 i = 0; - bool 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) - 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 - - calledFunction += offset; - - found = calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos; - i++; - } - while(i < 2 && !found && calledFunction[3] == 0xEA); - - 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; - } - } + //We're done + return 0; } + + i++; } + while(i < 2 && !found && calledFunction[3] == 0xEA); } } @@ -330,20 +324,19 @@ static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHa u32 *cmp = (u32 *)cmdPos; - if(*cmp == cfgSecureInfoGetRegionCmdPattern[1]) - { - 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] + if(*cmp != cfgSecureInfoGetRegionCmdPattern[1]) continue; - //The remaining, not patched, function code will do the rest for us - return; - } + 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 + return; } } } @@ -351,7 +344,6 @@ static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHa 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 @@ -375,7 +367,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) sizeof(pattern), -31, patch, sizeof(patch), 1 - )) res++; + )) goto error; } else if(progId == 0x0004013000003202LL) //FRIENDS @@ -388,10 +380,10 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) u8 *off = memsearch(code, pattern, size, sizeof(pattern)); - if(off == NULL) res++; + if(off == NULL) goto error; //Allow online access to work with old friends modules - else if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer; + if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer; } else if((progId == 0x0004001000021000LL || //USA MSET @@ -442,7 +434,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) sizeof(pattern) - 2, 0, patch, patchSize, 1 - )) res++; + )) goto error; } else if(progId == 0x0004013000008002LL) //NS @@ -464,7 +456,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) sizeof(patch), 2 ); - if(ret == 0 || (ret == 1 && progVer > 0xB)) res++; + if(ret == 0 || (ret == 1 && progVer > 0xB)) goto error; } if(LOADERFLAG(ISN3DS)) @@ -479,15 +471,13 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) u32 *off = (u32 *)memsearch(code, pattern, size, sizeof(pattern)); - 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; - } + if(off == NULL) goto error; + + //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; } } } @@ -507,7 +497,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) sizeof(pattern), 0, patch, sizeof(patch), 1 - )) res++; + )) goto error; if(secureInfoExists()) { @@ -520,7 +510,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) sizeof(pattern) - 2, 22, patch, sizeof(patch) - 2, 2 - ) != 2) res++; + ) != 2) goto error; } } @@ -539,28 +529,25 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 //mov r0, #0; bx lr }; - //Disable CRR0 signature (RSA2048 with SHA256) check + //Disable CRR0 signature (RSA2048 with SHA256) check and CRO0/CRR0 SHA256 hash checks (section hashes, and hash table) if(!patchMemory(code, size, pattern, sizeof(pattern), -9, patch, sizeof(patch), 1 - )) res++; - - //Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table) - if(!patchMemory(code, size, + ) || + !patchMemory(code, size, pattern2, sizeof(pattern2), 1, patch, sizeof(patch), 1 - )) res++; - - if(!patchMemory(code, size, + ) || + !patchMemory(code, size, pattern3, sizeof(pattern3), -2, patch, sizeof(patch), 1 - )) res++; + )) goto error; } else if(progId == 0x0004003000008A02LL && MULTICONFIG(DEVOPTIONS) == 1) //ErrDisp @@ -581,39 +568,37 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) sizeof(pattern), -1, patch, sizeof(patch), 1 - )) res++; - - if(patchMemory(code, size, + ) || + patchMemory(code, size, pattern2, sizeof(pattern2), 0, patch, sizeof(patch), 3 - ) != 3) res++; + ) != 3) goto error; } else if(CONFIG(USELANGEMUANDCODE) && (u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000) { - //External .code section loading - res += loadTitleCodeSection(progId, code, size); - - //Language emulation u8 regionId = 0xFF, languageId; - res += loadTitleLocaleConfig(progId, ®ionId, &languageId); + if(!loadTitleLocaleConfig(progId, ®ionId, &languageId) || + !loadTitleCodeSection(progId, code, size)) goto error; - if(!res && regionId != 0xFF) + if(regionId != 0xFF) { u32 CFGUHandleOffset; u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset); - if(CFGU_GetConfigInfoBlk2_endPos == NULL) res++; - else - { - res += patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos); - patchCfgGetRegion(code, size, regionId, CFGUHandleOffset); - } + if(CFGU_GetConfigInfoBlk2_endPos == NULL || + patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos)) goto error; + + patchCfgGetRegion(code, size, regionId, CFGUHandleOffset); } } - if(res != 0) svcBreak(USERBREAK_ASSERT); + return; + +error: + svcBreak(USERBREAK_ASSERT); + while(true); } \ No newline at end of file diff --git a/source/config.c b/source/config.c index f697917..e474107 100644 --- a/source/config.c +++ b/source/config.c @@ -33,40 +33,37 @@ CfgData configData; bool readConfig(void) { - bool ret; - if(fileRead(&configData, CONFIG_FILE, sizeof(CfgData)) != sizeof(CfgData) || memcmp(configData.magic, "CONF", 4) != 0 || configData.formatVersionMajor != CONFIG_VERSIONMAJOR || configData.formatVersionMinor != CONFIG_VERSIONMINOR) { configData.config = 0; - ret = false; - } - else ret = true; - return ret; + return false; + } + + return true; } void writeConfig(ConfigurationStatus needConfig, u32 configTemp) { /* If the configuration is different from previously, overwrite it. Just the no-forcing flag being set is not enough */ - if(needConfig == CREATE_CONFIGURATION || (configTemp & 0xFFFFFF7F) != configData.config) + if(needConfig != CREATE_CONFIGURATION && (configTemp & 0xFFFFFF7F) == configData.config) return; + + if(needConfig == CREATE_CONFIGURATION) { - if(needConfig == CREATE_CONFIGURATION) - { - memcpy(configData.magic, "CONF", 4); - configData.formatVersionMajor = CONFIG_VERSIONMAJOR; - configData.formatVersionMinor = CONFIG_VERSIONMINOR; - } - - //Merge the new options and new boot configuration - configData.config = (configData.config & 0xFFFFFF00) | (configTemp & 0xFF); - - if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData))) - error("Error writing the configuration file"); + memcpy(configData.magic, "CONF", 4); + configData.formatVersionMajor = CONFIG_VERSIONMAJOR; + configData.formatVersionMinor = CONFIG_VERSIONMINOR; } + + //Merge the new options and new boot configuration + configData.config = (configData.config & 0xFFFFFF00) | (configTemp & 0xFF); + + if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData))) + error("Error writing the configuration file"); } void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) @@ -249,12 +246,11 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) //Display all the multiple choice options in white for(u32 i = 0; i < multiOptionsAmount; i++) { - if(multiOptions[i].visible) - { - multiOptions[i].posY = endPos + SPACING_Y; - endPos = drawString(multiOptionsText[i], true, 10, multiOptions[i].posY, COLOR_WHITE); - drawCharacter(selected, true, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE); - } + if(!multiOptions[i].visible) continue; + + multiOptions[i].posY = endPos + SPACING_Y; + endPos = drawString(multiOptionsText[i], true, 10, multiOptions[i].posY, COLOR_WHITE); + drawCharacter(selected, true, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE); } endPos += SPACING_Y / 2; @@ -262,34 +258,34 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) //Display all the normal options in white except for the first one for(u32 i = 0, color = COLOR_RED; i < singleOptionsAmount; i++) { - if(singleOptions[i].visible) - { - singleOptions[i].posY = endPos + SPACING_Y; - endPos = drawString(singleOptionsText[i], true, 10, singleOptions[i].posY, color); - if(singleOptions[i].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[i].posY, color); + if(!singleOptions[i].visible) continue; - if(color == COLOR_RED) - { - singleSelected = i; - selectedOption = i + multiOptionsAmount; - color = COLOR_WHITE; - } + singleOptions[i].posY = endPos + SPACING_Y; + endPos = drawString(singleOptionsText[i], true, 10, singleOptions[i].posY, color); + if(singleOptions[i].enabled) drawCharacter(selected, true, 10 + SPACING_X, singleOptions[i].posY, color); + + if(color == COLOR_RED) + { + singleSelected = i; + selectedOption = i + multiOptionsAmount; + color = COLOR_WHITE; } } drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE); - u32 pressed = 0; - //Boring configuration menu - while(pressed != BUTTON_START) + while(true) { + u32 pressed; do { pressed = waitInput(true); } while(!(pressed & MENU_BUTTONS)); + if(pressed == BUTTON_START) break; + if(pressed != BUTTON_A) { //Remember the previously selected option @@ -319,21 +315,19 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode) if(selectedOption < multiOptionsAmount) { - if(multiOptions[selectedOption].visible) - { - isMultiOption = true; - break; - } + if(!multiOptions[selectedOption].visible) continue; + + isMultiOption = true; + break; } else { singleSelected = selectedOption - multiOptionsAmount; - if(singleOptions[singleSelected].visible) - { - isMultiOption = false; - break; - } + if(!singleOptions[singleSelected].visible) continue; + + isMultiOption = false; + break; } } diff --git a/source/crypto.c b/source/crypto.c index a1a42ec..5e51793 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -401,57 +401,45 @@ void set6x7xKeys(void) bool decryptExeFs(Cxi *cxi) { - bool isCxi; + if(memcmp(cxi->ncch.magic, "NCCH", 4) != 0) return false; - if(memcmp(cxi->ncch.magic, "NCCH", 4) == 0) - { - isCxi = true; + u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200; + u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200; + __attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0}; - u8 *exeFsOffset = (u8 *)cxi + (cxi->ncch.exeFsOffset + 1) * 0x200; - u32 exeFsSize = (cxi->ncch.exeFsSize - 1) * 0x200; - __attribute__((aligned(4))) u8 ncchCtr[AES_BLOCK_SIZE] = {0}; + for(u32 i = 0; i < 8; i++) + ncchCtr[7 - i] = cxi->ncch.partitionId[i]; + ncchCtr[8] = 2; - for(u32 i = 0; i < 8; i++) - ncchCtr[7 - i] = cxi->ncch.partitionId[i]; - ncchCtr[8] = 2; + aes_setkey(0x2C, cxi, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x2C); + aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); - aes_setkey(0x2C, cxi, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); - aes_advctr(ncchCtr, 0x200 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); - aes_use_keyslot(0x2C); - aes(cxi, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); - } - else isCxi = false; - - return isCxi && memcmp(cxi, "FIRM", 4) == 0; + return memcmp(cxi, "FIRM", 4) == 0; } bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize) { - bool isTicket; + if(memcmp(ticket->sigIssuer, "Root", 4) != 0) return false; - if(memcmp(ticket->sigIssuer, "Root", 4) == 0) - { - isTicket = true; - - __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], + __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)); + memcpy(titleKey, ticket->titleKey, sizeof(titleKey)); + memcpy(cetkIv, ticket->titleId, sizeof(ticket->titleId)); - aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); - aes_use_keyslot(0x3D); - aes(titleKey, titleKey, 1, cetkIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_setkey(0x3D, keyY0x3D, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x3D); + aes(titleKey, titleKey, 1, cetkIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); - __attribute__((aligned(4))) u8 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); - aes(cxi, cxi, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); - } - else isTicket = false; + aes_setkey(0x16, titleKey, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); + aes_use_keyslot(0x16); + aes(cxi, cxi, ncchSize / AES_BLOCK_SIZE, ncchIv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); - return isTicket && decryptExeFs(cxi); + return decryptExeFs(cxi); } void kernel9Loader(Arm9Bin *arm9Section) @@ -550,19 +538,18 @@ void computePinHash(u8 *outbuf, const u8 *inbuf) void backupAndRestoreShaHash(bool isRestore) { + if(!ISA9LH) return; + static bool didShaHashBackup = false; __attribute__((aligned(4))) static u8 shaHashBackup[SHA_256_HASH_SIZE]; - if(ISA9LH) + if(isRestore) { - if(isRestore) - { - if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup)); - } - else if(!didShaHashBackup) - { - memcpy(shaHashBackup, (void *)REG_SHA_HASH, sizeof(shaHashBackup)); - didShaHashBackup = true; - } + if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup)); + } + else if(!didShaHashBackup) + { + memcpy(shaHashBackup, (void *)REG_SHA_HASH, sizeof(shaHashBackup)); + didShaHashBackup = true; } } \ No newline at end of file diff --git a/source/draw.c b/source/draw.c index 1dcf821..9110845 100644 --- a/source/draw.c +++ b/source/draw.c @@ -38,30 +38,23 @@ bool loadSplash(void) *bottomSplashFile = "splashbottom.bin"; bool isTopSplashValid = getFileSize(topSplashFile) == SCREEN_TOP_FBSIZE, - isBottomSplashValid = getFileSize(bottomSplashFile) == SCREEN_BOTTOM_FBSIZE, - ret; + isBottomSplashValid = getFileSize(bottomSplashFile) == SCREEN_BOTTOM_FBSIZE; //Don't delay boot nor init the screens if no splash images or invalid splash images are on the SD - if(!isTopSplashValid && !isBottomSplashValid) ret = false; - else - { - initScreens(); - clearScreens(true); + if(!isTopSplashValid && !isBottomSplashValid) return false; - if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE; - if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE; + initScreens(); + clearScreens(true); - if(!isTopSplashValid && !isBottomSplashValid) ret = false; - else - { - swapFramebuffers(true); - wait(false, 3ULL); + if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE; + if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE; - ret = true; - } - } + if(!isTopSplashValid && !isBottomSplashValid) return false; - return ret; + swapFramebuffers(true); + wait(false, 3ULL); + + return true; } void drawCharacter(char character, bool isTopScreen, u32 posX, u32 posY, u32 color) diff --git a/source/emunand.c b/source/emunand.c index 4d43aae..82b8b72 100644 --- a/source/emunand.c +++ b/source/emunand.c @@ -36,7 +36,6 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) static u8 __attribute__((aligned(4))) temp[0x200]; static u32 nandSize = 0, fatStart; - bool found = false; if(!nandSize) { @@ -45,7 +44,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) fatStart = *(u32 *)(temp + 0x1C6); //First sector of the FAT partition } - for(u32 i = 0; i < 3 && !found; i++) + for(u32 i = 0; i < 3; i++) { static const u32 roundedMinsizes[] = {0x1D8000, 0x26E000}; @@ -72,7 +71,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) { emuOffset = nandOffset + 1; *emuHeader = nandOffset + 1; - found = true; + return; } //Check for Gateway EmuNAND @@ -80,7 +79,7 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) { emuOffset = nandOffset; *emuHeader = nandOffset + nandSize; - found = true; + return; } } @@ -88,136 +87,108 @@ void locateEmuNand(u32 *emuHeader, FirmwareSource *nandType) } //Fallback to the first EmuNAND if there's no second/third/fourth one, or to SysNAND if there isn't any - if(!found) + if(*nandType != FIRMWARE_EMUNAND) { - if(*nandType != FIRMWARE_EMUNAND) - { - *nandType = FIRMWARE_EMUNAND; - locateEmuNand(emuHeader, nandType); - } - else *nandType = FIRMWARE_SYSNAND; + *nandType = FIRMWARE_EMUNAND; + locateEmuNand(emuHeader, nandType); } + else *nandType = FIRMWARE_SYSNAND; } -static inline u32 getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space) +static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space) { const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; - u32 ret; //Looking for the last free space before Process9 *freeK9Space = memsearch(pos, pattern, size, sizeof(pattern)); - if(*freeK9Space == NULL) ret = 1; - else - { - *freeK9Space += 0x455; + if(*freeK9Space == NULL) return false; - ret = 0; - } + *freeK9Space += 0x455; - return ret; + return true; } static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc) { //Look for struct code const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; - u32 ret; const u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - *sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD); + if(off == NULL) return 1; - ret = 0; - } + *sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD); - return ret; + return 0; } static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset) { //Look for read/write code const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; - u32 ret; u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - if(readOffset == NULL) ret = 1; - else - { - readOffset -= 3; + if(readOffset == NULL) return 1; - u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)); + readOffset -= 3; - if(writeOffset == NULL) ret = 1; - else - { - writeOffset -= 3; - *readOffset = *writeOffset = 0x4C00; - readOffset[1] = writeOffset[1] = 0x47A0; - ((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset; + u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern)); - ret = 0; - } - } + if(writeOffset == NULL) return 1; - return ret; + writeOffset -= 3; + *readOffset = *writeOffset = 0x4C00; + readOffset[1] = writeOffset[1] = 0x47A0; + ((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset; + + return 0; } static inline u32 patchMpu(u8 *pos, u32 size) { //Look for MPU pattern const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; - u32 ret; u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - off[1] = 0x0036; - off[0xC] = off[0x12] = 0x0603; + if(off == NULL) return 1; - ret = 0; - } + off[1] = 0x0036; + off[0xC] = off[0x12] = 0x0603; - return ret; + return 0; } u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u32 emuHeader, u8 *kernel9Address) { + u8 *freeK9Space; + if(!getFreeK9Space(arm9Section, kernel9Size, &freeK9Space)) return 1; + u32 ret = 0; - u8 *freeK9Space; - ret += getFreeK9Space(arm9Section, kernel9Size, &freeK9Space); + //Copy EmuNAND code + memcpy(freeK9Space, emunand_bin, emunand_bin_size); - if(!ret) - { - //Copy EmuNAND code - memcpy(freeK9Space, emunand_bin, emunand_bin_size); + //Add the data of the found EmuNAND + u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4), + *posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4); + *posOffset = emuOffset; + *posHeader = emuHeader; - //Add the data of the found EmuNAND - u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4), - *posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4); - *posOffset = emuOffset; - *posHeader = emuHeader; + //Find and add the SDMMC struct + u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4); + u32 sdmmc; + ret += getSdmmc(process9Offset, process9Size, &sdmmc); + if(!ret) *posSdmmc = sdmmc; - //Find and add the SDMMC struct - u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4); - u32 sdmmc; - ret += getSdmmc(process9Offset, process9Size, &sdmmc); - if(!ret) *posSdmmc = sdmmc; + //Add EmuNAND hooks + u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address); + ret += patchNandRw(process9Offset, process9Size, branchOffset); - //Add EmuNAND hooks - u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address); - ret += patchNandRw(process9Offset, process9Size, branchOffset); - - //Set MPU - ret += patchMpu(arm9Section, kernel9Size); - } + //Set MPU + ret += patchMpu(arm9Section, kernel9Size); return ret; } \ No newline at end of file diff --git a/source/exceptions.c b/source/exceptions.c index ee53f08..3bc072b 100644 --- a/source/exceptions.c +++ b/source/exceptions.c @@ -47,7 +47,6 @@ void installArm9Handlers(void) u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset) { - u32 ret; u32 *endPos = exceptionsPage + 0x400; u32 *initFPU; @@ -59,152 +58,147 @@ u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffse u32 *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 + if(initFPU == endPos || freeSpace == endPos || mcuReboot == endPos || *(u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 36) != 0xFFFFFFFF) return 1; + + initFPU += 3; + mcuReboot -= 2; + + memcpy(freeSpace, arm11_exceptions_bin + 32, arm11_exceptions_bin_size - 32); + + exceptionsPage[1] = MAKE_BRANCH(exceptionsPage + 1, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 8) - 32); //Undefined Instruction + exceptionsPage[3] = MAKE_BRANCH(exceptionsPage + 3, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 12) - 32); //Prefetch Abort + exceptionsPage[4] = MAKE_BRANCH(exceptionsPage + 4, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 16) - 32); //Data Abort + exceptionsPage[7] = MAKE_BRANCH(exceptionsPage + 7, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 4) - 32); //FIQ + + for(u32 *pos = freeSpace; pos < (u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 32); pos++) { - initFPU += 3; - mcuReboot -= 2; - - memcpy(freeSpace, arm11_exceptions_bin + 32, arm11_exceptions_bin_size - 32); - - exceptionsPage[1] = MAKE_BRANCH(exceptionsPage + 1, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 8) - 32); //Undefined Instruction - exceptionsPage[3] = MAKE_BRANCH(exceptionsPage + 3, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 12) - 32); //Prefetch Abort - exceptionsPage[4] = MAKE_BRANCH(exceptionsPage + 4, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 16) - 32); //Data Abort - exceptionsPage[7] = MAKE_BRANCH(exceptionsPage + 7, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 4) - 32); //FIQ - - for(u32 *pos = freeSpace; pos < (u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 32); pos++) + switch(*pos) //Perform relocations { - switch(*pos) //Perform relocations - { - case 0xFFFF3000: *pos = stackAddress; break; - case 0xEBFFFFFE: *pos = MAKE_BRANCH_LINK(pos, initFPU); break; - case 0xEAFFFFFE: *pos = MAKE_BRANCH(pos, mcuReboot); break; - case 0xE12FFF1C: pos[1] = 0xFFFF0000 + 4 * (u32)(freeSpace - exceptionsPage) + pos[1] - 32; break; //bx r12 (mainHandler) - case 0xBEEFBEEF: *pos = codeSetOffset; break; - } + case 0xFFFF3000: *pos = stackAddress; break; + case 0xEBFFFFFE: *pos = MAKE_BRANCH_LINK(pos, initFPU); break; + case 0xEAFFFFFE: *pos = MAKE_BRANCH(pos, mcuReboot); break; + case 0xE12FFF1C: pos[1] = 0xFFFF0000 + 4 * (u32)(freeSpace - exceptionsPage) + pos[1] - 32; break; //bx r12 (mainHandler) + case 0xBEEFBEEF: *pos = codeSetOffset; break; } - - ret = 0; } - return ret; + return 0; } void detectAndProcessExceptionDumps(void) { volatile ExceptionDumpHeader *dumpHeader = (volatile ExceptionDumpHeader *)0x25000000; - if(dumpHeader->magic[0] == 0xDEADC0DE && dumpHeader->magic[1] == 0xDEADCAFE && (dumpHeader->processor == 9 || dumpHeader->processor == 11)) + if(dumpHeader->magic[0] != 0xDEADC0DE || dumpHeader->magic[1] == 0xDEADCAFE || (dumpHeader->processor != 9 && dumpHeader->processor != 11)) return; + + const vu32 *regs = (vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader)); + const vu8 *stackDump = (vu8 *)regs + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize; + const vu8 *additionalData = stackDump + dumpHeader->stackDumpSize; + + const char *handledExceptionNames[] = { + "FIQ", "undefined instruction", "prefetch abort", "data abort" + }; + + const char *specialExceptions[] = { + "(kernel panic)", "(svcBreak)" + }; + + const char *registerNames[] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", + "SP", "LR", "PC", "CPSR", "FPEXC" + }; + + char hexString[] = "00000000"; + + initScreens(); + + drawString("An exception occurred", true, 10, 10, COLOR_RED); + u32 posY = drawString(dumpHeader->processor == 11 ? "Processor: ARM11 (core )" : "Processor: ARM9", true, 10, 30, COLOR_WHITE); + if(dumpHeader->processor == 11) drawCharacter('0' + dumpHeader->core, true, 10 + 29 * SPACING_X, 30, COLOR_WHITE); + + posY = drawString("Exception type: ", true, 10, posY + SPACING_Y, COLOR_WHITE); + drawString(handledExceptionNames[dumpHeader->type], true, 10 + 17 * SPACING_X, posY, COLOR_WHITE); + + if(dumpHeader->type == 2) { - const vu32 *regs = (vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader)); - const vu8 *stackDump = (vu8 *)regs + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize; - const vu8 *additionalData = stackDump + dumpHeader->stackDumpSize; - - const char *handledExceptionNames[] = { - "FIQ", "undefined instruction", "prefetch abort", "data abort" - }; - - const char *specialExceptions[] = { - "(kernel panic)", "(svcBreak)" - }; - - const char *registerNames[] = { - "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", - "SP", "LR", "PC", "CPSR", "FPEXC" - }; - - char hexString[] = "00000000"; - - initScreens(); - - drawString("An exception occurred", true, 10, 10, COLOR_RED); - u32 posY = drawString(dumpHeader->processor == 11 ? "Processor: ARM11 (core )" : "Processor: ARM9", true, 10, 30, COLOR_WHITE); - if(dumpHeader->processor == 11) drawCharacter('0' + dumpHeader->core, true, 10 + 29 * SPACING_X, 30, COLOR_WHITE); - - posY = drawString("Exception type: ", true, 10, posY + SPACING_Y, COLOR_WHITE); - drawString(handledExceptionNames[dumpHeader->type], true, 10 + 17 * SPACING_X, posY, COLOR_WHITE); - - if(dumpHeader->type == 2) + if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 4) { - if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 4) - { - u32 instr = *(vu32 *)(stackDump - 4); - if(instr == 0xE12FFF7E) drawString(specialExceptions[0], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE); - else if(instr == 0xEF00003C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE); - } - else if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 2) - { - u16 instr = *(vu16 *)(stackDump - 2); - if(instr == 0xDF3C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE); - } + u32 instr = *(vu32 *)(stackDump - 4); + if(instr == 0xE12FFF7E) drawString(specialExceptions[0], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE); + else if(instr == 0xEF00003C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE); } - - if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0) + else if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 2) { - char processName[] = "Current process: "; - memcpy(processName + sizeof(processName) - 9, (void *)additionalData, 8); - posY = drawString(processName, true, 10, posY + SPACING_Y, COLOR_WHITE); + u16 instr = *(vu16 *)(stackDump - 2); + if(instr == 0xDF3C) drawString(specialExceptions[1], true, 10 + 32 * SPACING_X, posY, COLOR_WHITE); } - - posY += SPACING_Y; - - for(u32 i = 0; i < 17; i += 2) - { - posY = drawString(registerNames[i], true, 10, posY + SPACING_Y, COLOR_WHITE); - hexItoa(regs[i], hexString, 8, true); - drawString(hexString, true, 10 + 7 * SPACING_X, posY, COLOR_WHITE); - - if(i != 16 || dumpHeader->processor != 9) - { - drawString(registerNames[i + 1], true, 10 + 22 * SPACING_X, posY, COLOR_WHITE); - hexItoa(i == 16 ? regs[20] : regs[i + 1], hexString, 8, true); - drawString(hexString, true, 10 + 29 * SPACING_X, posY, COLOR_WHITE); - } - } - - posY += SPACING_Y; - - u32 mode = regs[16] & 0xF; - if(dumpHeader->type == 3 && (mode == 7 || mode == 11)) - posY = drawString("Incorrect dump: failed to dump code and/or stack", true, 10, posY + SPACING_Y, COLOR_YELLOW) + SPACING_Y; - - u32 posYBottom = drawString("Stack dump:", false, 10, 10, COLOR_WHITE) + SPACING_Y; - - for(u32 line = 0; line < 19 && stackDump < additionalData; line++) - { - hexItoa(regs[13] + 8 * line, hexString, 8, true); - posYBottom = drawString(hexString, false, 10, posYBottom + SPACING_Y, COLOR_WHITE); - drawCharacter(':', false, 10 + 8 * SPACING_X, posYBottom, COLOR_WHITE); - - for(u32 i = 0; i < 8 && stackDump < additionalData; i++, stackDump++) - { - char byteString[] = "00"; - hexItoa(*stackDump, byteString, 2, false); - drawString(byteString, false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE); - } - } - - char path[36]; - char fileName[] = "crash_dump_00000000.dmp"; - const char *pathFolder = dumpHeader->processor == 9 ? "dumps/arm9" : "dumps/arm11"; - - findDumpFile(pathFolder, fileName); - memcpy(path, pathFolder, strlen(pathFolder) + 1); - concatenateStrings(path, "/"); - concatenateStrings(path, fileName); - - if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize)) - { - posY = drawString("You can find a dump in the following file:", true, 10, posY + SPACING_Y, COLOR_WHITE); - posY = drawString(path, true, 10, posY + SPACING_Y, COLOR_WHITE) + SPACING_Y; - } - else posY = drawString("Error writing the dump file", true, 10, posY + SPACING_Y, COLOR_RED); - - drawString("Press any button to shutdown", true, 10, posY + SPACING_Y, COLOR_WHITE); - - memset32((void *)dumpHeader, 0, dumpHeader->totalSize); - - waitInput(false); - mcuPowerOff(); } + + if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0) + { + char processName[] = "Current process: "; + memcpy(processName + sizeof(processName) - 9, (void *)additionalData, 8); + posY = drawString(processName, true, 10, posY + SPACING_Y, COLOR_WHITE); + } + + posY += SPACING_Y; + + for(u32 i = 0; i < 17; i += 2) + { + posY = drawString(registerNames[i], true, 10, posY + SPACING_Y, COLOR_WHITE); + hexItoa(regs[i], hexString, 8, true); + drawString(hexString, true, 10 + 7 * SPACING_X, posY, COLOR_WHITE); + + if(i != 16 || dumpHeader->processor != 9) + { + drawString(registerNames[i + 1], true, 10 + 22 * SPACING_X, posY, COLOR_WHITE); + hexItoa(i == 16 ? regs[20] : regs[i + 1], hexString, 8, true); + drawString(hexString, true, 10 + 29 * SPACING_X, posY, COLOR_WHITE); + } + } + + posY += SPACING_Y; + + u32 mode = regs[16] & 0xF; + if(dumpHeader->type == 3 && (mode == 7 || mode == 11)) + posY = drawString("Incorrect dump: failed to dump code and/or stack", true, 10, posY + SPACING_Y, COLOR_YELLOW) + SPACING_Y; + + u32 posYBottom = drawString("Stack dump:", false, 10, 10, COLOR_WHITE) + SPACING_Y; + + for(u32 line = 0; line < 19 && stackDump < additionalData; line++) + { + hexItoa(regs[13] + 8 * line, hexString, 8, true); + posYBottom = drawString(hexString, false, 10, posYBottom + SPACING_Y, COLOR_WHITE); + drawCharacter(':', false, 10 + 8 * SPACING_X, posYBottom, COLOR_WHITE); + + for(u32 i = 0; i < 8 && stackDump < additionalData; i++, stackDump++) + { + char byteString[] = "00"; + hexItoa(*stackDump, byteString, 2, false); + drawString(byteString, false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE); + } + } + + char path[36]; + char fileName[] = "crash_dump_00000000.dmp"; + const char *pathFolder = dumpHeader->processor == 9 ? "dumps/arm9" : "dumps/arm11"; + + findDumpFile(pathFolder, fileName); + memcpy(path, pathFolder, strlen(pathFolder) + 1); + concatenateStrings(path, "/"); + concatenateStrings(path, fileName); + + if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize)) + { + posY = drawString("You can find a dump in the following file:", true, 10, posY + SPACING_Y, COLOR_WHITE); + posY = drawString(path, true, 10, posY + SPACING_Y, COLOR_WHITE) + SPACING_Y; + } + else posY = drawString("Error writing the dump file", true, 10, posY + SPACING_Y, COLOR_RED); + + drawString("Press any button to shutdown", true, 10, posY + SPACING_Y, COLOR_WHITE); + + memset32((void *)dumpHeader, 0, dumpHeader->totalSize); + + waitInput(false); + mcuPowerOff(); } \ No newline at end of file diff --git a/source/firm.c b/source/firm.c index 30cac88..a3ebb7e 100755 --- a/source/firm.c +++ b/source/firm.c @@ -36,7 +36,7 @@ static Firm *firm = (Firm *)0x24000000; -u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode) +static inline bool loadFirmFromStorage(FirmwareType firmType) { const char *firmwareFiles[] = { "firmware.bin", @@ -53,6 +53,30 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora "cetk_sysupdater" }; + u32 firmSize = fileRead(firm, firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)firmType], 0x400000 + sizeof(Cxi) + 0x200); + + if(!firmSize) return false; + + if(firmSize <= sizeof(Cxi) + 0x200) error("The FIRM in /luma is not valid."); + + if(memcmp(firm, "FIRM", 4) != 0) + { + u8 cetk[0xA50]; + + if(fileRead(cetk, firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk) || + !decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize)) + error("The FIRM in /luma is encrypted or corrupted."); + } + + //Check that the FIRM is right for the console from the ARM9 section address + if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800)) + error("The FIRM in /luma is not for this console."); + + return true; +} + +u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode) +{ //Load FIRM from CTRNAND u32 firmVersion = firmRead(firm, (u32)*firmType); @@ -77,32 +101,8 @@ u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStora else if(firmVersion < 0x25) mustLoadFromStorage = true; } - if(loadFromStorage || mustLoadFromStorage) - { - u32 firmSize = fileRead(firm, *firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)*firmType], 0x400000 + sizeof(Cxi) + 0x200); - - if(firmSize > 0) - { - if(firmSize <= sizeof(Cxi) + 0x200) error("The FIRM in /luma is not valid."); - - if(memcmp(firm, "FIRM", 4) != 0) - { - u8 cetk[0xA50]; - - if(fileRead(cetk, *firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)*firmType], sizeof(cetk)) != sizeof(cetk) || - !decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize)) - error("The FIRM in /luma is encrypted or corrupted."); - } - - //Check that the FIRM is right for the console from the ARM9 section address - if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800)) - error("The FIRM in /luma is not for this console."); - - firmVersion = 0xFFFFFFFF; - } - } - - if(firmVersion != 0xFFFFFFFF) + if((loadFromStorage || mustLoadFromStorage) && loadFirmFromStorage(*firmType)) firmVersion = 0xFFFFFFFF; + else { 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."); @@ -310,10 +310,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo srcModuleSize = ((Cxi *)src)->ncch.contentSize * 0x200; const char *moduleName = ((Cxi *)src)->exHeader.systemControlInfo.appTitle; - bool loadedModule; - - if(!loadFromStorage) loadedModule = false; - else + if(loadFromStorage) { char fileName[24] = "sysmodules/"; @@ -323,8 +320,7 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo dstModuleSize = getFileSize(fileName); - if(dstModuleSize == 0) loadedModule = false; - else + if(dstModuleSize != 0) { if(dstModuleSize > maxModuleSize) error(extModuleSizeError); @@ -334,29 +330,26 @@ static inline void copySection0AndInjectSystemModules(FirmwareType firmType, boo memcmp(moduleName, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0) error("An external FIRM module is invalid or corrupted."); - loadedModule = true; + continue; } } - if(!loadedModule) + const u8 *module; + + if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0) { - const u8 *module; - - if(firmType == NATIVE_FIRM && memcmp(moduleName, "loader", 6) == 0) - { - module = injector_bin; - dstModuleSize = injector_bin_size; - } - else - { - module = src; - dstModuleSize = srcModuleSize; - } - - if(dstModuleSize > maxModuleSize) error(extModuleSizeError); - - memcpy(dst, module, dstModuleSize); + module = injector_bin; + dstModuleSize = injector_bin_size; } + else + { + module = src; + dstModuleSize = srcModuleSize; + } + + if(dstModuleSize > maxModuleSize) error(extModuleSizeError); + + memcpy(dst, module, dstModuleSize); } } diff --git a/source/fs.c b/source/fs.c index f47962f..45d8fce 100644 --- a/source/fs.c +++ b/source/fs.c @@ -66,17 +66,16 @@ bool mountFs(bool isSd, bool switchToCtrNand) u32 fileRead(void *dest, const char *path, u32 maxSize) { FIL file; + + if(f_open(&file, path, FA_READ) != FR_OK) return 0; + u32 ret; - if(f_open(&file, path, FA_READ) != FR_OK) ret = 0; - else - { - u32 size = f_size(&file); - if(dest == NULL) ret = size; - else if(size <= maxSize) - f_read(&file, dest, size, (unsigned int *)&ret); - f_close(&file); - } + u32 size = f_size(&file); + if(dest == NULL) ret = size; + else if(size <= maxSize) + f_read(&file, dest, size, (unsigned int *)&ret); + f_close(&file); return ret; } @@ -89,7 +88,6 @@ u32 getFileSize(const char *path) bool fileWrite(const void *buffer, const char *path, u32 size) { FIL file; - bool ret; switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS)) { @@ -100,8 +98,7 @@ bool fileWrite(const void *buffer, const char *path, u32 size) f_truncate(&file); f_close(&file); - ret = (u32)written == size; - break; + return (u32)written == size; } case FR_NO_PATH: for(u32 i = 1; path[i] != 0; i++) @@ -113,14 +110,10 @@ bool fileWrite(const void *buffer, const char *path, u32 size) f_mkdir(folder); } - ret = fileWrite(buffer, path, size); - break; + return fileWrite(buffer, path, size); default: - ret = false; - break; + return false; } - - return ret; } void fileDelete(const char *path) @@ -158,33 +151,30 @@ void loadPayload(u32 pressed, const char *payloadPath) result = f_findfirst(&dir, &info, path, pattern); - if(result == FR_OK) - { - f_closedir(&dir); + if(result != FR_OK) return; - if(info.fname[0] != 0) - { - concatenateStrings(path, "/"); - concatenateStrings(path, info.altname); - payloadSize = fileRead(payloadAddress, path, maxPayloadSize); - } - } + f_closedir(&dir); + + if(!info.fname[0]) return; + + concatenateStrings(path, "/"); + concatenateStrings(path, info.altname); + payloadSize = fileRead(payloadAddress, path, maxPayloadSize); } else payloadSize = fileRead(payloadAddress, payloadPath, maxPayloadSize); - if(payloadSize > 0) - { - memcpy(loaderAddress, loader_bin, loader_bin_size); - loaderAddress[1] = payloadSize; + if(!payloadSize) return; - backupAndRestoreShaHash(true); - initScreens(); + memcpy(loaderAddress, loader_bin, loader_bin_size); + loaderAddress[1] = payloadSize; - flushDCacheRange(loaderAddress, loader_bin_size); - flushICacheRange(loaderAddress, loader_bin_size); + backupAndRestoreShaHash(true); + initScreens(); - ((void (*)())loaderAddress)(); - } + flushDCacheRange(loaderAddress, loader_bin_size); + flushICacheRange(loaderAddress, loader_bin_size); + + ((void (*)())loaderAddress)(); } void payloadMenu(void) @@ -192,89 +182,87 @@ void payloadMenu(void) DIR dir; char path[62] = "payloads"; - if(f_opendir(&dir, path) == FR_OK) + if(f_opendir(&dir, path) != FR_OK) return; + + FILINFO info; + u32 payloadNum = 0; + char payloadList[20][49]; + + while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0 && payloadNum < 20) { - FILINFO info; - u32 payloadNum = 0; - char payloadList[20][49]; + if(info.fname[0] == '.' || memcmp(info.altname + 8, ".BIN", 4) != 0) continue; + u32 nameLength = strlen(info.fname) - 4; - while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0 && payloadNum < 20) - if(info.fname[0] != '.' && memcmp(info.altname + 8, ".BIN", 4) == 0) - { - u32 nameLength = strlen(info.fname) - 4; - if(nameLength < 49) - { - memcpy(payloadList[payloadNum], info.fname, nameLength); - payloadList[payloadNum][nameLength] = 0; - payloadNum++; - } - } + if(nameLength > 48) continue; - f_closedir(&dir); - - if(payloadNum > 0) - { - initScreens(); - - drawString("Luma3DS chainloader", true, 10, 10, COLOR_TITLE); - drawString("Press A to select, START to quit", true, 10, 10 + SPACING_Y, COLOR_TITLE); - - for(u32 i = 0, posY = 10 + 3 * SPACING_Y, color = COLOR_RED; i < payloadNum; i++, posY += SPACING_Y) - { - drawString(payloadList[i], true, 10, posY, color); - if(color == COLOR_RED) color = COLOR_WHITE; - } - - u32 pressed = 0, - selectedPayload = 0; - - while(pressed != BUTTON_A && pressed != BUTTON_START) - { - do - { - pressed = waitInput(true); - } - while(!(pressed & MENU_BUTTONS)); - - u32 oldSelectedPayload = selectedPayload; - - switch(pressed) - { - case BUTTON_UP: - selectedPayload = !selectedPayload ? payloadNum - 1 : selectedPayload - 1; - break; - case BUTTON_DOWN: - selectedPayload = selectedPayload == payloadNum - 1 ? 0 : selectedPayload + 1; - break; - case BUTTON_LEFT: - selectedPayload = 0; - break; - case BUTTON_RIGHT: - selectedPayload = payloadNum - 1; - break; - default: - continue; - } - - if(oldSelectedPayload == selectedPayload) continue; - - drawString(payloadList[oldSelectedPayload], true, 10, 10 + (3 + oldSelectedPayload) * SPACING_Y, COLOR_WHITE); - drawString(payloadList[selectedPayload], true, 10, 10 + (3 + selectedPayload) * SPACING_Y, COLOR_RED); - } - - if(pressed == BUTTON_A) - { - concatenateStrings(path, "/"); - concatenateStrings(path, payloadList[selectedPayload]); - concatenateStrings(path, ".bin"); - loadPayload(0, path); - error("The payload is too large or corrupted."); - } - - while(HID_PAD & MENU_BUTTONS); - wait(false, 2ULL); - } + memcpy(payloadList[payloadNum], info.fname, nameLength); + payloadList[payloadNum][nameLength] = 0; + payloadNum++; } + + f_closedir(&dir); + + if(!payloadNum) return; + + initScreens(); + + drawString("Luma3DS chainloader", true, 10, 10, COLOR_TITLE); + drawString("Press A to select, START to quit", true, 10, 10 + SPACING_Y, COLOR_TITLE); + + for(u32 i = 0, posY = 10 + 3 * SPACING_Y, color = COLOR_RED; i < payloadNum; i++, posY += SPACING_Y) + { + drawString(payloadList[i], true, 10, posY, color); + if(color == COLOR_RED) color = COLOR_WHITE; + } + + u32 pressed = 0, + selectedPayload = 0; + + while(pressed != BUTTON_A && pressed != BUTTON_START) + { + do + { + pressed = waitInput(true); + } + while(!(pressed & MENU_BUTTONS)); + + u32 oldSelectedPayload = selectedPayload; + + switch(pressed) + { + case BUTTON_UP: + selectedPayload = !selectedPayload ? payloadNum - 1 : selectedPayload - 1; + break; + case BUTTON_DOWN: + selectedPayload = selectedPayload == payloadNum - 1 ? 0 : selectedPayload + 1; + break; + case BUTTON_LEFT: + selectedPayload = 0; + break; + case BUTTON_RIGHT: + selectedPayload = payloadNum - 1; + break; + default: + continue; + } + + if(oldSelectedPayload == selectedPayload) continue; + + drawString(payloadList[oldSelectedPayload], true, 10, 10 + (3 + oldSelectedPayload) * SPACING_Y, COLOR_WHITE); + drawString(payloadList[selectedPayload], true, 10, 10 + (3 + selectedPayload) * SPACING_Y, COLOR_RED); + } + + if(pressed == BUTTON_A) + { + concatenateStrings(path, "/"); + concatenateStrings(path, payloadList[selectedPayload]); + concatenateStrings(path, ".bin"); + loadPayload(0, path); + error("The payload is too large or corrupted."); + } + + while(HID_PAD & MENU_BUTTONS); + wait(false, 2ULL); } u32 firmRead(void *dest, u32 firmType) @@ -292,36 +280,35 @@ u32 firmRead(void *dest, u32 firmType) DIR dir; u32 firmVersion = 0xFFFFFFFF; - if(f_opendir(&dir, path) == FR_OK) + if(f_opendir(&dir, path) != FR_OK) goto exit; + + FILINFO info; + + //Parse the target directory + while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0) { - FILINFO info; + //Not a cxi + if(info.fname[9] == 'a' && strlen(info.fname) != 12) continue; - //Parse the target directory - while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0) - { - //Not a cxi - if(info.fname[9] != 'a' || strlen(info.fname) != 12) continue; + u32 tempVersion = hexAtoi(info.altname, 8); - u32 tempVersion = hexAtoi(info.altname, 8); - - //Found an older cxi - if(tempVersion < firmVersion) firmVersion = tempVersion; - } - - f_closedir(&dir); - - if(firmVersion != 0xFFFFFFFF) - { - //Complete the string with the .app name - concatenateStrings(path, "/00000000.app"); - - //Convert back the .app name from integer to array - hexItoa(firmVersion, path + 35, 8, false); - - if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x200) firmVersion = 0xFFFFFFFF; - } + //Found an older cxi + if(tempVersion < firmVersion) firmVersion = tempVersion; } + f_closedir(&dir); + + if(firmVersion == 0xFFFFFFFF) goto exit; + + //Complete the string with the .app name + concatenateStrings(path, "/00000000.app"); + + //Convert back the .app name from integer to array + hexItoa(firmVersion, path + 35, 8, false); + + if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x200) firmVersion = 0xFFFFFFFF; + +exit: return firmVersion; } diff --git a/source/main.c b/source/main.c index cd83d34..8e18b34 100644 --- a/source/main.c +++ b/source/main.c @@ -78,147 +78,147 @@ void main(void) nandType = (FirmwareSource)BOOTCFG_NAND; firmSource = (FirmwareSource)BOOTCFG_FIRM; isA9lhInstalled = BOOTCFG_A9LH != 0; + + goto boot; } - else + + if(ISA9LH) { - if(ISA9LH) + detectAndProcessExceptionDumps(); + installArm9Handlers(); + } + + firmType = NATIVE_FIRM; + isA9lhInstalled = ISA9LH; + + //Get pressed buttons + u32 pressed = HID_PAD; + + //Save old options and begin saving the new boot configuration + configTemp = (configData.config & 0xFFFFFF00) | ((u32)ISA9LH << 6); + + //If it's a MCU reboot, try to force boot options + if(ISA9LH && CFG_BOOTENV && needConfig != CREATE_CONFIGURATION) + { + //Always force a SysNAND boot when quitting AGB_FIRM + if(CFG_BOOTENV == 7) { - detectAndProcessExceptionDumps(); - installArm9Handlers(); + nandType = FIRMWARE_SYSNAND; + firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM; + + //Flag to prevent multiple boot options-forcing + configTemp |= 1 << 7; + + goto boot; } - firmType = NATIVE_FIRM; - isA9lhInstalled = ISA9LH; - - //Get pressed buttons - u32 pressed = HID_PAD; - - //Save old options and begin saving the new boot configuration - configTemp = (configData.config & 0xFFFFFF00) | ((u32)ISA9LH << 6); - - //If it's a MCU reboot, try to force boot options - if(ISA9LH && CFG_BOOTENV && needConfig != CREATE_CONFIGURATION) + /* Else, force the last used boot options unless a button is pressed + or the no-forcing flag is set */ + if(!pressed && !BOOTCFG_NOFORCEFLAG) { - //Always force a SysNAND boot when quitting AGB_FIRM - if(CFG_BOOTENV == 7) - { - nandType = FIRMWARE_SYSNAND; - firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM; - needConfig = DONT_CONFIGURE; + nandType = (FirmwareSource)BOOTCFG_NAND; + firmSource = (FirmwareSource)BOOTCFG_FIRM; - //Flag to prevent multiple boot options-forcing - configTemp |= 1 << 7; - } - - /* Else, force the last used boot options unless a button is pressed - or the no-forcing flag is set */ - else if(!pressed && !BOOTCFG_NOFORCEFLAG) - { - nandType = (FirmwareSource)BOOTCFG_NAND; - firmSource = (FirmwareSource)BOOTCFG_FIRM; - needConfig = DONT_CONFIGURE; - } - } - - //Boot options aren't being forced - if(needConfig != DONT_CONFIGURE) - { - u32 pinMode = MULTICONFIG(PIN); - bool pinExists = pinMode != 0 && verifyPin(pinMode); - - //If no configuration file exists or SELECT is held, load configuration menu - bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & (BUTTON_SELECT | BUTTON_L1)) == BUTTON_SELECT); - - if(shouldLoadConfigMenu) - { - configMenu(isSdMode, pinExists, pinMode); - - //Update pressed buttons - pressed = HID_PAD; - } - - if(ISA9LH && !CFG_BOOTENV && pressed == SAFE_MODE) - { - nandType = FIRMWARE_SYSNAND; - firmSource = FIRMWARE_SYSNAND; - - isSafeMode = true; - - //If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo - if(pinExists && !shouldLoadConfigMenu) - { - while(HID_PAD & PIN_BUTTONS); - wait(false, 2ULL); - } - } - else - { - u32 splashMode = MULTICONFIG(SPLASH); - - if(splashMode == 1 && loadSplash()) pressed = HID_PAD; - - if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START) - { - payloadMenu(); - pressed = HID_PAD; - } - else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) || - ((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL); - - if(splashMode == 2) loadSplash(); - - //If booting from CTRNAND, always use SysNAND - if(!isSdMode) nandType = FIRMWARE_SYSNAND; - - //If R is pressed, boot the non-updated NAND with the FIRM of the opposite one - else if(pressed & BUTTON_R1) - { - if(CONFIG(USESYSFIRM)) - { - nandType = FIRMWARE_EMUNAND; - firmSource = FIRMWARE_SYSNAND; - } - else - { - nandType = FIRMWARE_SYSNAND; - firmSource = FIRMWARE_EMUNAND; - } - } - - /* Else, boot the NAND the user set to autoboot or the opposite one, depending on L, - with their own FIRM */ - else firmSource = nandType = (CONFIG(AUTOBOOTSYS) == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND; - - //If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config - if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND) - { - FirmwareSource tempNand; - switch(pressed & DPAD_BUTTONS) - { - case BUTTON_UP: - tempNand = FIRMWARE_EMUNAND; - break; - case BUTTON_RIGHT: - tempNand = FIRMWARE_EMUNAND2; - break; - case BUTTON_DOWN: - tempNand = FIRMWARE_EMUNAND3; - break; - case BUTTON_LEFT: - tempNand = FIRMWARE_EMUNAND4; - break; - default: - tempNand = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU)); - break; - } - - if(nandType == FIRMWARE_EMUNAND) nandType = tempNand; - else firmSource = tempNand; - } - } + goto boot; } } + u32 pinMode = MULTICONFIG(PIN); + bool pinExists = pinMode != 0 && verifyPin(pinMode); + + //If no configuration file exists or SELECT is held, load configuration menu + bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & (BUTTON_SELECT | BUTTON_L1)) == BUTTON_SELECT); + + if(shouldLoadConfigMenu) + { + configMenu(isSdMode, pinExists, pinMode); + + //Update pressed buttons + pressed = HID_PAD; + } + + if(ISA9LH && !CFG_BOOTENV && pressed == SAFE_MODE) + { + nandType = FIRMWARE_SYSNAND; + firmSource = FIRMWARE_SYSNAND; + + isSafeMode = true; + + //If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo + if(pinExists && !shouldLoadConfigMenu) + { + while(HID_PAD & PIN_BUTTONS); + wait(false, 2ULL); + } + + goto boot; + } + + u32 splashMode = MULTICONFIG(SPLASH); + + if(splashMode == 1 && loadSplash()) pressed = HID_PAD; + + if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START) + { + payloadMenu(); + pressed = HID_PAD; + } + else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) || + ((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL); + + if(splashMode == 2) loadSplash(); + + //If booting from CTRNAND, always use SysNAND + if(!isSdMode) nandType = FIRMWARE_SYSNAND; + + //If R is pressed, boot the non-updated NAND with the FIRM of the opposite one + else if(pressed & BUTTON_R1) + { + if(CONFIG(USESYSFIRM)) + { + nandType = FIRMWARE_EMUNAND; + firmSource = FIRMWARE_SYSNAND; + } + else + { + nandType = FIRMWARE_SYSNAND; + firmSource = FIRMWARE_EMUNAND; + } + } + + /* Else, boot the NAND the user set to autoboot or the opposite one, depending on L, + with their own FIRM */ + else firmSource = nandType = (CONFIG(AUTOBOOTSYS) == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND; + + //If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config + if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND) + { + FirmwareSource tempNand; + switch(pressed & DPAD_BUTTONS) + { + case BUTTON_UP: + tempNand = FIRMWARE_EMUNAND; + break; + case BUTTON_RIGHT: + tempNand = FIRMWARE_EMUNAND2; + break; + case BUTTON_DOWN: + tempNand = FIRMWARE_EMUNAND3; + break; + case BUTTON_LEFT: + tempNand = FIRMWARE_EMUNAND4; + break; + default: + tempNand = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU)); + break; + } + + if(nandType == FIRMWARE_EMUNAND) nandType = tempNand; + else firmSource = tempNand; + } + +boot: + //If we need to boot EmuNAND, make sure it exists if(nandType != FIRMWARE_SYSNAND) { diff --git a/source/patches.c b/source/patches.c index f49c3d4..e33307b 100644 --- a/source/patches.c +++ b/source/patches.c @@ -35,6 +35,29 @@ #include "utils.h" #include "../build/bundled.h" +static inline void pathChanger(u8 *pos) +{ + const char *pathFile = "path.txt"; + + u32 pathSize = getFileSize(pathFile); + + if(pathSize < 6 || pathSize > 57) return; + + u8 path[pathSize]; + fileRead(path, pathFile, pathSize); + if(path[pathSize - 1] == 0xA) pathSize--; + if(path[pathSize - 1] == 0xD) pathSize--; + + if(pathSize < 6 || pathSize > 57 || path[0] != '/' || memcmp(&path[pathSize - 4], ".bin", 4) != 0) return; + + u16 finalPath[pathSize]; + for(u32 i = 0; i < pathSize; i++) + finalPath[i] = (u16)path[i]; + + u8 *posPath = memsearch(pos, u"sd", reboot_bin_size, 4) + 0xA; + memcpy(posPath, finalPath, pathSize * 2); +} + u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) { u8 *temp = memsearch(pos, "NCCH", size, 4); @@ -51,34 +74,26 @@ u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage) { - const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; - bool res = true; + const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}, + pattern2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; *arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); + *freeK11Space = memsearch(pos, pattern2, size, sizeof(pattern2)); + + if(*arm11ExceptionsPage == NULL || *freeK11Space == NULL) error("Failed to get Kernel11 data."); u32 *arm11SvcTable; - if(*arm11ExceptionsPage == NULL) res = false; - else - { - *arm11ExceptionsPage -= 0xB; - u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch - u32 pointedInstructionVA = 0xFFFF0008 - svcOffset; - *baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case - arm11SvcTable = *arm11SvcHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //SVC handler address - while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL) - } + *arm11ExceptionsPage -= 0xB; + u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch + u32 pointedInstructionVA = 0xFFFF0008 - svcOffset; + *baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case + arm11SvcTable = *arm11SvcHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //SVC handler address + while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL) - const u8 pattern2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + (*freeK11Space)++; - *freeK11Space = memsearch(pos, pattern2, size, sizeof(pattern2)); - - if(*freeK11Space == NULL) res = false; - else (*freeK11Space)++; - - if(!res) error("Failed to get Kernel11 data."); - - return arm11SvcTable; + return arm11SvcTable; } u32 patchSignatureChecks(u8 *pos, u32 size) @@ -86,207 +101,139 @@ u32 patchSignatureChecks(u8 *pos, u32 size) //Look for signature checks const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; - u32 ret; u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2)); - if(off == NULL || temp == NULL) ret = 1; - else - { - u16 *off2 = (u16 *)(temp - 1); + if(off == NULL || temp == NULL) return 1; - *off = off2[0] = 0x2000; - off2[1] = 0x4770; + u16 *off2 = (u16 *)(temp - 1); + *off = off2[0] = 0x2000; + off2[1] = 0x4770; - ret = 0; - } - - return ret; + return 0; } u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr) { //Look for firmlaunch code const u8 pattern[] = {0xE2, 0x20, 0x20, 0x90}; - u32 ret; u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - off -= 0x13; + if(off == NULL) return 1; - //Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1 - u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr); + off -= 0x13; - //Copy firmlaunch code - memcpy(off, reboot_bin, reboot_bin_size); + //Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1 + u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr); - //Put the fOpen offset in the right location - u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4); - *pos_fopen = fOpenOffset; + //Copy firmlaunch code + memcpy(off, reboot_bin, reboot_bin_size); - ret = 0; + //Put the fOpen offset in the right location + u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4); + *pos_fopen = fOpenOffset; - if(CONFIG(USECUSTOMPATH)) - { - const char *pathFile = "path.txt"; + if(CONFIG(USECUSTOMPATH)) pathChanger(off); - u32 pathSize = getFileSize(pathFile); - - if(pathSize > 5 && pathSize < 58) - { - u8 path[pathSize]; - fileRead(path, pathFile, pathSize); - if(path[pathSize - 1] == 0xA) pathSize--; - if(path[pathSize - 1] == 0xD) pathSize--; - - if(pathSize > 5 && pathSize < 56 && path[0] == '/' && memcmp(&path[pathSize - 4], ".bin", 4) == 0) - { - u16 finalPath[pathSize]; - for(u32 i = 0; i < pathSize; i++) - finalPath[i] = (u16)path[i]; - - u8 *pos_path = memsearch(off, u"sd", reboot_bin_size, 4) + 0xA; - memcpy(pos_path, finalPath, pathSize * 2); - } - } - } - } - - return ret; + return 0; } u32 patchFirmWrites(u8 *pos, u32 size) { - u32 ret; - //Look for FIRM writing code u8 *off = memsearch(pos, "exe:", size, 4); - if(off == NULL) ret = 1; - else - { - const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; + if(off == NULL) return 1; - u16 *off2 = (u16 *)memsearch(off - 0x100, pattern, 0x100, sizeof(pattern)); + const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; - if(off2 == NULL) ret = 1; - else - { - off2[0] = 0x2000; - off2[1] = 0x46C0; + u16 *off2 = (u16 *)memsearch(off - 0x100, pattern, 0x100, sizeof(pattern)); - ret = 0; - } - } + if(off2 == NULL) return 1; - return ret; + off2[0] = 0x2000; + off2[1] = 0x46C0; + + return 0; } u32 patchOldFirmWrites(u8 *pos, u32 size) { //Look for FIRM writing code const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB}; - u32 ret; u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - off[0] = 0x2400; - off[1] = 0xE01D; + if(off == NULL) return 1; - ret = 0; - } + off[0] = 0x2400; + off[1] = 0xE01D; - return ret; + return 0; } 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++; + if(off == NULL) return firmVersion == 0xFFFFFFFF ? 0 : 1; - memset32(off, 0, 8); //Zero out the first TitleID in the list + off++; - ret = 0; - } + //Zero out the first TitleID in the list + memset32(off, 0, 8); - return ret; + return 0; } 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); + if(temp == NULL) return 1; - *off = 0x2001; //mov r0, #1 + u16 *off = (u16 *)(temp - 1); + *off = 0x2001; //mov r0, #1 - ret = 0; - } - - return ret; + return 0; } 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--; + if(off == NULL) return 1; - *off = 0x2001; //mov r0, #1 + off--; + *off = 0x2001; //mov r0, #1 - ret = 0; - } - - return ret; + return 0; } 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 + if(off == NULL) return 1; - ret = 0; - } + *off = 0x2301; //mov r3, #1 - return ret; + return 0; } u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space) { - u32 ret = 0; + if(arm11SvcTable[0x7B] != 0) return 0; //Official implementation of svcBackdoor const u8 svcBackdoor[] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff @@ -300,137 +247,107 @@ u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **free 0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0 0x11, 0xFF, 0x2F, 0xE1}; //bx r1 - if(!arm11SvcTable[0x7B]) - { - if(*(u32 *)(*freeK11Space + sizeof(svcBackdoor) - 4) != 0xFFFFFFFF) ret = 1; - else - { - memcpy(*freeK11Space, svcBackdoor, sizeof(svcBackdoor)); + if(*(u32 *)(*freeK11Space + sizeof(svcBackdoor) - 4) != 0xFFFFFFFF) return 1; - arm11SvcTable[0x7B] = baseK11VA + *freeK11Space - pos; - *freeK11Space += sizeof(svcBackdoor); - } - } + memcpy(*freeK11Space, svcBackdoor, sizeof(svcBackdoor)); - return ret; + arm11SvcTable[0x7B] = baseK11VA + *freeK11Space - pos; + *freeK11Space += sizeof(svcBackdoor); + + return 0; } u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode) { - u32 ret; + if(*(u32 *)(*freeK11Space + svcGetCFWInfo_bin_size - 4) != 0xFFFFFFFF) return 1; - if(*(u32 *)(*freeK11Space + svcGetCFWInfo_bin_size - 4) != 0xFFFFFFFF) ret = 1; - else + memcpy(*freeK11Space, svcGetCFWInfo_bin, svcGetCFWInfo_bin_size); + + struct CfwInfo { - memcpy(*freeK11Space, svcGetCFWInfo_bin, svcGetCFWInfo_bin_size); + char magic[4]; - struct CfwInfo - { - char magic[4]; + u8 versionMajor; + u8 versionMinor; + u8 versionBuild; + u8 flags; - u8 versionMajor; - u8 versionMinor; - u8 versionBuild; - u8 flags; + u32 commitHash; - u32 commitHash; + u32 config; + } __attribute__((packed)) *info = (struct CfwInfo *)memsearch(*freeK11Space, "LUMA", svcGetCFWInfo_bin_size, 4); - u32 config; - } __attribute__((packed)) *info = (struct CfwInfo *)memsearch(*freeK11Space, "LUMA", svcGetCFWInfo_bin_size, 4); + const char *rev = REVISION; - const char *rev = REVISION; + info->commitHash = COMMIT_HASH; + info->config = configData.config; + info->versionMajor = (u8)(rev[1] - '0'); + info->versionMinor = (u8)(rev[3] - '0'); - info->commitHash = COMMIT_HASH; - info->config = configData.config; - info->versionMajor = (u8)(rev[1] - '0'); - info->versionMinor = (u8)(rev[3] - '0'); + bool isRelease; - bool isRelease; - - if(rev[4] == '.') - { - info->versionBuild = (u8)(rev[5] - '0'); - isRelease = rev[6] == 0; - } - else isRelease = rev[4] == 0; - - if(isRelease) info->flags = 1; - - if(ISN3DS) info->flags |= 1 << 4; - - if(isSafeMode) info->flags |= 1 << 5; - - arm11SvcTable[0x2E] = baseK11VA + *freeK11Space - pos; //Stubbed svc - *freeK11Space += svcGetCFWInfo_bin_size; - - ret = 0; + if(rev[4] == '.') + { + info->versionBuild = (u8)(rev[5] - '0'); + isRelease = rev[6] == 0; } + else isRelease = rev[4] == 0; - return ret; + if(isRelease) info->flags = 1; + if(ISN3DS) info->flags |= 1 << 4; + if(isSafeMode) info->flags |= 1 << 5; + + arm11SvcTable[0x2E] = baseK11VA + *freeK11Space - pos; //Stubbed svc + *freeK11Space += svcGetCFWInfo_bin_size; + + return 0; } u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) { const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C}; - u32 ret; u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - if(temp == NULL) ret = 1; - else + if(temp == NULL) return 1; + + u32 *off = (u32 *)(temp - 0xA); + + for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40 { - u32 *off = (u32 *)(temp - 0xA); + //Discard everything that's not str rX, [r0, #imm](!) + if((*off & 0xFE5F0000) != 0xE4000000) continue; - for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40 - { - //Discard everything that's not str rX, [r0, #imm](!) - if((*off & 0xFE5F0000) == 0xE4000000) - { - u32 rD = (*off >> 12) & 0xF, - offset = (*off & 0xFFF) * ((((*off >> 23) & 1) == 0) ? -1 : 1); - bool writeback = ((*off >> 21) & 1) != 0, - pre = ((*off >> 24) & 1) != 0; + u32 rD = (*off >> 12) & 0xF, + offset = (*off & 0xFFF) * ((((*off >> 23) & 1) == 0) ? -1 : 1); + bool writeback = ((*off >> 21) & 1) != 0, + pre = ((*off >> 24) & 1) != 0; - u32 addr = r0 + ((pre || !writeback) ? offset : 0); - if((addr & 7) != 0 && addr != 0x08000014 && addr != 0x08000004) *off = 0xE1A00000; //nop - else *off = 0xE5800000 | (rD << 12) | (addr & 0xFFF); //Preserve IRQ and SVC handlers + u32 addr = r0 + ((pre || !writeback) ? offset : 0); + if((addr & 7) != 0 && addr != 0x08000014 && addr != 0x08000004) *off = 0xE1A00000; //nop + else *off = 0xE5800000 | (rD << 12) | (addr & 0xFFF); //Preserve IRQ and SVC handlers - if(!pre) addr += offset; - if(writeback) r0 = addr; - } - } - - ret = 0; + if(!pre) addr += offset; + if(writeback) r0 = addr; } - return ret; + return 0; } u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset) { const u8 pattern[] = {0x1B, 0x50, 0xA0, 0xE3}, //Get TitleID from CodeSet pattern2[] = {0xE8, 0x13, 0x00, 0x02}; //Call exception dispatcher - bool ret = true; u32 *loadCodeSet = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - - if(loadCodeSet == NULL) ret = false; - else - { - loadCodeSet -= 2; - *codeSetOffset = *loadCodeSet & 0xFFF; - } - u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2)); - u32 stackAddress; + if(loadCodeSet == NULL || temp == NULL) error("Failed to get ARM11 exception handlers data."); - if(temp == NULL) ret = false; - else stackAddress = *(u32 *)(temp + 9); + loadCodeSet -= 2; + *codeSetOffset = *loadCodeSet & 0xFFF; - if(!ret) error("Failed to get ARM11 exception handlers data."); - - return stackAddress; + return *(u32 *)(temp + 9); } u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) @@ -439,22 +356,17 @@ u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) //Look for the svc handler const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr - u32 ret; u32 *arm9SvcTable = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - if(arm9SvcTable == NULL) ret = 1; - else - { - while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL) + if(arm9SvcTable == NULL) return 1; - u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); - *addr = 0xE12FFF7F; + while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL) - ret = 0; - } + u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); + *addr = 0xE12FFF7F; - return ret; + return 0; } void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable) @@ -467,76 +379,54 @@ void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable) u32 patchKernel9Panic(u8 *pos, u32 size) { const u8 pattern[] = {0xFF, 0xEA, 0x04, 0xD0}; - u32 ret; u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - if(temp == NULL) ret = 1; - else - { - u32 *off = (u32 *)(temp - 0x12); - *off = 0xE12FFF7E; + if(temp == NULL) return 1; - ret = 0; - } + u32 *off = (u32 *)(temp - 0x12); + *off = 0xE12FFF7E; - return ret; + return 0; } u32 patchKernel11Panic(u8 *pos, u32 size) { const u8 pattern[] = {0x02, 0x0B, 0x44, 0xE2}; - u32 ret; u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - *off = 0xE12FFF7E; + if(off == NULL) return 1; - ret = 0; - } + *off = 0xE12FFF7E; - return ret; + return 0; } u32 patchP9AccessChecks(u8 *pos, u32 size) { const u8 pattern[] = {0x00, 0x08, 0x49, 0x68}; - u32 ret; u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - if(temp == NULL) ret = 1; - else - { - u16 *off = (u16 *)(temp - 3); + if(temp == NULL) return 1; - off[0] = 0x2001; //mov r0, #1 - off[1] = 0x4770; //bx lr + u16 *off = (u16 *)(temp - 3); + off[0] = 0x2001; //mov r0, #1 + off[1] = 0x4770; //bx lr - ret = 0; - } - - return ret; + return 0; } u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos) { - u32 ret; - while(*arm11SvcHandler != 0xE11A0E1B && arm11SvcHandler < endPos) arm11SvcHandler++; //TST R10, R11,LSL LR - if(arm11SvcHandler == endPos) ret = 1; - else - { - *arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1 + if(arm11SvcHandler == endPos) return 1; - ret = 0; - } + *arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1 - return ret; + return 0; } u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space) @@ -544,214 +434,159 @@ u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space) /* We have to detour a function in the ARM11 kernel because builtin modules are compressed in memory and are only decompressed at runtime */ - u32 ret; - //Check that we have enough free space - if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) != 0xFFFFFFFF) ret = 0; - else - { - //Look for the code that decompresses the .code section of the builtin modules - const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D}; + if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) != 0xFFFFFFFF) return 0; - u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); + //Look for the code that decompresses the .code section of the builtin modules + const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D}; - if(temp == NULL) ret = 1; - else - { - //Inject our code into the free space - memcpy(*freeK11Space, k11modules_bin, k11modules_bin_size); + u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - u32 *off = (u32 *)(temp - 0xB); + if(temp == NULL) return 1; - //Inject a jump (BL) instruction to our code at the offset we found - *off = 0xEB000000 | (((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF); + //Inject our code into the free space + memcpy(*freeK11Space, k11modules_bin, k11modules_bin_size); - *freeK11Space += k11modules_bin_size; + u32 *off = (u32 *)(temp - 0xB); - ret = 0; - } - } + //Inject a jump (BL) instruction to our code at the offset we found + *off = 0xEB000000 | (((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF); - return ret; + *freeK11Space += k11modules_bin_size; + + return 0; } u32 patchUnitInfoValueSet(u8 *pos, u32 size) { //Look for UNITINFO value being set during kernel sync const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13}; - u32 ret; u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - off[0] = ISDEVUNIT ? 0 : 1; - off[3] = 0xE3; + if(off == NULL) return 1; - ret = 0; - } + off[0] = ISDEVUNIT ? 0 : 1; + off[3] = 0xE3; - return ret; + return 0; } u32 patchLgySignatureChecks(u8 *pos, u32 size) { const u8 pattern[] = {0x47, 0xC1, 0x17, 0x49}; - u32 ret; u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - if(temp == NULL) ret = 1; - else - { - u16 *off = (u16 *)(temp + 1); + if(temp == NULL) return 1; - off[0] = 0x2000; - off[1] = 0xB04E; - off[2] = 0xBD70; + u16 *off = (u16 *)(temp + 1); + off[0] = 0x2000; + off[1] = 0xB04E; + off[2] = 0xBD70; - ret = 0; - } - - return ret; + return 0; } u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size) { const u8 pattern[] = {0x20, 0xF6, 0xE7, 0x7F}; - u32 ret; u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - if(temp == NULL) ret = 1; - else - { - u16 *off = (u16 *)(temp - 1); + if(temp == NULL) return 1; - *off = 0x2001; //mov r0, #1 + u16 *off = (u16 *)(temp - 1); + *off = 0x2001; //mov r0, #1 - ret = 0; - } - - return ret; + return 0; } u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size) { const u8 pattern[] = {0xC0, 0x30, 0x06, 0xF0}; - u32 ret; u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - off[1] = 0x2000; - off[2] = 0; + if(off == NULL) return 1; - ret = 0; - } + off[1] = 0x2000; + off[2] = 0; - return ret; + return 0; } u32 patchTwlWhitelistChecks(u8 *pos, u32 size) { const u8 pattern[] = {0x22, 0x00, 0x20, 0x30}; - u32 ret; u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - off[2] = 0x2000; - off[3] = 0; + if(off == NULL) return 1; - ret = 0; - } + off[2] = 0x2000; + off[3] = 0; - return ret; + return 0; } u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion) { const u8 pattern[] = {0x25, 0x20, 0x00, 0x0E}; - u32 ret; u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); if(temp == NULL) { - if(firmVersion == 0xFFFFFFFF) ret = patchOldTwlFlashcartChecks(pos, size); - else ret = 1; - } - else - { - u16 *off = (u16 *)(temp + 3); + if(firmVersion == 0xFFFFFFFF) return patchOldTwlFlashcartChecks(pos, size); - off[0] = off[6] = off[0xC] = 0x2001; //mov r0, #1 - off[1] = off[7] = off[0xD] = 0; //nop - - ret = 0; + return 1; } - return ret; + u16 *off = (u16 *)(temp + 3); + off[0] = off[6] = off[0xC] = 0x2001; //mov r0, #1 + off[1] = off[7] = off[0xD] = 0; //nop + + return 0; } u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size) { const u8 pattern[] = {0x06, 0xF0, 0xA0, 0xFD}; - u32 ret; u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - off[0] = off[6] = 0x2001; //mov r0, #1 - off[1] = off[7] = 0; //nop + if(off == NULL) return 1; - ret = 0; - } + off[0] = off[6] = 0x2001; //mov r0, #1 + off[1] = off[7] = 0; //nop - return ret; + return 0; } u32 patchTwlShaHashChecks(u8 *pos, u32 size) { const u8 pattern[] = {0x10, 0xB5, 0x14, 0x22}; - u32 ret; u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - off[0] = 0x2001; //mov r0, #1 - off[1] = 0x4770; + if(off == NULL) return 1; - ret = 0; - } + off[0] = 0x2001; //mov r0, #1 + off[1] = 0x4770; - return ret; + return 0; } u32 patchAgbBootSplash(u8 *pos, u32 size) { const u8 pattern[] = {0x00, 0x00, 0x01, 0xEF}; - u32 ret; u8 *off = memsearch(pos, pattern, size, sizeof(pattern)); - if(off == NULL) ret = 1; - else - { - off[2] = 0x26; + if(off == NULL) return 1; - ret = 0; - } + off[2] = 0x26; - return ret; + return 0; } \ No newline at end of file diff --git a/source/pin.c b/source/pin.c index 238d216..6dd877d 100644 --- a/source/pin.c +++ b/source/pin.c @@ -85,16 +85,20 @@ void newPin(bool allowSkipping, u32 pinMode) if(pressed & BUTTON_START) return; - if(pressed & BUTTON_SELECT) reset = true; - else if(pressed != 0) + if(pressed & BUTTON_SELECT) { - enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password - - //Visualize character on screen - drawCharacter(enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE); - - cnt++; + reset = true; + continue; } + + if(!pressed) continue; + + enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password + + //Visualize character on screen + drawCharacter(enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE); + + cnt++; } PinData pin; @@ -188,26 +192,29 @@ bool verifyPin(u32 pinMode) pressed &= PIN_BUTTONS; - if(pressed & BUTTON_SELECT) reset = true; - else if(pressed != 0) + if(pressed & BUTTON_SELECT) { - enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password + reset = true; + continue; + } - //Visualize character on screen - drawCharacter((char)enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE); + if(!pressed) continue; - if(++cnt >= lengthBlock[0]) - { - computePinHash(tmp, enteredPassword); - unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0; + enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password - if(!unlock) - { - reset = true; + //Visualize character on screen + drawCharacter((char)enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE); - drawString("Wrong PIN, try again", true, 10, 10 + 5 * SPACING_Y, COLOR_RED); - } - } + if(++cnt < lengthBlock[0]) continue; + + computePinHash(tmp, enteredPassword); + unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0; + + if(!unlock) + { + reset = true; + + drawString("Wrong PIN, try again", true, 10, 10 + 5 * SPACING_Y, COLOR_RED); } } diff --git a/source/screen.c b/source/screen.c index 9b44da6..2448f67 100644 --- a/source/screen.c +++ b/source/screen.c @@ -57,6 +57,7 @@ void __attribute__((naked)) arm11Stub(void) static void invokeArm11Function(void (*func)()) { static bool hasCopiedStub = false; + if(!hasCopiedStub) { memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30); diff --git a/source/utils.c b/source/utils.c index 28d31c1..dda72e9 100644 --- a/source/utils.c +++ b/source/utils.c @@ -56,7 +56,6 @@ static u64 chrono(bool isMilliseconds) u32 waitInput(bool isMenu) { static u64 dPadDelay = 0ULL; - bool pressedKey = false; u32 key, oldKey = HID_PAD; @@ -66,23 +65,24 @@ u32 waitInput(bool isMenu) startChrono(); } - while(!pressedKey) + while(true) { key = HID_PAD; if(!key) { if(i2cReadRegister(I2C_DEV_MCU, 0x10) == 1) mcuPowerOff(); - oldKey = key; + oldKey = 0; dPadDelay = 0; + continue; } - else if((key != oldKey) || (isMenu && (key & DPAD_BUTTONS) != 0 && (chrono(true) >= dPadDelay))) - { - //Make sure the key is pressed - u32 i; - for(i = 0; i < 0x13000 && key == HID_PAD; i++); - if(i == 0x13000) pressedKey = true; - } + + if(key == oldKey && (!isMenu || (!(key & DPAD_BUTTONS) || chrono(true) < dPadDelay))) continue; + + //Make sure the key is pressed + u32 i; + for(i = 0; i < 0x13000 && key == HID_PAD; i++); + if(i == 0x13000) break; } return key;