Implement loading of exheaders from SD/CTRNAND (must be called luma/titles/TITLEID/exheader.bin), thanks to @HiddenRambler!
This commit is contained in:
parent
3907c46980
commit
a0c2b43b34
@ -11,6 +11,9 @@
|
|||||||
#define MAX_SESSIONS 1
|
#define MAX_SESSIONS 1
|
||||||
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
|
#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};
|
const char CODE_PATH[] = {0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -30,6 +33,28 @@ static u64 g_cached_prog_handle;
|
|||||||
static exheader_header g_exheader;
|
static exheader_header g_exheader;
|
||||||
static char g_ret_buf[1024];
|
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)
|
static int lzss_decompress(u8 *end)
|
||||||
{
|
{
|
||||||
unsigned int v1; // r1@2
|
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 size;
|
||||||
u64 total;
|
u64 total;
|
||||||
|
|
||||||
archivePath.type = PATH_BINARY;
|
if(!CONFIG(PATCHGAMES) || !loadTitleCodeSection(progid, (u8 *)shared->text_addr, (u64)shared->total_size << 12))
|
||||||
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)))
|
|
||||||
{
|
{
|
||||||
svcBreak(USERBREAK_ASSERT);
|
archivePath.type = PATH_BINARY;
|
||||||
}
|
archivePath.data = &prog_handle;
|
||||||
|
archivePath.size = 8;
|
||||||
|
|
||||||
// get file size
|
filePath.type = PATH_BINARY;
|
||||||
if (R_FAILED(IFile_GetSize(&file, &size)))
|
filePath.data = CODE_PATH;
|
||||||
{
|
filePath.size = sizeof(CODE_PATH);
|
||||||
IFile_Close(&file);
|
if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, filePath, FS_OPEN_READ)))
|
||||||
svcBreak(USERBREAK_ASSERT);
|
{
|
||||||
}
|
svcBreak(USERBREAK_ASSERT);
|
||||||
|
}
|
||||||
|
|
||||||
// check size
|
// get file size
|
||||||
if (size > (u64)shared->total_size << 12)
|
if (R_FAILED(IFile_GetSize(&file, &size)))
|
||||||
{
|
{
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
return 0xC900464F;
|
svcBreak(USERBREAK_ASSERT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read code
|
// check size
|
||||||
res = IFile_Read(&file, &total, (void *)shared->text_addr, size);
|
if (size > (u64)shared->total_size << 12)
|
||||||
IFile_Close(&file); // done reading
|
{
|
||||||
if (R_FAILED(res))
|
IFile_Close(&file);
|
||||||
{
|
return 0xC900464F;
|
||||||
svcBreak(USERBREAK_ASSERT);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// decompress
|
// read code
|
||||||
if (is_compressed)
|
res = IFile_Read(&file, &total, (void *)shared->text_addr, size);
|
||||||
{
|
IFile_Close(&file); // done reading
|
||||||
lzss_decompress((u8 *)shared->text_addr + size);
|
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);
|
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;
|
exheader->accessdesc.arm11systemlocalcaps.storageinfo.accessinfo[0] |= 0x480;
|
||||||
|
|
||||||
// Tweak 3dsx placeholder title exheader
|
// Tweak 3dsx placeholder title exheader
|
||||||
if (nbSection0Modules == 6 && exheader->arm11systemlocalcaps.programid == HBLDR_3DSX_TID)
|
if (nbSection0Modules == 6)
|
||||||
{
|
{
|
||||||
Handle hbldr = 0;
|
if(exheader->arm11systemlocalcaps.programid == HBLDR_3DSX_TID)
|
||||||
res = HBLDR_Init(&hbldr);
|
|
||||||
if (R_SUCCEEDED(res))
|
|
||||||
{
|
{
|
||||||
u32* cmdbuf = getThreadCommandBuffer();
|
Handle hbldr = 0;
|
||||||
cmdbuf[0] = IPC_MakeHeader(4,0,2);
|
res = HBLDR_Init(&hbldr);
|
||||||
cmdbuf[1] = IPC_Desc_Buffer(sizeof(*exheader), IPC_BUFFER_RW);
|
if (R_SUCCEEDED(res))
|
||||||
cmdbuf[2] = (u32)exheader;
|
{
|
||||||
res = svcSendSyncRequest(hbldr);
|
u32* cmdbuf = getThreadCommandBuffer();
|
||||||
svcCloseHandle(hbldr);
|
cmdbuf[0] = IPC_MakeHeader(4,0,2);
|
||||||
if (R_SUCCEEDED(res)) {
|
cmdbuf[1] = IPC_Desc_Buffer(sizeof(*exheader), IPC_BUFFER_RW);
|
||||||
res = cmdbuf[1];
|
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);
|
svcBreak(USERBREAK_ASSERT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadCFWInfo();
|
||||||
|
|
||||||
g_active_handles = 2;
|
g_active_handles = 2;
|
||||||
g_cached_prog_handle = 0;
|
g_cached_prog_handle = 0;
|
||||||
index = 1;
|
index = 1;
|
||||||
|
@ -3,12 +3,8 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "strings.h"
|
#include "strings.h"
|
||||||
#include "fsldr.h"
|
#include "fsldr.h"
|
||||||
#include "ifile.h"
|
|
||||||
#include "../build/bundled.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)
|
static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s32 offset, const void *replace, u32 repSize, u32 count)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
@ -32,7 +28,7 @@ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s3
|
|||||||
return i;
|
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},
|
FS_Path filePath = {PATH_ASCII, strnlen(path, 255) + 1, path},
|
||||||
archivePath = {PATH_EMPTY, 1, (u8 *)""};
|
archivePath = {PATH_EMPTY, 1, (u8 *)""};
|
||||||
@ -73,32 +69,6 @@ static u32 checkLumaDir(const char *path)
|
|||||||
return dirCheck(archiveId, path) ? archiveId : 0;
|
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 inline bool secureInfoExists(void)
|
||||||
{
|
{
|
||||||
static bool exists = false;
|
static bool exists = false;
|
||||||
@ -353,7 +323,7 @@ exit:
|
|||||||
return ret;
|
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"
|
/* 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 */
|
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;
|
IFile file;
|
||||||
|
|
||||||
if(!openLumaFile(&file, path)) return true;
|
if(!openLumaFile(&file, path)) return false;
|
||||||
|
|
||||||
bool ret;
|
|
||||||
u64 fileSize;
|
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
|
else
|
||||||
{
|
{
|
||||||
u64 total;
|
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);
|
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)
|
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)
|
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
|
if(progId == 0x0004003000008F02LL || //USA Home Menu
|
||||||
progId == 0x0004003000008202LL || //JPN Home Menu
|
progId == 0x0004003000008202LL || //JPN Home Menu
|
||||||
progId == 0x0004003000009802LL || //EUR 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(CONFIG(PATCHGAMES))
|
||||||
{
|
{
|
||||||
if(!loadTitleCodeSection(progId, code, size) ||
|
if(!applyCodeIpsPatch(progId, code, size)) goto error;
|
||||||
!applyCodeIpsPatch(progId, code, size)) goto error;
|
|
||||||
|
|
||||||
if((u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000)
|
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:
|
error:
|
||||||
svcBreak(USERBREAK_ASSERT);
|
svcBreak(USERBREAK_ASSERT);
|
||||||
while(true);
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <3ds/types.h>
|
#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(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))
|
#define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||||
@ -35,4 +37,10 @@ enum singleOptions
|
|||||||
DISABLEARM11EXCHANDLERS
|
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);
|
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);
|
||||||
|
Reference in New Issue
Block a user