From a0c2b43b34ae4fe1146bd42f4fcb7cf82b3b35e8 Mon Sep 17 00:00:00 2001 From: Aurora Wright Date: Tue, 1 Aug 2017 17:27:14 +0200 Subject: [PATCH] Implement loading of exheaders from SD/CTRNAND (must be called luma/titles/TITLEID/exheader.bin), thanks to @HiddenRambler! --- sysmodules/loader/source/loader.c | 132 +++++++++++++++++++---------- sysmodules/loader/source/patcher.c | 88 ++++++++++--------- sysmodules/loader/source/patcher.h | 8 ++ 3 files changed, 140 insertions(+), 88 deletions(-) diff --git a/sysmodules/loader/source/loader.c b/sysmodules/loader/source/loader.c index 3a8e569..8768130 100644 --- a/sysmodules/loader/source/loader.c +++ b/sysmodules/loader/source/loader.c @@ -11,6 +11,9 @@ #define MAX_SESSIONS 1 #define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100) +u32 config, multiConfig, bootConfig; +bool isN3DS, isSafeMode, isSdMode; + const char CODE_PATH[] = {0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00}; typedef struct @@ -30,6 +33,28 @@ static u64 g_cached_prog_handle; static exheader_header g_exheader; static char g_ret_buf[1024]; +static inline void loadCFWInfo(void) +{ + s64 out; + + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 3))) svcBreak(USERBREAK_ASSERT); + config = (u32)out; + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 4))) svcBreak(USERBREAK_ASSERT); + multiConfig = (u32)out; + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 5))) svcBreak(USERBREAK_ASSERT); + bootConfig = (u32)out; + + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x201))) svcBreak(USERBREAK_ASSERT); + isN3DS = (bool)out; + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x202))) svcBreak(USERBREAK_ASSERT); + isSafeMode = (bool)out; + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT); + isSdMode = (bool)out; + + IFile file; + if(isSafeMode) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted +} + static int lzss_decompress(u8 *end) { unsigned int v1; // r1@2 @@ -116,44 +141,47 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i u64 size; u64 total; - archivePath.type = PATH_BINARY; - archivePath.data = &prog_handle; - archivePath.size = 8; - - filePath.type = PATH_BINARY; - filePath.data = CODE_PATH; - filePath.size = sizeof(CODE_PATH); - if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, filePath, FS_OPEN_READ))) + if(!CONFIG(PATCHGAMES) || !loadTitleCodeSection(progid, (u8 *)shared->text_addr, (u64)shared->total_size << 12)) { - svcBreak(USERBREAK_ASSERT); - } + archivePath.type = PATH_BINARY; + archivePath.data = &prog_handle; + archivePath.size = 8; - // get file size - if (R_FAILED(IFile_GetSize(&file, &size))) - { - IFile_Close(&file); - svcBreak(USERBREAK_ASSERT); - } + filePath.type = PATH_BINARY; + filePath.data = CODE_PATH; + filePath.size = sizeof(CODE_PATH); + if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, filePath, FS_OPEN_READ))) + { + svcBreak(USERBREAK_ASSERT); + } - // check size - if (size > (u64)shared->total_size << 12) - { - IFile_Close(&file); - return 0xC900464F; - } + // get file size + if (R_FAILED(IFile_GetSize(&file, &size))) + { + IFile_Close(&file); + svcBreak(USERBREAK_ASSERT); + } - // read code - res = IFile_Read(&file, &total, (void *)shared->text_addr, size); - IFile_Close(&file); // done reading - if (R_FAILED(res)) - { - svcBreak(USERBREAK_ASSERT); - } + // check size + if (size > (u64)shared->total_size << 12) + { + IFile_Close(&file); + return 0xC900464F; + } - // decompress - if (is_compressed) - { - lzss_decompress((u8 *)shared->text_addr + size); + // read code + res = IFile_Read(&file, &total, (void *)shared->text_addr, size); + IFile_Close(&file); // done reading + if (R_FAILED(res)) + { + svcBreak(USERBREAK_ASSERT); + } + + // decompress + if (is_compressed) + { + lzss_decompress((u8 *)shared->text_addr + size); + } } u16 progver = g_exheader.codesetinfo.flags.remasterversion[0] | (g_exheader.codesetinfo.flags.remasterversion[1] << 8); @@ -212,21 +240,31 @@ static Result loader_GetProgramInfo(exheader_header *exheader, u64 prog_handle) exheader->accessdesc.arm11systemlocalcaps.storageinfo.accessinfo[0] |= 0x480; // Tweak 3dsx placeholder title exheader - if (nbSection0Modules == 6 && exheader->arm11systemlocalcaps.programid == HBLDR_3DSX_TID) + if (nbSection0Modules == 6) { - Handle hbldr = 0; - res = HBLDR_Init(&hbldr); - if (R_SUCCEEDED(res)) + if(exheader->arm11systemlocalcaps.programid == HBLDR_3DSX_TID) { - u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(4,0,2); - cmdbuf[1] = IPC_Desc_Buffer(sizeof(*exheader), IPC_BUFFER_RW); - cmdbuf[2] = (u32)exheader; - res = svcSendSyncRequest(hbldr); - svcCloseHandle(hbldr); - if (R_SUCCEEDED(res)) { - res = cmdbuf[1]; - } + Handle hbldr = 0; + res = HBLDR_Init(&hbldr); + if (R_SUCCEEDED(res)) + { + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(4,0,2); + cmdbuf[1] = IPC_Desc_Buffer(sizeof(*exheader), IPC_BUFFER_RW); + cmdbuf[2] = (u32)exheader; + res = svcSendSyncRequest(hbldr); + svcCloseHandle(hbldr); + if (R_SUCCEEDED(res)) { + res = cmdbuf[1]; + } + } + } + + u64 originalProgId = exheader->arm11systemlocalcaps.programid; + if(CONFIG(PATCHGAMES) && loadTitleExheader(exheader->arm11systemlocalcaps.programid, exheader)) + { + exheader->arm11systemlocalcaps.programid = originalProgId; + exheader->accessdesc.arm11systemlocalcaps.programid = originalProgId; } } } @@ -586,6 +624,8 @@ int main() svcBreak(USERBREAK_ASSERT); } + loadCFWInfo(); + g_active_handles = 2; g_cached_prog_handle = 0; index = 1; diff --git a/sysmodules/loader/source/patcher.c b/sysmodules/loader/source/patcher.c index 8ae2db3..f73a015 100644 --- a/sysmodules/loader/source/patcher.c +++ b/sysmodules/loader/source/patcher.c @@ -3,12 +3,8 @@ #include "memory.h" #include "strings.h" #include "fsldr.h" -#include "ifile.h" #include "../build/bundled.h" -static u32 config, multiConfig, bootConfig; -static bool isN3DS, isSafeMode, isSdMode; - static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s32 offset, const void *replace, u32 repSize, u32 count) { u32 i; @@ -32,7 +28,7 @@ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s3 return i; } -static Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags) +Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags) { FS_Path filePath = {PATH_ASCII, strnlen(path, 255) + 1, path}, archivePath = {PATH_EMPTY, 1, (u8 *)""}; @@ -73,32 +69,6 @@ static u32 checkLumaDir(const char *path) return dirCheck(archiveId, path) ? archiveId : 0; } -static inline void loadCFWInfo(void) -{ - static bool infoLoaded = false; - s64 out; - - if(infoLoaded) return; - - if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 3))) svcBreak(USERBREAK_ASSERT); - config = (u32)out; - if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 4))) svcBreak(USERBREAK_ASSERT); - multiConfig = (u32)out; - if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 5))) svcBreak(USERBREAK_ASSERT); - bootConfig = (u32)out; - - if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x201))) svcBreak(USERBREAK_ASSERT); - isN3DS = (bool)out; - if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x202))) svcBreak(USERBREAK_ASSERT); - isSafeMode = (bool)out; - if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT); - isSdMode = (bool)out; - - IFile file; - if(isSafeMode) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted - infoLoaded = true; -} - static inline bool secureInfoExists(void) { static bool exists = false; @@ -353,7 +323,7 @@ exit: return ret; } -static inline bool loadTitleCodeSection(u64 progId, u8 *code, u32 size) +bool loadTitleCodeSection(u64 progId, u8 *code, u32 size) { /* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/code.bin" If it exists it should be a decrypted and decompressed binary code file */ @@ -363,22 +333,60 @@ static inline bool loadTitleCodeSection(u64 progId, u8 *code, u32 size) IFile file; - if(!openLumaFile(&file, path)) return true; + if(!openLumaFile(&file, path)) return false; - bool ret; u64 fileSize; - if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = false; + if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) goto error; else { u64 total; - ret = R_SUCCEEDED(IFile_Read(&file, &total, code, fileSize)) && total == fileSize; + if(R_FAILED(IFile_Read(&file, &total, code, fileSize)) || total != fileSize) goto error; } IFile_Close(&file); - return ret; + return true; + +error: + IFile_Close(&file); + + svcBreak(USERBREAK_ASSERT); + while(true); +} + +bool loadTitleExheader(u64 progId, exheader_header *exheader) +{ + /* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/exheader.bin" + If it exists it should be a decrypted exheader */ + + char path[] = "/luma/titles/0000000000000000/exheader.bin"; + progIdToStr(path + 28, progId); + + IFile file; + + if(!openLumaFile(&file, path)) return false; + + u64 fileSize; + + if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize != sizeof(exheader_header)) goto error; + else + { + u64 total; + + if(R_FAILED(IFile_Read(&file, &total, exheader, fileSize)) || total != fileSize) goto error; + } + + IFile_Close(&file); + + return true; + +error: + IFile_Close(&file); + + svcBreak(USERBREAK_ASSERT); + while(true); } static inline bool loadTitleLocaleConfig(u64 progId, u8 *mask, u8 *regionId, u8 *languageId, u8 *countryId, u8 *stateId) @@ -570,8 +578,6 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize, void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress) { - loadCFWInfo(); - if(progId == 0x0004003000008F02LL || //USA Home Menu progId == 0x0004003000008202LL || //JPN Home Menu progId == 0x0004003000009802LL || //EUR Home Menu @@ -873,8 +879,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro if(CONFIG(PATCHGAMES)) { - if(!loadTitleCodeSection(progId, code, size) || - !applyCodeIpsPatch(progId, code, size)) goto error; + if(!applyCodeIpsPatch(progId, code, size)) goto error; if((u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000) { @@ -894,5 +899,4 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro error: svcBreak(USERBREAK_ASSERT); - while(true); } diff --git a/sysmodules/loader/source/patcher.h b/sysmodules/loader/source/patcher.h index 1e2bf5b..f2e8a4b 100644 --- a/sysmodules/loader/source/patcher.h +++ b/sysmodules/loader/source/patcher.h @@ -1,6 +1,8 @@ #pragma once #include <3ds/types.h> +#include "exheader.h" +#include "ifile.h" #define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF)) #define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF)) @@ -35,4 +37,10 @@ enum singleOptions DISABLEARM11EXCHANDLERS }; +extern u32 config, multiConfig, bootConfig; +extern bool isN3DS, isSafeMode, isSdMode; + void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress); +Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags); +bool loadTitleCodeSection(u64 progId, u8 *code, u32 size); +bool loadTitleExheader(u64 progId, exheader_header *exheader);