From e231275cbe304b546d7793283a6738f3fe6ed1ca Mon Sep 17 00:00:00 2001 From: Aurora Wright Date: Fri, 5 May 2017 20:16:44 +0200 Subject: [PATCH] Rewrite the LayeredFS code to check the mount name properly and use ro/data padding for the custom path --- injector/patches/romfsredir.s | 27 ++++++-- injector/source/loader.c | 2 +- injector/source/patcher.c | 126 ++++++++++++++++++++-------------- injector/source/patcher.h | 2 +- 4 files changed, 98 insertions(+), 59 deletions(-) diff --git a/injector/patches/romfsredir.s b/injector/patches/romfsredir.s index e8ae6c1..bfe3585 100644 --- a/injector/patches/romfsredir.s +++ b/injector/patches/romfsredir.s @@ -52,16 +52,16 @@ _start: ; it from its original archive like nothing happened fsRedir: stmfd sp!, {r0-r12, lr} - ldrb r12, [r1] - cmp r12, #0x72 ; 'r', should include "rom:", "rom2:" and "rex:" - ldrne r11, [pc, #updateRomFsStart-.-8] - cmpne r12, r11 - bne endRedir + addr r3, romFsMount + bl compare + addne r3, pc, #updateRomFsMount-.-8 + blne compare + bne endRedir sub sp, sp, #0x400 pathRedir: stmfd sp!, {r0-r3} add r0, sp, #0x10 - addr r3, customPath + load r3, customPath pathRedir_1: ldrb r2, [r3], #1 strh r2, [r0], #2 @@ -89,13 +89,26 @@ _start: bxeq lr b _fsRedir + 4 + compare: + mov r9, r1 + add r10, r3, #4 + loop: + ldrb r12, [r3], #1 + ldrb r11, [r9], #2 + cmp r11, r12 + bxne lr + cmp r10, r3 + bne loop + bx lr + .pool .align 4 archiveName : .dcb "lf:", 0 fsMountArchive : .word 0xdead0005 fsRegisterArchive : .word 0xdead0006 archiveId : .word 0xdead0007 - updateRomFsStart : .word 0xdead0008 + romFsMount : .dcb "rom:" + updateRomFsMount : .word 0xdead0008 customPath : .word 0xdead0004 .close diff --git a/injector/source/loader.c b/injector/source/loader.c index faae6f4..5a49a3a 100644 --- a/injector/source/loader.c +++ b/injector/source/loader.c @@ -158,7 +158,7 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i u16 progver = g_exheader.codesetinfo.flags.remasterversion[0] | (g_exheader.codesetinfo.flags.remasterversion[1] << 8); // patch - patchCode(progid, progver, (u8 *)shared->text_addr, shared->total_size << 12, g_exheader.codesetinfo.text.codesize, g_exheader.codesetinfo.ro.codesize); + patchCode(progid, progver, (u8 *)shared->text_addr, shared->total_size << 12, g_exheader.codesetinfo.text.codesize, g_exheader.codesetinfo.ro.codesize, g_exheader.codesetinfo.data.codesize, g_exheader.codesetinfo.ro.address, g_exheader.codesetinfo.data.address); return 0; } diff --git a/injector/source/patcher.c b/injector/source/patcher.c index 83bcd0c..1d6e4f2 100644 --- a/injector/source/patcher.c +++ b/injector/source/patcher.c @@ -328,48 +328,72 @@ static inline bool findLayeredFsSymbols(u8 *code, u32 size, u32 *fsMountArchive, return found == 4; } -static inline bool findLayeredFsPayloadOffset(u8 *code, u32 size, u32 *payloadOffset) +static inline bool findLayeredFsPayloadOffset(u8 *code, u32 size, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress, u32 *payloadOffset, u32 *pathOffset, u32 *pathAddress) { + u32 roundedTextSize = ((size + 4095) & 0xFFFFF000), + roundedRoSize = ((roSize + 4095) & 0xFFFFF000), + roundedDataSize = ((dataSize + 4095) & 0xFFFFF000); + //First check for sufficient padding at the end of the .text segment - if(((size + 4095) & 0xFFFFF000) - size >= romfsredir_bin_size) + if(roundedTextSize - size >= romfsredir_bin_size) *payloadOffset = size; + else { - *payloadOffset = size; + //If there isn't enough padding look for the "throwFatalError" function to replace + u32 svcConnectToPort = 0xFFFFFFFF; - return true; - } - - //If there isn't enough padding look for the "throwFatalError" function to replace - u32 svcConnectToPort = 0xFFFFFFFF; - - for(u32 addr = 4; svcConnectToPort == 0xFFFFFFFF && addr <= size - 4; addr += 4) - { - if(*(u32 *)(code + addr) == 0xEF00002D) - svcConnectToPort = addr - 4; - } - - if(svcConnectToPort != 0xFFFFFFFF) - { - u32 func = 0xFFFFFFFF; - - for(u32 i = 4; func == 0xFFFFFFFF && i <= size - 4; i += 4) + for(u32 addr = 4; svcConnectToPort == 0xFFFFFFFF && addr <= size - 4; addr += 4) { - if(*(u32 *)(code + i) != MAKE_BRANCH_LINK(i, svcConnectToPort)) continue; - - func = findFunctionStart(code, i); - - for(u32 pos = func + 4; func != 0xFFFFFFFF && pos <= size - 4 && *(u16 *)(code + pos + 2) != 0xE92D; pos += 4) - if(*(u32 *)(code + pos) == 0xE200167E) func = 0xFFFFFFFF; + if(*(u32 *)(code + addr) == 0xEF00002D) + svcConnectToPort = addr - 4; } - if(func != 0xFFFFFFFF) + if(svcConnectToPort != 0xFFFFFFFF) { - *payloadOffset = func; + u32 func = 0xFFFFFFFF; - return true; + for(u32 i = 4; func == 0xFFFFFFFF && i <= size - 4; i += 4) + { + if(*(u32 *)(code + i) != MAKE_BRANCH_LINK(i, svcConnectToPort)) continue; + + func = findFunctionStart(code, i); + + for(u32 pos = func + 4; func != 0xFFFFFFFF && pos <= size - 4 && *(u16 *)(code + pos + 2) != 0xE92D; pos += 4) + if(*(u32 *)(code + pos) == 0xE200167E) func = 0xFFFFFFFF; + } + + if(func != 0xFFFFFFFF) + *payloadOffset = func; } } - return false; + if(roundedRoSize - roSize >= 39) + { + *pathOffset = roundedTextSize + roSize; + *pathAddress = roAddress + roSize; + } + else if(roundedDataSize - dataSize >= 39) + { + *pathOffset = roundedTextSize + roundedRoSize + dataSize; + *pathAddress = dataAddress + dataSize; + } + else + { + u32 strSpace = 0xFFFFFFFF; + + for(u32 addr = 0; strSpace == 0xFFFFFFFF && addr <= size - 4; addr += 4) + { + if(*(u32 *)(code + addr) == 0xE3A00B42) + strSpace = findFunctionStart(code, addr); + } + + if(strSpace != 0xFFFFFFFF) + { + *pathOffset = strSpace; + *pathAddress = 0x100000 + strSpace; + } + } + + return *payloadOffset != 0 && *pathOffset != 0; } static inline bool applyCodeIpsPatch(u64 progId, u8 *code, u32 size) @@ -514,7 +538,7 @@ exit: return ret; } -static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize) +static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress) { /* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/romfs" If it exists it should be a folder containing ROMFS files */ @@ -530,23 +554,23 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize) fsRegisterArchive = 0xFFFFFFFF, fsTryOpenFile = 0xFFFFFFFF, fsOpenFileDirectly = 0xFFFFFFFF, - payloadOffset; + payloadOffset = 0, + pathOffset = 0, + pathAddress; if(!findLayeredFsSymbols(code, textSize, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly) || - !findLayeredFsPayloadOffset(code, textSize, &payloadOffset)) return false; + !findLayeredFsPayloadOffset(code, textSize, roSize, dataSize, roAddress, dataAddress, &payloadOffset, &pathOffset, &pathAddress)) return false; - static const char *updateRomFsMounts[] = { "patch:", - "ext:" }; - char updateRomFsStart = 'r'; - u32 i; + static const char *updateRomFsMounts[] = { "rom2:", + "rex:" + "patch:", + "ext:", + "rom:" }; + u32 updateRomFsIndex; //Locate update RomFSes - for(i = 0; i < sizeof(updateRomFsMounts) / sizeof(char *); i++) - { - if(memsearch(code, updateRomFsMounts[i], size, strnlen(updateRomFsMounts[i], 255)) != NULL) break; - } - - if(i != sizeof(updateRomFsMounts) / sizeof(char *)) updateRomFsStart = updateRomFsMounts[i][0]; + for(updateRomFsIndex = 0; updateRomFsIndex < sizeof(updateRomFsMounts) / sizeof(char *) - 1; updateRomFsIndex++) + if(memsearch(code, updateRomFsMounts[updateRomFsIndex], size, strnlen(updateRomFsMounts[updateRomFsIndex], 255)) != NULL) break; //Setup the payload u8 *payload = code + payloadOffset; @@ -554,7 +578,7 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize) //Insert symbols in the payload u32 *payload32 = (u32 *)payload; - for(i = 0; i < romfsredir_bin_size / 4; i++) + for(u32 i = 0; i < romfsredir_bin_size / 4; i++) { switch(payload32[i]) { @@ -571,8 +595,7 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize) payload32[i] = MAKE_BRANCH(payloadOffset + i * 4, fsTryOpenFile + 4); break; case 0xdead0004: - memcpy(payload32 + i, "lf:", 3); - memcpy((u8 *)(payload32 + i) + 3, path, sizeof(path)); + payload32[i] = pathAddress; break; case 0xdead0005: payload32[i] = 0x100000 + fsMountArchive; @@ -584,11 +607,14 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize) payload32[i] = archiveId; break; case 0xdead0008: - payload32[i] = (u32)updateRomFsStart; + memcpy(payload32 + i, updateRomFsMounts[updateRomFsIndex], 4); break; } } + memcpy(code + pathOffset, "lf:", 3); + memcpy(code + pathOffset + 3, path, sizeof(path)); + //Place the hooks *(u32 *)(code + fsOpenFileDirectly) = MAKE_BRANCH(fsOpenFileDirectly, payloadOffset); *(u32 *)(code + fsTryOpenFile) = MAKE_BRANCH(fsTryOpenFile, payloadOffset + 12); @@ -596,7 +622,7 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize) return true; } -void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize) +void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress) { loadCFWInfo(); @@ -760,7 +786,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro patch[] = u"C"; //Use SecureInfo_C - if(patchMemory(code + textSize, roSize, + if(patchMemory(code + ((textSize + 4095) & 0xFFFFF000), roSize, pattern, sizeof(pattern) - 2, 22, patch, @@ -858,7 +884,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro if(!loadTitleCodeSection(progId, code, size) || !applyCodeIpsPatch(progId, code, size) || !loadTitleLocaleConfig(progId, ®ionId, &languageId) || - !patchLayeredFs(progId, code, size, textSize)) goto error; + !patchLayeredFs(progId, code, size, textSize, roSize, dataSize, roAddress, dataAddress)) goto error; if(regionId != 0xFF) { diff --git a/injector/source/patcher.h b/injector/source/patcher.h index da3da6b..a57ab06 100644 --- a/injector/source/patcher.h +++ b/injector/source/patcher.h @@ -44,4 +44,4 @@ enum flags ISSAFEMODE }; -void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize); +void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress);