Use .text segment padding for LayeredFS payload

This commit is contained in:
Seth VanHeulen 2017-04-16 17:59:20 -04:00
parent 07bbff7d11
commit 7ea80353f6
3 changed files with 43 additions and 28 deletions

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); patchCode(progid, progver, (u8 *)shared->text_addr, shared->total_size << 12, g_exheader.codesetinfo.text.codesize);
return 0; return 0;
} }

View File

@ -289,12 +289,9 @@ static u32 findFunctionStart(u8* code, u32 pos)
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }
static bool findLayeredFsSymbols(u8* code, u32 size, u32 *fsMountArchive, u32 *fsRegisterArchive, u32 *fsTryOpenFile, u32 *fsOpenFileDirectly, u32 *throwFatalError) static bool findLayeredFsSymbols(u8* code, u32 size, u32 *fsMountArchive, u32 *fsRegisterArchive, u32 *fsTryOpenFile, u32 *fsOpenFileDirectly)
{ {
bool found = false; for(u32 addr = 0; addr <= size - 4; addr += 4)
u32 svcConnectToPort = 0xFFFFFFFF;
for(u32 addr = 0; !found && addr <= size - 4; addr += 4)
{ {
if(*fsMountArchive == 0xFFFFFFFF) if(*fsMountArchive == 0xFFFFFFFF)
{ {
@ -321,29 +318,46 @@ static bool findLayeredFsSymbols(u8* code, u32 size, u32 *fsMountArchive, u32 *f
if(*fsOpenFileDirectly == 0xFFFFFFFF && *(u32 *)(code + addr) == 0x08030204) if(*fsOpenFileDirectly == 0xFFFFFFFF && *(u32 *)(code + addr) == 0x08030204)
*fsOpenFileDirectly = findFunctionStart(code, addr); *fsOpenFileDirectly = findFunctionStart(code, addr);
if(addr >= 4 && svcConnectToPort == 0xFFFFFFFF && *(u32 *)(code + addr) == 0xEF00002D) if(*fsMountArchive != 0xFFFFFFFF && *fsRegisterArchive != 0xFFFFFFFF && *fsTryOpenFile != 0xFFFFFFFF && *fsOpenFileDirectly != 0xFFFFFFFF) return true;
svcConnectToPort = addr - 4;
if(svcConnectToPort != 0xFFFFFFFF && *fsMountArchive != 0xFFFFFFFF && *fsRegisterArchive != 0xFFFFFFFF && *fsTryOpenFile != 0xFFFFFFFF && *fsOpenFileDirectly != 0xFFFFFFFF) found = true;
} }
if(found) return false;
}
static bool findLayeredFsPayloadOffset(u8* code, u32 text_size, u32* payload_offset) {
// First check for sufficient padding at the end of the .text segment
if (((text_size + 4095) & 0xfffff000) - text_size >= romfsredir_bin_size) {
*payload_offset = text_size;
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 <= text_size - 4; addr += 4)
{
if(*(u32 *)(code + addr) == 0xEF00002D)
svcConnectToPort = addr - 4;
}
if(svcConnectToPort != 0xFFFFFFFF)
{ {
u32 func = 0xFFFFFFFF; u32 func = 0xFFFFFFFF;
for(u32 i = 4; func == 0xFFFFFFFF && i <= size - 4; i += 4) for(u32 i = 4; func == 0xFFFFFFFF && i <= text_size - 4; i += 4)
{ {
if(*(u32 *)(code + i) != MAKE_BRANCH_LINK(i, svcConnectToPort)) continue; if(*(u32 *)(code + i) != MAKE_BRANCH_LINK(i, svcConnectToPort)) continue;
func = findFunctionStart(code, i); func = findFunctionStart(code, i);
for(u32 pos = func + 4; func != 0xFFFFFFFF && pos <= size - 4 && *(u16 *)(code + pos + 2) != 0xE92D; pos += 4) for(u32 pos = func + 4; func != 0xFFFFFFFF && pos <= text_size - 4 && *(u16 *)(code + pos + 2) != 0xE92D; pos += 4)
if(*(u32 *)(code + pos) == 0xE200167E) func = 0xFFFFFFFF; if(*(u32 *)(code + pos) == 0xE200167E) func = 0xFFFFFFFF;
} }
*throwFatalError = func; if(func != 0xFFFFFFFF) {
*payload_offset = func;
if(func != 0xFFFFFFFF) return true; return true;
}
} }
return false; return false;
@ -491,7 +505,7 @@ exit:
return ret; return ret;
} }
static inline bool patchLayeredFs(u64 progId, u8* code, u32 size) static inline bool patchLayeredFs(u64 progId, u8* code, u32 size, u32 text_size)
{ {
/* 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 */
@ -508,13 +522,14 @@ static inline bool patchLayeredFs(u64 progId, u8* code, u32 size)
u32 fsMountArchive = 0xFFFFFFFF, u32 fsMountArchive = 0xFFFFFFFF,
fsRegisterArchive = 0xFFFFFFFF, fsRegisterArchive = 0xFFFFFFFF,
fsTryOpenFile = 0xFFFFFFFF, fsTryOpenFile = 0xFFFFFFFF,
fsOpenFileDirectly = 0xFFFFFFFF, fsOpenFileDirectly = 0xFFFFFFFF;
throwFatalError;
if(!findLayeredFsSymbols(code, size, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly, &throwFatalError)) return false; if(!findLayeredFsSymbols(code, size, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly)) return false;
//Setup the payload //Setup the payload
u8 *payload = code + throwFatalError; u32 payload_offset;
if(!findLayeredFsPayloadOffset(code, text_size, &payload_offset)) return false;
u8 *payload = code + payload_offset;
memcpy(payload, romfsredir_bin, romfsredir_bin_size); memcpy(payload, romfsredir_bin, romfsredir_bin_size);
//Insert symbols in the payload //Insert symbols in the payload
@ -527,13 +542,13 @@ static inline bool patchLayeredFs(u64 progId, u8* code, u32 size)
payload32[i] = *(u32 *)(code + fsOpenFileDirectly); payload32[i] = *(u32 *)(code + fsOpenFileDirectly);
break; break;
case 0xdead0001: case 0xdead0001:
payload32[i] = MAKE_BRANCH(throwFatalError + i * 4, fsOpenFileDirectly + 4); payload32[i] = MAKE_BRANCH(payload_offset + i * 4, fsOpenFileDirectly + 4);
break; break;
case 0xdead0002: case 0xdead0002:
payload32[i] = *(u32 *)(code + fsTryOpenFile); payload32[i] = *(u32 *)(code + fsTryOpenFile);
break; break;
case 0xdead0003: case 0xdead0003:
payload32[i] = MAKE_BRANCH(throwFatalError + i * 4, fsTryOpenFile + 4); payload32[i] = MAKE_BRANCH(payload_offset + i * 4, fsTryOpenFile + 4);
break; break;
case 0xdead0004: case 0xdead0004:
memcpy(payload32 + i, mount, 5); memcpy(payload32 + i, mount, 5);
@ -555,13 +570,13 @@ static inline bool patchLayeredFs(u64 progId, u8* code, u32 size)
} }
//Place the hooks //Place the hooks
*(u32 *)(code + fsOpenFileDirectly) = MAKE_BRANCH(fsOpenFileDirectly, throwFatalError); *(u32 *)(code + fsOpenFileDirectly) = MAKE_BRANCH(fsOpenFileDirectly, payload_offset);
*(u32 *)(code + fsTryOpenFile) = MAKE_BRANCH(fsTryOpenFile, throwFatalError + 12); *(u32 *)(code + fsTryOpenFile) = MAKE_BRANCH(fsTryOpenFile, payload_offset + 12);
return true; return true;
} }
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 text_size)
{ {
loadCFWInfo(); loadCFWInfo();
@ -823,7 +838,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
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)) goto error; !patchLayeredFs(progId, code, size, text_size)) 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); void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 text_size);