|
|
|
|
@@ -13,7 +13,7 @@ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, in
|
|
|
|
|
{
|
|
|
|
|
u32 i;
|
|
|
|
|
|
|
|
|
|
for(i = 0; !count || i < count; i++)
|
|
|
|
|
for(i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
u8 *found = memsearch(start, pattern, size, patSize);
|
|
|
|
|
|
|
|
|
|
@@ -292,19 +292,21 @@ static inline bool findLayeredFsSymbols(u8 *code, u32 size, u32 *fsMountArchive,
|
|
|
|
|
|
|
|
|
|
for(u32 addr = 0; addr <= size - 4; addr += 4)
|
|
|
|
|
{
|
|
|
|
|
switch(*(u32 *)(code + addr))
|
|
|
|
|
u32 *addr32 = (u32 *)(code + addr);
|
|
|
|
|
|
|
|
|
|
switch(*addr32)
|
|
|
|
|
{
|
|
|
|
|
case 0xE5970010:
|
|
|
|
|
if(addr <= size - 12 && *fsMountArchive == 0xFFFFFFFF && *(u32 *)(code + addr + 4) == 0xE1CD20D8 && (*(u32 *)(code + addr + 8) & 0xFFFFFF) == 0x008D0000) temp = fsMountArchive;
|
|
|
|
|
if(addr <= size - 12 && *fsMountArchive == 0xFFFFFFFF && addr32[1] == 0xE1CD20D8 && (addr32[2] & 0xFFFFFF) == 0x008D0000) temp = fsMountArchive;
|
|
|
|
|
break;
|
|
|
|
|
case 0xE24DD028:
|
|
|
|
|
if(addr <= size - 16 && *fsMountArchive == 0xFFFFFFFF && *(u32 *)(code + addr + 4) == 0xE1A04000 && *(u32 *)(code + addr + 8) == 0xE59F60A8 && *(u32 *)(code + addr + 0xC) == 0xE3A0C001) temp = fsMountArchive;
|
|
|
|
|
if(addr <= size - 16 && *fsMountArchive == 0xFFFFFFFF && addr32[1] == 0xE1A04000 && addr32[2] == 0xE59F60A8 && addr32[3] == 0xE3A0C001) temp = fsMountArchive;
|
|
|
|
|
break;
|
|
|
|
|
case 0xE3500008:
|
|
|
|
|
if(addr <= size - 12 && *fsRegisterArchive == 0xFFFFFFFF && (*(u32 *)(code + addr + 4) & 0xFFF00FF0) == 0xE1800400 && (*(u32 *)(code + addr + 8) & 0xFFF00FF0) == 0xE1800FC0) temp = fsRegisterArchive;
|
|
|
|
|
if(addr <= size - 12 && *fsRegisterArchive == 0xFFFFFFFF && (addr32[1] & 0xFFF00FF0) == 0xE1800400 && (addr32[2] & 0xFFF00FF0) == 0xE1800FC0) temp = fsRegisterArchive;
|
|
|
|
|
break;
|
|
|
|
|
case 0xE351003A:
|
|
|
|
|
if(addr <= size - 0x40 && *fsTryOpenFile == 0xFFFFFFFF && *(u32 *)(code + addr + 4) == 0x1AFFFFFC && *(u32 *)(code + addr + 0x34) == 0xE590C000 && *(u32 *)(code + addr + 0x3C) == 0xE12FFF3C) temp = fsTryOpenFile;
|
|
|
|
|
if(addr <= size - 0x40 && *fsTryOpenFile == 0xFFFFFFFF && addr32[1] == 0x1AFFFFFC && addr32[0xD] == 0xE590C000 && addr32[0xF] == 0xE12FFF3C) temp = fsTryOpenFile;
|
|
|
|
|
break;
|
|
|
|
|
case 0x08030204:
|
|
|
|
|
if(*fsOpenFileDirectly == 0xFFFFFFFF) temp = fsOpenFileDirectly;
|
|
|
|
|
@@ -328,48 +330,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 +540,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,25 +556,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:" },
|
|
|
|
|
patch = 'r';
|
|
|
|
|
static const char *updateRomFsMounts[] = { "rom2:",
|
|
|
|
|
"rex:",
|
|
|
|
|
"patch:",
|
|
|
|
|
"ext:",
|
|
|
|
|
"rom:" };
|
|
|
|
|
u32 updateRomFsIndex;
|
|
|
|
|
|
|
|
|
|
//Change update RomFS mountpoints to start with "r"
|
|
|
|
|
for(u32 i = 0, ret = 0; i < sizeof(updateRomFsMounts) / sizeof(char *) && !ret; i++)
|
|
|
|
|
{
|
|
|
|
|
ret = patchMemory(code, size,
|
|
|
|
|
updateRomFsMounts[i],
|
|
|
|
|
strnlen(updateRomFsMounts[i], 255), 0,
|
|
|
|
|
&patch,
|
|
|
|
|
sizeof(patch), 0
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
//Locate update RomFSes
|
|
|
|
|
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;
|
|
|
|
|
@@ -573,8 +597,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;
|
|
|
|
|
@@ -585,9 +608,15 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize)
|
|
|
|
|
case 0xdead0007:
|
|
|
|
|
payload32[i] = archiveId;
|
|
|
|
|
break;
|
|
|
|
|
case 0xdead0008:
|
|
|
|
|
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);
|
|
|
|
|
@@ -595,7 +624,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();
|
|
|
|
|
|
|
|
|
|
@@ -759,7 +788,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,
|
|
|
|
|
@@ -849,25 +878,29 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
|
|
|
|
|
)) goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(CONFIG(PATCHGAMES) && (u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000)
|
|
|
|
|
if(CONFIG(PATCHGAMES))
|
|
|
|
|
{
|
|
|
|
|
u8 regionId = 0xFF,
|
|
|
|
|
languageId;
|
|
|
|
|
|
|
|
|
|
if(!loadTitleCodeSection(progId, code, size) ||
|
|
|
|
|
!applyCodeIpsPatch(progId, code, size) ||
|
|
|
|
|
!loadTitleLocaleConfig(progId, ®ionId, &languageId) ||
|
|
|
|
|
!patchLayeredFs(progId, code, size, textSize)) goto error;
|
|
|
|
|
!applyCodeIpsPatch(progId, code, size)) goto error;
|
|
|
|
|
|
|
|
|
|
if(regionId != 0xFF)
|
|
|
|
|
if((u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000)
|
|
|
|
|
{
|
|
|
|
|
u32 CFGUHandleOffset;
|
|
|
|
|
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, textSize, &CFGUHandleOffset);
|
|
|
|
|
u8 regionId = 0xFF,
|
|
|
|
|
languageId;
|
|
|
|
|
|
|
|
|
|
if(CFGU_GetConfigInfoBlk2_endPos == NULL ||
|
|
|
|
|
!patchCfgGetLanguage(code, textSize, languageId, CFGU_GetConfigInfoBlk2_endPos)) goto error;
|
|
|
|
|
if(!loadTitleLocaleConfig(progId, ®ionId, &languageId) ||
|
|
|
|
|
!patchLayeredFs(progId, code, size, textSize, roSize, dataSize, roAddress, dataAddress)) goto error;
|
|
|
|
|
|
|
|
|
|
patchCfgGetRegion(code, textSize, regionId, CFGUHandleOffset);
|
|
|
|
|
if(regionId != 0xFF)
|
|
|
|
|
{
|
|
|
|
|
u32 CFGUHandleOffset;
|
|
|
|
|
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, textSize, &CFGUHandleOffset);
|
|
|
|
|
|
|
|
|
|
if(CFGU_GetConfigInfoBlk2_endPos == NULL ||
|
|
|
|
|
!patchCfgGetLanguage(code, textSize, languageId, CFGU_GetConfigInfoBlk2_endPos)) goto error;
|
|
|
|
|
|
|
|
|
|
patchCfgGetRegion(code, textSize, regionId, CFGUHandleOffset);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|