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

View File

@ -107,3 +107,75 @@ Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archi
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_SetPriority(u32 priority);
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 "memory.h"
#include "strings.h"
#include "fsldr.h"
#include "ifile.h"
#include "CFWInfo.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);
}
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)
{
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;
}
static bool checkLumaDir(const char *path)
{
return dirCheck(ARCHIVE_SDMC, path);
}
static inline void loadCFWInfo(void)
{
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)
{
@ -260,36 +285,82 @@ static u32 findNearestStmfd(u8* code, u32 pos)
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)
if(func > size - 8) return 0xFFFFFFFF;
return findNearestStmfd(code, func);
}
static inline u32 findThrowFatalError(u8* code, u32 size)
{
u32 connectToPort;
for(connectToPort = 0; *(u32 *)(code + connectToPort + 4) != 0xEF00002D; connectToPort += 4)
if(connectToPort > size - 12) return 0xFFFFFFFF;
u32 func = 0xFFFFFFFF;
for(u32 i = 4; func == 0xFFFFFFFF && i <= size - 4; i += 4)
for(u32 addr = 0; addr <= size - 4; addr += 4)
{
if(*(u32 *)(code + i) != MAKE_BRANCH_LINK(i, connectToPort)) continue;
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);
}
}
func = findNearestStmfd(code, i);
if(*fsRegisterArchive == 0xFFFFFFFF && addr <= size - 8)
{
if(*(u32 *)(code + addr) == 0xC82044B4)
{
if(*(u32 *)(code + addr + 4) == 0xD8604659)
*fsRegisterArchive = findStart(code, addr);
}
}
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(*fsTryOpenFile == 0xFFFFFFFF && addr <= size - 12)
{
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);
}
}
}
if(*fsOpenFileDirectly == 0xFFFFFFFF)
{
if(*(u32 *)(code + addr) == 0x08030204)
{
*fsOpenFileDirectly = findStart(code, addr);
}
}
if(svcConnectToPort == 0xFFFFFFFF && addr >= 4)
{
if(*(u32 *)(code + addr) == 0xEF00002D)
svcConnectToPort = addr - 4;
}
}
return func;
if(svcConnectToPort != 0xFFFFFFFF && *fsMountArchive != 0xFFFFFFFF && *fsRegisterArchive != 0xFFFFFFFF && *fsTryOpenFile != 0xFFFFFFFF && *fsOpenFileDirectly != 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;
func = findStart(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;
}
*throwFatalError = func;
if(func != 0xFFFFFFFF) return true;
}
return false;
}
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";
progIdToStr(path + 28, progId);
IFile file;
u32 archive = openLumaFile(&file, path);
if(!checkLumaDir(path)) return true;
if(!archive) return true;
u32 fsMountArchive = 0xFFFFFFFF,
fsRegisterArchive = 0xFFFFFFFF,
fsTryOpenFile = 0xFFFFFFFF,
fsOpenFileDirectly = 0xFFFFFFFF,
throwFatalError;
bool ret = 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;
if(!findSymbols(code, size, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly, &throwFatalError)) return false;
//Setup the payload
u8 *payload = code + throwFatalError;
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);
payloadSymbols[0] = 0x100000 + fsOpenFileDirectly + 4;
*(u64 *)(payloadSymbols + 2) = 0x1000ULL;
*(u64 *)(payloadSymbols + 4) = romfsSize - 0x1000ULL;
payloadSymbols[6] = archive;
payloadSymbols[7] = sizeof(path);
payloadSymbols[8] = 0x100000 + throwFatalError + romfsredir_bin_size; //String pointer
//Insert symbols in the payload
u32 *payload32 = (u32 *)payload;
for(u32 i = 0; i < romfsredir_bin_size / 4; i++)
{
switch (payload32[i])
{
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
*(u32 *)(code + fsOpenFileDirectly) = MAKE_BRANCH(fsOpenFileDirectly, throwFatalError);
*(u32 *)(code + fsTryOpenFile) = MAKE_BRANCH(fsTryOpenFile, throwFatalError + 12);
u32 fsOpenLinkFile = findFunctionCommand(code, size, 0x80C0000);
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;
return true;
}
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)