LayeredFS

This commit is contained in:
Aurora Wright 2017-04-13 01:03:37 +02:00
parent 28e6ad3372
commit 5b6bd048a9
4 changed files with 304 additions and 131 deletions

View File

@ -1,80 +1,107 @@
; Code from delebile
.arm.little .arm.little
.create "build/romfsredir.bin", 0 .create "build/romfsredir.bin", 0
.macro addr, reg, func
add reg, pc, #func-.-8
.endmacro
.macro load, reg, func .macro load, reg, func
ldr reg, [pc, #func-.-8] ldr reg, [pc, #func-.-8]
.endmacro .endmacro
.macro svc, svcnum
.word 0xef000000 + svcnum
.endmacro
; Patch by delebile
.arm .arm
; fsOpenFileDirectly function will be redirected here. _start:
; If the requested archive is not ROMFS, we'll return
; to the original function. ; Jumps here before the fsOpenFileDirectly call
openFileDirectlyHook: _mountSd:
b mountSd
.word 0xdead0000 ; Substituted opcode
.word 0xdead0001 ; Branch to hooked function
; Jumps here before every iFileOpen call
_fsRedir:
b fsRedir
.word 0xdead0002 ; Substituted opcode
.word 0xdead0003 ; Branch to hooked function
; Mounts SDMC and registers the archive as 'sdmc:'
mountSd:
cmp r3, #3 cmp r3, #3
beq openRomfs bne _mountSd+4
load r12, fsOpenFileDirectly stmfd sp!, {r0-r4, lr}
nop ; Will be replaced with the original function opcode sub sp, sp, #4
bx r12 mov r1, #9
mov r0, sp
load r4, fsMountArchive
blx r4
mov r3, #0
mov r2, #0
ldr r1, [sp]
addr r0, sdmcArchiveName
load r4, fsRegisterArchive
blx r4
add sp, sp, #4
ldmfd sp!, {r0-r4, lr}
b _mountSd+4
; We redirect ROMFS file opening by changing the parameters and call ; Check the path passed to iFileOpen.
; the fsOpenFileDirectly function recursively. The parameter format: ; If it is trying to access a RomFS file, we try to
; r0 : fsUserHandle ; open it from the title folder on the sdcard.
; r1 : Output FileHandle ; If the file cannot be opened from the sdcard, we just open
; r2 : Transaction (usually 0) ; it from its original archive like nothing happened
; r3 : Archive ID fsRedir:
; [sp, #0x00] : Archive PathType stmfd sp!, {r0-r12, lr}
; [sp, #0x04] : Archive DataPointer ldrb r12, [r1]
; [sp, #0x08] : Archive PathSize cmp r12, #0x72 ; 'r', should include "rom:" and "rom2:"
; [sp, #0x0C] : File PathType bne endRedir
; [sp, #0x10] : File DataPointer sub sp, sp, #0x400
; [sp, #0x14] : File PathSize pathRedir:
; [sp, #0x18] : File OpenFlags stmfd sp!, {r0-r3}
; [sp, #0x1C] : Attributes (usually 0) add r0, sp, #0x10
openRomfs: addr r3, sdmcCustomPath
sub sp, sp, #0x50 pathRedir_1:
stmfd sp!, {r0, r1, lr} ldrb r2, [r3], #1
add sp, sp, #0x5C strh r2, [r0], #2
str r3, [sp, #0x0C] ; File PathType (ASCII = 3) cmp r2, #0
load r12, romfsFileName bne pathRedir_1
str r12, [sp, #0x10] ; File DataPointer sub r0, r0, #2
load r12, romfsFileNameSize pathRedir_2:
str r12, [sp, #0x14] ; File PathSize ldrh r2, [r1], #2
load r3, archive cmp r2, #0x3A ; ':'
bl openFileDirectlyHook bne pathRedir_2
sub sp, sp, #0x5C pathRedir_3:
ldmfd sp!, {r0, r1, lr} ldrh r2, [r1], #2
add sp, sp, #0x50 strh r2, [r0], #2
mov r0, r1 ; Substitute fsUserHandle with the fileHandle cmp r2, #0
bne pathRedir_3
ldmfd sp!, {r0-r3}
mov r1, sp
bl _fsRedir+4
add sp, sp, #0x400
cmp r0, #0
; Once we have the sd romfs file opened, we'll open a subfile endRedir:
; in order to skip the useless data. ldmfd sp!, {r0-r12, lr}
stmfd sp!, {r1, r3-r11} moveq r0, #0
mrc p15, 0, r4, c13, c0, 3 beq panic
add r4, r4, #0x80 bxeq lr
mov r1, r4 b _fsRedir+4
add r3, pc, #fsOpenSubFileCmd-.-8
ldmia r3!, {r5-r9} panic:
stmia r1!, {r5-r9} swi 0x3C
ldr r0, [r0] b panic
swi 0x32
ldr r0, [r4, #0x0C]
ldmfd sp!, {r1, r3-r11}
str r0, [r1]
mov r0, #0
bx lr
.pool .pool
.align 4 .align 4
; Part of these symbols will be set from outside sdmcArchiveName : .dcb "sdmc:", 0
fsOpenFileDirectly : .word 0 .align 4
fsOpenSubFileCmd : .word 0x08010100 fsMountArchive : .word 0xdead0005
.word 0 ; File Offset fsRegisterArchive : .word 0xdead0006
.word 0 sdmcCustomPath : .word 0xdead0004
.word 0 ; File Size
.word 0
archive : .word 0
romfsFileNameSize : .word 0
romfsFileName : .word 0 ; File DataPointer
.close .close

View File

@ -107,3 +107,75 @@ Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archi
return cmdbuf[1]; return cmdbuf[1];
} }
Result FSLDR_OpenArchive(FS_Archive* archive, FS_ArchiveID id, FS_Path path)
{
if(!archive) return -2;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x80C,3,2); // 0x80C00C2
cmdbuf[1] = id;
cmdbuf[2] = path.type;
cmdbuf[3] = path.size;
cmdbuf[4] = IPC_Desc_StaticBuffer(path.size, 0);
cmdbuf[5] = (u32) path.data;
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
if(archive) *archive = cmdbuf[2] | ((u64) cmdbuf[3] << 32);
return cmdbuf[1];
}
Result FSLDR_CloseArchive(FS_Archive archive)
{
if(!archive) return -2;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x80E,2,0); // 0x80E0080
cmdbuf[1] = (u32) archive;
cmdbuf[2] = (u32) (archive >> 32);
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
return cmdbuf[1];
}
Result FSLDR_OpenDirectory(Handle* out, FS_Archive archive, FS_Path path)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x80B,4,2); // 0x80B0102
cmdbuf[1] = (u32) archive;
cmdbuf[2] = (u32) (archive >> 32);
cmdbuf[3] = path.type;
cmdbuf[4] = path.size;
cmdbuf[5] = IPC_Desc_StaticBuffer(path.size, 0);
cmdbuf[6] = (u32) path.data;
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret;
if(out) *out = cmdbuf[3];
return cmdbuf[1];
}
Result FSDIRLDR_Close(Handle handle)
{
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(0x802,0,0); // 0x8020000
Result ret = 0;
if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
ret = cmdbuf[1];
if(R_SUCCEEDED(ret)) ret = svcCloseHandle(handle);
return ret;
}

View File

@ -7,3 +7,7 @@ void fsldrExit(void);
Result FSLDR_InitializeWithSdkVersion(Handle session, u32 version); Result FSLDR_InitializeWithSdkVersion(Handle session, u32 version);
Result FSLDR_SetPriority(u32 priority); Result FSLDR_SetPriority(u32 priority);
Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes); Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes);
Result FSLDR_OpenArchive(FS_Archive* archive, FS_ArchiveID id, FS_Path path);
Result FSLDR_CloseArchive(FS_Archive archive);
Result FSLDR_OpenDirectory(Handle* out, FS_Archive archive, FS_Path path);
Result FSDIRLDR_Close(Handle handle);

View File

@ -2,6 +2,7 @@
#include "patcher.h" #include "patcher.h"
#include "memory.h" #include "memory.h"
#include "strings.h" #include "strings.h"
#include "fsldr.h"
#include "ifile.h" #include "ifile.h"
#include "CFWInfo.h" #include "CFWInfo.h"
#include "../build/bundled.h" #include "../build/bundled.h"
@ -39,6 +40,25 @@ static Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, in
return IFile_Open(file, archiveId, archivePath, filePath, flags); return IFile_Open(file, archiveId, archivePath, filePath, flags);
} }
static bool dirCheck(FS_ArchiveID archiveId, const char *path)
{
bool ret;
Handle handle;
FS_Archive archive;
FS_Path dirPath = {PATH_ASCII, strnlen(path, 255) + 1, path},
archivePath = {PATH_EMPTY, 1, (u8 *)""};
if(R_FAILED(FSLDR_OpenArchive(&archive, archiveId, archivePath))) ret = false;
else
{
ret = R_SUCCEEDED(FSLDR_OpenDirectory(&handle, archive, dirPath));
if(ret) FSDIRLDR_Close(handle);
FSLDR_CloseArchive(archive);
}
return ret;
}
static u32 openLumaFile(IFile *file, const char *path) static u32 openLumaFile(IFile *file, const char *path)
{ {
Result res = fileOpen(file, ARCHIVE_SDMC, path, FS_OPEN_READ); Result res = fileOpen(file, ARCHIVE_SDMC, path, FS_OPEN_READ);
@ -49,6 +69,11 @@ static u32 openLumaFile(IFile *file, const char *path)
return (u32)res == 0xC88044AB && R_SUCCEEDED(fileOpen(file, ARCHIVE_NAND_RW, path, FS_OPEN_READ)) ? ARCHIVE_NAND_RW : 0; return (u32)res == 0xC88044AB && R_SUCCEEDED(fileOpen(file, ARCHIVE_NAND_RW, path, FS_OPEN_READ)) ? ARCHIVE_NAND_RW : 0;
} }
static bool checkLumaDir(const char *path)
{
return dirCheck(ARCHIVE_SDMC, path);
}
static inline void loadCFWInfo(void) static inline void loadCFWInfo(void)
{ {
static bool infoLoaded = false; static bool infoLoaded = false;
@ -249,7 +274,7 @@ static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHa
} }
} }
static u32 findNearestStmfd(u8* code, u32 pos) static u32 findStart(u8* code, u32 pos)
{ {
while(pos >= 4) while(pos >= 4)
{ {
@ -260,36 +285,82 @@ static u32 findNearestStmfd(u8* code, u32 pos)
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }
static u32 findFunctionCommand(u8* code, u32 size, u32 command) static bool findSymbols(u8* code, u32 size, u32 *fsMountArchive, u32 *fsRegisterArchive, u32 *fsTryOpenFile, u32 *fsOpenFileDirectly, u32 *throwFatalError)
{ {
u32 func; u32 svcConnectToPort = 0xFFFFFFFF;
for(func = 4; *(u32 *)(code + func) != command; func += 4) for(u32 addr = 0; addr <= size - 4; addr += 4)
if(func > size - 8) return 0xFFFFFFFF; {
if(*fsMountArchive == 0xFFFFFFFF)
{
if(addr <= size - 12 && *(u32 *)(code + addr) == 0xE5970010)
{
if((*(u32 *)(code + addr + 4) == 0xE1CD20D8) && ((*(u32 *)(code + addr + 8) & 0xFFFFFF) == 0x008D0000))
*fsMountArchive = findStart(code, addr);
}
else if(addr <= size - 16 && *(u32 *)(code + addr) == 0xE24DD028)
{
if((*(u32 *)(code + addr + 4) == 0xE1A04000) && (*(u32 *)(code + addr + 8) == 0xE59F60A8) && (*(u32 *)(code + addr + 0xC) == 0xE3A0C001))
*fsMountArchive = findStart(code, addr);
}
}
return findNearestStmfd(code, func); if(*fsRegisterArchive == 0xFFFFFFFF && addr <= size - 8)
} {
if(*(u32 *)(code + addr) == 0xC82044B4)
{
if(*(u32 *)(code + addr + 4) == 0xD8604659)
*fsRegisterArchive = findStart(code, addr);
}
}
static inline u32 findThrowFatalError(u8* code, u32 size) if(*fsTryOpenFile == 0xFFFFFFFF && addr <= size - 12)
{ {
u32 connectToPort; if(*(u32 *)(code + addr + 0xC) == 0xE12FFF3C)
{
if(((*(u32 *)(code + addr) == 0xE1A0100D) || (*(u32 *)(code + addr) == 0xE28D1010)) &&
(*(u32 *)(code + addr + 4) == 0xE590C000) && ((*(u32 *)(code + addr + 8) == 0xE1A00004) || (*(u32 *)(code + addr + 8) == 0xE1A00005)))
{
*fsTryOpenFile = findStart(code, addr);
}
}
}
for(connectToPort = 0; *(u32 *)(code + connectToPort + 4) != 0xEF00002D; connectToPort += 4) if(*fsOpenFileDirectly == 0xFFFFFFFF)
if(connectToPort > size - 12) return 0xFFFFFFFF; {
if(*(u32 *)(code + addr) == 0x08030204)
{
*fsOpenFileDirectly = findStart(code, addr);
}
}
if(svcConnectToPort == 0xFFFFFFFF && addr >= 4)
{
if(*(u32 *)(code + addr) == 0xEF00002D)
svcConnectToPort = addr - 4;
}
}
if(svcConnectToPort != 0xFFFFFFFF && *fsMountArchive != 0xFFFFFFFF && *fsRegisterArchive != 0xFFFFFFFF && *fsTryOpenFile != 0xFFFFFFFF && *fsOpenFileDirectly != 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 <= size - 4; i += 4)
{ {
if(*(u32 *)(code + i) != MAKE_BRANCH_LINK(i, connectToPort)) continue; if(*(u32 *)(code + i) != MAKE_BRANCH_LINK(i, svcConnectToPort)) continue;
func = findNearestStmfd(code, i); func = findStart(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 <= size - 4 && *(u16 *)(code + pos + 2) != 0xE92D; pos += 4)
if(*(u32 *)(code + pos) == 0xE200167E) func = 0xFFFFFFFF; if(*(u32 *)(code + pos) == 0xE200167E) func = 0xFFFFFFFF;
} }
return func; *throwFatalError = func;
if(func != 0xFFFFFFFF) return true;
}
return false;
} }
static inline bool applyCodeIpsPatch(u64 progId, u8 *code, u32 size) static inline bool applyCodeIpsPatch(u64 progId, u8 *code, u32 size)
@ -442,57 +513,56 @@ static inline bool patchRomfsRedirection(u64 progId, u8* code, u32 size)
char path[] = "/luma/titles/0000000000000000/romfs"; char path[] = "/luma/titles/0000000000000000/romfs";
progIdToStr(path + 28, progId); progIdToStr(path + 28, progId);
IFile file; if(!checkLumaDir(path)) return true;
u32 archive = openLumaFile(&file, path);
if(!archive) return true; u32 fsMountArchive = 0xFFFFFFFF,
fsRegisterArchive = 0xFFFFFFFF,
fsTryOpenFile = 0xFFFFFFFF,
fsOpenFileDirectly = 0xFFFFFFFF,
throwFatalError;
bool ret = false; if(!findSymbols(code, size, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly, &throwFatalError)) return false;
u64 romfsSize;
if(R_FAILED(IFile_GetSize(&file, &romfsSize))) goto exit;
u64 total;
u32 magic;
if(R_FAILED(IFile_Read(&file, &total, &magic, 4)) || total != 4 || magic != 0x43465649) goto exit;
u32 fsOpenFileDirectly = findFunctionCommand(code, size, 0x08030204),
throwFatalError = findThrowFatalError(code, size);
if(fsOpenFileDirectly == 0xFFFFFFFF || throwFatalError == 0xFFFFFFFF) goto exit;
//Setup the payload //Setup the payload
u8 *payload = code + throwFatalError; u8 *payload = code + throwFatalError;
memcpy(payload, romfsredir_bin, romfsredir_bin_size); memcpy(payload, romfsredir_bin, romfsredir_bin_size);
memcpy(payload + romfsredir_bin_size, path, sizeof(path));
*(u32 *)(payload + 0xC) = *(u32 *)(code + fsOpenFileDirectly);
u32 *payloadSymbols = (u32 *)(payload + romfsredir_bin_size - 0x24); //Insert symbols in the payload
payloadSymbols[0] = 0x100000 + fsOpenFileDirectly + 4; u32 *payload32 = (u32 *)payload;
*(u64 *)(payloadSymbols + 2) = 0x1000ULL; for(u32 i = 0; i < romfsredir_bin_size / 4; i++)
*(u64 *)(payloadSymbols + 4) = romfsSize - 0x1000ULL; {
payloadSymbols[6] = archive; switch (payload32[i])
payloadSymbols[7] = sizeof(path); {
payloadSymbols[8] = 0x100000 + throwFatalError + romfsredir_bin_size; //String pointer case 0xdead0000:
payload32[i] = *(u32 *)(code + fsOpenFileDirectly);
break;
case 0xdead0001:
payload32[i] = MAKE_BRANCH(throwFatalError + i * 4, fsOpenFileDirectly + 4);
break;
case 0xdead0002:
payload32[i] = *(u32 *)(code + fsTryOpenFile);
break;
case 0xdead0003:
payload32[i] = MAKE_BRANCH(throwFatalError + i * 4, fsTryOpenFile + 4);
break;
case 0xdead0004:
memcpy(payload32 + i, "sdmc:", 5);
memcpy((u8 *)(payload32 + i) + 5, path, sizeof(path));
break;
case 0xdead0005:
payload32[i] = 0x100000 + fsMountArchive;
break;
case 0xdead0006:
payload32[i] = 0x100000 + fsRegisterArchive;
break;
}
}
//Place the hooks //Place the hooks
*(u32 *)(code + fsOpenFileDirectly) = MAKE_BRANCH(fsOpenFileDirectly, throwFatalError); *(u32 *)(code + fsOpenFileDirectly) = MAKE_BRANCH(fsOpenFileDirectly, throwFatalError);
*(u32 *)(code + fsTryOpenFile) = MAKE_BRANCH(fsTryOpenFile, throwFatalError + 12);
u32 fsOpenLinkFile = findFunctionCommand(code, size, 0x80C0000); return true;
if(fsOpenLinkFile != 0xFFFFFFFF)
{
*(u32 *)(code + fsOpenLinkFile) = 0xE3A03003; //mov r3, #3
*(u32 *)(code + fsOpenLinkFile + 4) = MAKE_BRANCH(fsOpenLinkFile + 4, throwFatalError);
}
ret = true;
exit:
IFile_Close(&file);
return ret;
} }
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)