Rewrite the LayeredFS code to check the mount name properly and use ro/data padding for the custom path

This commit is contained in:
Aurora Wright 2017-05-05 20:16:44 +02:00
parent b1c07c6204
commit e231275cbe
4 changed files with 98 additions and 59 deletions

View File

@ -52,16 +52,16 @@ _start:
; it from its original archive like nothing happened ; it from its original archive like nothing happened
fsRedir: fsRedir:
stmfd sp!, {r0-r12, lr} stmfd sp!, {r0-r12, lr}
ldrb r12, [r1] addr r3, romFsMount
cmp r12, #0x72 ; 'r', should include "rom:", "rom2:" and "rex:" bl compare
ldrne r11, [pc, #updateRomFsStart-.-8] addne r3, pc, #updateRomFsMount-.-8
cmpne r12, r11 blne compare
bne endRedir bne endRedir
sub sp, sp, #0x400 sub sp, sp, #0x400
pathRedir: pathRedir:
stmfd sp!, {r0-r3} stmfd sp!, {r0-r3}
add r0, sp, #0x10 add r0, sp, #0x10
addr r3, customPath load r3, customPath
pathRedir_1: pathRedir_1:
ldrb r2, [r3], #1 ldrb r2, [r3], #1
strh r2, [r0], #2 strh r2, [r0], #2
@ -89,13 +89,26 @@ _start:
bxeq lr bxeq lr
b _fsRedir + 4 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 .pool
.align 4 .align 4
archiveName : .dcb "lf:", 0 archiveName : .dcb "lf:", 0
fsMountArchive : .word 0xdead0005 fsMountArchive : .word 0xdead0005
fsRegisterArchive : .word 0xdead0006 fsRegisterArchive : .word 0xdead0006
archiveId : .word 0xdead0007 archiveId : .word 0xdead0007
updateRomFsStart : .word 0xdead0008 romFsMount : .dcb "rom:"
updateRomFsMount : .word 0xdead0008
customPath : .word 0xdead0004 customPath : .word 0xdead0004
.close .close

View File

@ -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); u16 progver = g_exheader.codesetinfo.flags.remasterversion[0] | (g_exheader.codesetinfo.flags.remasterversion[1] << 8);
// patch // 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; return 0;
} }

View File

@ -328,48 +328,72 @@ static inline bool findLayeredFsSymbols(u8 *code, u32 size, u32 *fsMountArchive,
return found == 4; 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 //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; for(u32 addr = 4; svcConnectToPort == 0xFFFFFFFF && addr <= size - 4; addr += 4)
}
//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)
{ {
if(*(u32 *)(code + i) != MAKE_BRANCH_LINK(i, svcConnectToPort)) continue; if(*(u32 *)(code + addr) == 0xEF00002D)
svcConnectToPort = addr - 4;
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) 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) static inline bool applyCodeIpsPatch(u64 progId, u8 *code, u32 size)
@ -514,7 +538,7 @@ exit:
return ret; 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" /* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/romfs"
If it exists it should be a folder containing ROMFS files */ 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, fsRegisterArchive = 0xFFFFFFFF,
fsTryOpenFile = 0xFFFFFFFF, fsTryOpenFile = 0xFFFFFFFF,
fsOpenFileDirectly = 0xFFFFFFFF, fsOpenFileDirectly = 0xFFFFFFFF,
payloadOffset; payloadOffset = 0,
pathOffset = 0,
pathAddress;
if(!findLayeredFsSymbols(code, textSize, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly) || 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:", static const char *updateRomFsMounts[] = { "rom2:",
"ext:" }; "rex:"
char updateRomFsStart = 'r'; "patch:",
u32 i; "ext:",
"rom:" };
u32 updateRomFsIndex;
//Locate update RomFSes //Locate update RomFSes
for(i = 0; i < sizeof(updateRomFsMounts) / sizeof(char *); i++) for(updateRomFsIndex = 0; updateRomFsIndex < sizeof(updateRomFsMounts) / sizeof(char *) - 1; updateRomFsIndex++)
{ if(memsearch(code, updateRomFsMounts[updateRomFsIndex], size, strnlen(updateRomFsMounts[updateRomFsIndex], 255)) != NULL) break;
if(memsearch(code, updateRomFsMounts[i], size, strnlen(updateRomFsMounts[i], 255)) != NULL) break;
}
if(i != sizeof(updateRomFsMounts) / sizeof(char *)) updateRomFsStart = updateRomFsMounts[i][0];
//Setup the payload //Setup the payload
u8 *payload = code + payloadOffset; 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 //Insert symbols in the payload
u32 *payload32 = (u32 *)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]) 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); payload32[i] = MAKE_BRANCH(payloadOffset + i * 4, fsTryOpenFile + 4);
break; break;
case 0xdead0004: case 0xdead0004:
memcpy(payload32 + i, "lf:", 3); payload32[i] = pathAddress;
memcpy((u8 *)(payload32 + i) + 3, path, sizeof(path));
break; break;
case 0xdead0005: case 0xdead0005:
payload32[i] = 0x100000 + fsMountArchive; payload32[i] = 0x100000 + fsMountArchive;
@ -584,11 +607,14 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize)
payload32[i] = archiveId; payload32[i] = archiveId;
break; break;
case 0xdead0008: case 0xdead0008:
payload32[i] = (u32)updateRomFsStart; memcpy(payload32 + i, updateRomFsMounts[updateRomFsIndex], 4);
break; break;
} }
} }
memcpy(code + pathOffset, "lf:", 3);
memcpy(code + pathOffset + 3, path, sizeof(path));
//Place the hooks //Place the hooks
*(u32 *)(code + fsOpenFileDirectly) = MAKE_BRANCH(fsOpenFileDirectly, payloadOffset); *(u32 *)(code + fsOpenFileDirectly) = MAKE_BRANCH(fsOpenFileDirectly, payloadOffset);
*(u32 *)(code + fsTryOpenFile) = MAKE_BRANCH(fsTryOpenFile, payloadOffset + 12); *(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; 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(); loadCFWInfo();
@ -760,7 +786,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
patch[] = u"C"; patch[] = u"C";
//Use SecureInfo_C //Use SecureInfo_C
if(patchMemory(code + textSize, roSize, if(patchMemory(code + ((textSize + 4095) & 0xFFFFF000), roSize,
pattern, pattern,
sizeof(pattern) - 2, 22, sizeof(pattern) - 2, 22,
patch, patch,
@ -858,7 +884,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
if(!loadTitleCodeSection(progId, code, size) || if(!loadTitleCodeSection(progId, code, size) ||
!applyCodeIpsPatch(progId, code, size) || !applyCodeIpsPatch(progId, code, size) ||
!loadTitleLocaleConfig(progId, &regionId, &languageId) || !loadTitleLocaleConfig(progId, &regionId, &languageId) ||
!patchLayeredFs(progId, code, size, textSize)) goto error; !patchLayeredFs(progId, code, size, textSize, roSize, dataSize, roAddress, dataAddress)) goto error;
if(regionId != 0xFF) if(regionId != 0xFF)
{ {

View File

@ -44,4 +44,4 @@ enum flags
ISSAFEMODE 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);