From 5b6bd048a91a2fdce06439f9124e685711866d8e Mon Sep 17 00:00:00 2001 From: Aurora Wright Date: Thu, 13 Apr 2017 01:03:37 +0200 Subject: [PATCH] LayeredFS --- injector/patches/romfsredir.s | 161 +++++++++++++++------------ injector/source/fsldr.c | 72 +++++++++++++ injector/source/fsldr.h | 4 + injector/source/patcher.c | 198 +++++++++++++++++++++++----------- 4 files changed, 304 insertions(+), 131 deletions(-) diff --git a/injector/patches/romfsredir.s b/injector/patches/romfsredir.s index b657313..0362911 100644 --- a/injector/patches/romfsredir.s +++ b/injector/patches/romfsredir.s @@ -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 -.close \ No newline at end of file + sdmcArchiveName : .dcb "sdmc:", 0 + .align 4 + fsMountArchive : .word 0xdead0005 + fsRegisterArchive : .word 0xdead0006 + sdmcCustomPath : .word 0xdead0004 + +.close + diff --git a/injector/source/fsldr.c b/injector/source/fsldr.c index fbc97be..78ea736 100644 --- a/injector/source/fsldr.c +++ b/injector/source/fsldr.c @@ -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; +} \ No newline at end of file diff --git a/injector/source/fsldr.h b/injector/source/fsldr.h index e4546ea..08268ce 100644 --- a/injector/source/fsldr.h +++ b/injector/source/fsldr.h @@ -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); \ No newline at end of file diff --git a/injector/source/patcher.c b/injector/source/patcher.c index 7d5d288..9243c25 100644 --- a/injector/source/patcher.c +++ b/injector/source/patcher.c @@ -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)