Added RomFS redirection courtesy of @delebile, changed structure for game patches: language emulation txts now go to /luma/titles/<titleid>/locale.txt, code.bins go to /luma/titles/<titleid>/code.bin, RomFSes go to /luma/titles/<titleid>/romfs
This commit is contained in:
parent
1fcab825bf
commit
b5336c81cc
@ -14,6 +14,7 @@ OC := arm-none-eabi-objcopy
|
|||||||
name := $(shell basename $(CURDIR))
|
name := $(shell basename $(CURDIR))
|
||||||
|
|
||||||
dir_source := source
|
dir_source := source
|
||||||
|
dir_patches := patches
|
||||||
dir_build := build
|
dir_build := build
|
||||||
dir_out := ../$(dir_build)
|
dir_out := ../$(dir_build)
|
||||||
|
|
||||||
@ -31,6 +32,14 @@ LDFLAGS := -Xlinker --defsym="__start__=0x14000000" -specs=3dsx.specs $(ASFLAGS)
|
|||||||
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.s *.c))
|
$(call rwildcard, $(dir_source), *.s *.c))
|
||||||
|
|
||||||
|
bundled = $(dir_build)/romfsredir.bin.o
|
||||||
|
|
||||||
|
define bin2o
|
||||||
|
bin2s $< | $(AS) -o $(@)
|
||||||
|
echo "extern const u8" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> $(dir_build)/bundled.h
|
||||||
|
echo "extern const u32" `(echo $(<F) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> $(dir_build)/bundled.h
|
||||||
|
endef
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(dir_out)/$(name).bin
|
all: $(dir_out)/$(name).bin
|
||||||
|
|
||||||
@ -38,12 +47,23 @@ all: $(dir_out)/$(name).bin
|
|||||||
clean:
|
clean:
|
||||||
@rm -rf $(dir_build)
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
|
.PRECIOUS: $(dir_build)/%.bin
|
||||||
|
|
||||||
|
$(dir_build):
|
||||||
|
@mkdir -p "$@"
|
||||||
|
|
||||||
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
|
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
|
||||||
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
|
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
|
||||||
|
|
||||||
$(dir_build)/$(name).elf: $(objects)
|
$(dir_build)/$(name).elf: $(bundled) $(objects)
|
||||||
$(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS)
|
$(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS)
|
||||||
|
|
||||||
|
$(dir_build)/%.bin.o: $(dir_build)/%.bin
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
$(dir_build)/%.bin: $(dir_patches)/%.s $(dir_build)
|
||||||
|
@armips $<
|
||||||
|
|
||||||
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c
|
$(dir_build)/%.o: $(dir_source)/%.c
|
||||||
|
81
injector/patches/romfsredir.s
Normal file
81
injector/patches/romfsredir.s
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
; Code from delebile
|
||||||
|
|
||||||
|
.arm.little
|
||||||
|
.create "build/romfsredir.bin", 0
|
||||||
|
|
||||||
|
.macro load, reg, func
|
||||||
|
ldr reg, [pc, #func-.-8]
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.arm
|
||||||
|
; fsOpenFileDirectly function will be redirected here.
|
||||||
|
; If the requested archive is not ROMFS, we'll return
|
||||||
|
; to the original fucntion.
|
||||||
|
openFileDirectlyHook:
|
||||||
|
cmp r3, #3
|
||||||
|
beq openRomfs
|
||||||
|
load r12, fsOpenFileDirectly
|
||||||
|
add r12, r12, #4
|
||||||
|
nop ; Will be replaced with the original function opcode
|
||||||
|
bx r12
|
||||||
|
|
||||||
|
; 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
|
||||||
|
mov r3, #9 ; SDMC Archive ID
|
||||||
|
bl openFileDirectlyHook
|
||||||
|
sub sp, sp, #0x5C
|
||||||
|
ldmfd sp!, {r0, r1, lr}
|
||||||
|
add sp, sp, #0x50
|
||||||
|
mov r0, r1 ; Substitute fsUserHandle with the fileHandle
|
||||||
|
|
||||||
|
; Once we have the sd romfs file opened, we'll open a subfile
|
||||||
|
; in order to skip the useless data.
|
||||||
|
fsOpenSubFile:
|
||||||
|
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
|
||||||
|
|
||||||
|
.pool
|
||||||
|
.align 4
|
||||||
|
; Part of these symbols will be set from outside
|
||||||
|
fsOpenFileDirectly : .word 0x00000000
|
||||||
|
fsOpenSubFileCmd : .word 0x08010100
|
||||||
|
.word 0x00000000 ; File Offset
|
||||||
|
.word 0x00000000
|
||||||
|
.word 0x00000000 ; File Size
|
||||||
|
.word 0x00000000
|
||||||
|
romfsFileNameSize : .word 0x00000000
|
||||||
|
romfsFileName : .word 0x00000000 ; File DataPointer
|
||||||
|
.close
|
@ -4,6 +4,7 @@
|
|||||||
#include "strings.h"
|
#include "strings.h"
|
||||||
#include "ifile.h"
|
#include "ifile.h"
|
||||||
#include "CFWInfo.h"
|
#include "CFWInfo.h"
|
||||||
|
#include "../build/bundled.h"
|
||||||
|
|
||||||
static CFWInfo info;
|
static CFWInfo info;
|
||||||
|
|
||||||
@ -134,97 +135,6 @@ exit:
|
|||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool loadTitleCodeSection(u64 progId, u8 *code, u32 size)
|
|
||||||
{
|
|
||||||
/* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin"
|
|
||||||
If it exists it should be a decompressed binary code file */
|
|
||||||
|
|
||||||
char path[] = "/luma/code_sections/0000000000000000.bin";
|
|
||||||
progIdToStr(path + 35, progId);
|
|
||||||
|
|
||||||
IFile file;
|
|
||||||
|
|
||||||
if(R_FAILED(openLumaFile(&file, path))) return true;
|
|
||||||
|
|
||||||
bool ret;
|
|
||||||
u64 fileSize;
|
|
||||||
|
|
||||||
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u64 total;
|
|
||||||
|
|
||||||
ret = R_SUCCEEDED(IFile_Read(&file, &total, code, fileSize)) && total == fileSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
IFile_Close(&file);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
|
||||||
{
|
|
||||||
/* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt"
|
|
||||||
If it exists it should contain, for example, "EUR IT" */
|
|
||||||
|
|
||||||
char path[] = "/luma/locales/0000000000000000.txt";
|
|
||||||
progIdToStr(path + 29, progId);
|
|
||||||
|
|
||||||
IFile file;
|
|
||||||
|
|
||||||
if(R_FAILED(openLumaFile(&file, path))) return true;
|
|
||||||
|
|
||||||
bool ret;
|
|
||||||
u64 fileSize;
|
|
||||||
|
|
||||||
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 6 || fileSize > 8)
|
|
||||||
{
|
|
||||||
ret = false;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buf[8];
|
|
||||||
u64 total;
|
|
||||||
|
|
||||||
if(R_FAILED(IFile_Read(&file, &total, buf, fileSize)))
|
|
||||||
{
|
|
||||||
ret = false;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 i,
|
|
||||||
j;
|
|
||||||
|
|
||||||
for(i = 0; i < 7; i++)
|
|
||||||
{
|
|
||||||
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
|
|
||||||
|
|
||||||
if(memcmp(buf, regions[i], 3) == 0)
|
|
||||||
{
|
|
||||||
*regionId = (u8)i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(j = 0; j < 12; j++)
|
|
||||||
{
|
|
||||||
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
|
|
||||||
|
|
||||||
if(memcmp(buf + 4, languages[j], 2) == 0)
|
|
||||||
{
|
|
||||||
*languageId = (u8)j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = i != 7 && j != 12;
|
|
||||||
|
|
||||||
exit:
|
|
||||||
IFile_Close(&file);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
|
static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
|
||||||
{
|
{
|
||||||
/* HANS:
|
/* HANS:
|
||||||
@ -285,7 +195,6 @@ static inline bool patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CF
|
|||||||
|
|
||||||
u8 *calledFunction = instr;
|
u8 *calledFunction = instr;
|
||||||
u32 i = 0;
|
u32 i = 0;
|
||||||
bool found;
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -307,7 +216,7 @@ static inline bool patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CF
|
|||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
while(i < 2 && !found && calledFunction[3] == 0xEA);
|
while(i < 2 && calledFunction[3] == 0xEA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,6 +248,214 @@ static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 findNearestStmfd(u8* code, u32 pos)
|
||||||
|
{
|
||||||
|
while(pos > 0)
|
||||||
|
{
|
||||||
|
if(*(u16 *)(code + pos + 2) == 0xE92D) return pos;
|
||||||
|
pos -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 findFunctionCommand(u8* code, u32 size, u32 command)
|
||||||
|
{
|
||||||
|
u32 func = 0;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < size && !func; i += 4)
|
||||||
|
if(*(u32 *)(code + i) == command) func = i;
|
||||||
|
|
||||||
|
return !func ? 0 : findNearestStmfd(code, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 findThrowFatalError(u8* code, u32 size)
|
||||||
|
{
|
||||||
|
u32 connectToPort = 0;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < size && !connectToPort; i += 4)
|
||||||
|
if(*(u32 *)(code + i) == 0xEF00002D) connectToPort = i - 4;
|
||||||
|
|
||||||
|
if(!connectToPort) return 0;
|
||||||
|
|
||||||
|
u32 func = 0;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < size && !func; i += 4)
|
||||||
|
{
|
||||||
|
if(*(u32 *)(code + i) != MAKE_BRANCH_LINK(i, connectToPort)) continue;
|
||||||
|
|
||||||
|
func = findNearestStmfd(code, i);
|
||||||
|
|
||||||
|
for(u32 pos = func + 4; func != 0 && pos <= size - 4 && *(u16 *)(code + pos + 2) != 0xE92D; pos += 4)
|
||||||
|
if(*(u32 *)(code + pos) == 0xE200167E) func = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline 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 */
|
||||||
|
|
||||||
|
char path[] = "/luma/titles/0000000000000000/code.bin";
|
||||||
|
progIdToStr(path + 28, progId);
|
||||||
|
|
||||||
|
IFile file;
|
||||||
|
|
||||||
|
if(R_FAILED(openLumaFile(&file, path))) return true;
|
||||||
|
|
||||||
|
bool ret;
|
||||||
|
u64 fileSize;
|
||||||
|
|
||||||
|
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u64 total;
|
||||||
|
|
||||||
|
ret = R_SUCCEEDED(IFile_Read(&file, &total, code, fileSize)) && total == fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFile_Close(&file);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
||||||
|
{
|
||||||
|
/* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/locale.txt"
|
||||||
|
If it exists it should contain, for example, "EUR IT" */
|
||||||
|
|
||||||
|
char path[] = "/luma/titles/0000000000000000/locale.txt";
|
||||||
|
progIdToStr(path + 28, progId);
|
||||||
|
|
||||||
|
IFile file;
|
||||||
|
|
||||||
|
if(R_FAILED(openLumaFile(&file, path))) return true;
|
||||||
|
|
||||||
|
bool ret;
|
||||||
|
u64 fileSize;
|
||||||
|
|
||||||
|
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 6 || fileSize > 8)
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[8];
|
||||||
|
u64 total;
|
||||||
|
|
||||||
|
if(R_FAILED(IFile_Read(&file, &total, buf, fileSize)))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 i,
|
||||||
|
j;
|
||||||
|
|
||||||
|
for(i = 0; i < 7; i++)
|
||||||
|
{
|
||||||
|
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
|
||||||
|
|
||||||
|
if(memcmp(buf, regions[i], 3) == 0)
|
||||||
|
{
|
||||||
|
*regionId = (u8)i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(j = 0; j < 12; j++)
|
||||||
|
{
|
||||||
|
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
|
||||||
|
|
||||||
|
if(memcmp(buf + 4, languages[j], 2) == 0)
|
||||||
|
{
|
||||||
|
*languageId = (u8)j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i != 7 && j != 12;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
IFile_Close(&file);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool patchRomfsRedirection(u64 progId, u8* code, u32 size)
|
||||||
|
{
|
||||||
|
/* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/romfs"
|
||||||
|
If it exists it should be a decrypted raw RomFS */
|
||||||
|
|
||||||
|
char path[] = "/luma/titles/0000000000000000/romfs";
|
||||||
|
progIdToStr(path + 28, progId);
|
||||||
|
|
||||||
|
IFile file;
|
||||||
|
|
||||||
|
if(R_FAILED(openLumaFile(&file, path))) return true;
|
||||||
|
|
||||||
|
bool ret;
|
||||||
|
u64 romfsSize;
|
||||||
|
|
||||||
|
if(R_FAILED(IFile_GetSize(&file, &romfsSize)))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 total;
|
||||||
|
u32 header;
|
||||||
|
|
||||||
|
if(R_FAILED(IFile_Read(&file, &total, &header, 4)) || total != 4 || header != 0x43465649)
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 fsOpenFileDirectly = findFunctionCommand(code, size, 0x08030204),
|
||||||
|
fsOpenLinkFile = findFunctionCommand(code, size, 0x80C0000),
|
||||||
|
throwFatalError = findThrowFatalError(code, size);
|
||||||
|
|
||||||
|
if(!fsOpenFileDirectly || !throwFatalError)
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Setup the payload
|
||||||
|
memcpy(code + throwFatalError, romfsredir_bin, romfsredir_bin_size);
|
||||||
|
*((u32 *)(code + throwFatalError + 0x10)) = *(u32 *)(code + fsOpenFileDirectly);
|
||||||
|
*((u32 *)(code + throwFatalError + romfsredir_bin_size - 0x08)) = sizeof(path);
|
||||||
|
*((u64 *)(code + throwFatalError + romfsredir_bin_size - 0x10)) = romfsSize - 0x1000ULL;
|
||||||
|
*((u64 *)(code + throwFatalError + romfsredir_bin_size - 0x18)) = 0x1000ULL;
|
||||||
|
*((u32 *)(code + throwFatalError + romfsredir_bin_size - 0x20)) = fsOpenFileDirectly + 0x100000;
|
||||||
|
|
||||||
|
//Place the hooks
|
||||||
|
*(u32 *)(code + fsOpenFileDirectly) = MAKE_BRANCH(fsOpenFileDirectly, throwFatalError);
|
||||||
|
|
||||||
|
if(fsOpenLinkFile != 0)
|
||||||
|
{
|
||||||
|
*(u32 *)(code + fsOpenLinkFile) = 0xE3A03003; //mov r3, #3
|
||||||
|
*(u32 *)(code + fsOpenLinkFile + 4) = MAKE_BRANCH(fsOpenLinkFile + 4, throwFatalError);
|
||||||
|
memcpy(code + fsOpenLinkFile + 8, path, sizeof(path));
|
||||||
|
*(u32 *)(code + throwFatalError + romfsredir_bin_size - 4) = fsOpenLinkFile + 8 + 0x100000; //String pointer
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(code + throwFatalError + romfsredir_bin_size, path, 0x30);
|
||||||
|
*(u32 *)(code + throwFatalError + romfsredir_bin_size - 4) = throwFatalError + romfsredir_bin_size + 0x100000; //String pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
loadCFWInfo();
|
loadCFWInfo();
|
||||||
@ -575,12 +692,13 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
|
|||||||
) != 3) goto error;
|
) != 3) goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(CONFIG(USELANGEMUANDCODE) && (u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000)
|
else if(CONFIG(PATCHGAMES) && (u32)((progId & 0xFFFFFFF000000000LL) >> 0x24) == 0x0004000)
|
||||||
{
|
{
|
||||||
u8 regionId = 0xFF,
|
u8 regionId = 0xFF,
|
||||||
languageId;
|
languageId;
|
||||||
if(!loadTitleLocaleConfig(progId, ®ionId, &languageId) ||
|
|
||||||
!loadTitleCodeSection(progId, code, size)) goto error;
|
if(!loadTitleCodeSection(progId, code, size) ||
|
||||||
|
!loadTitleLocaleConfig(progId, ®ionId, &languageId)) goto error;
|
||||||
|
|
||||||
if(regionId != 0xFF)
|
if(regionId != 0xFF)
|
||||||
{
|
{
|
||||||
@ -592,6 +710,8 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size)
|
|||||||
|
|
||||||
patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
|
patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!patchRomfsRedirection(progId, code, size)) goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include <3ds/types.h>
|
#include <3ds/types.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))
|
||||||
|
|
||||||
#define CONFIG(a) (((info.config >> (a + 20)) & 1) != 0)
|
#define CONFIG(a) (((info.config >> (a + 20)) & 1) != 0)
|
||||||
#define MULTICONFIG(a) ((info.config >> (a * 2 + 8)) & 3)
|
#define MULTICONFIG(a) ((info.config >> (a * 2 + 8)) & 3)
|
||||||
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
#define BOOTCONFIG(a, b) ((info.config >> a) & b)
|
||||||
@ -28,7 +31,7 @@ enum singleOptions
|
|||||||
USESYSFIRM,
|
USESYSFIRM,
|
||||||
LOADEXTFIRMSANDMODULES,
|
LOADEXTFIRMSANDMODULES,
|
||||||
USECUSTOMPATH,
|
USECUSTOMPATH,
|
||||||
USELANGEMUANDCODE,
|
PATCHGAMES,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
PATCHACCESS
|
PATCHACCESS
|
||||||
|
@ -80,7 +80,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
"( ) Use SysNAND FIRM if booting with R",
|
"( ) Use SysNAND FIRM if booting with R",
|
||||||
"( ) Enable loading external FIRMs and modules",
|
"( ) Enable loading external FIRMs and modules",
|
||||||
"( ) Use custom path",
|
"( ) Use custom path",
|
||||||
"( ) Enable region/language emu. and ext. .code",
|
"( ) Enable game patching",
|
||||||
"( ) Show NAND or user string in System Settings",
|
"( ) Show NAND or user string in System Settings",
|
||||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||||
"( ) Patch SVC/service/archive/ARM9 access"
|
"( ) Patch SVC/service/archive/ARM9 access"
|
||||||
@ -160,10 +160,12 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
|
|
||||||
"Enable overriding the region and\n"
|
"Enable overriding the region and\n"
|
||||||
"language configuration and the usage\n"
|
"language configuration and the usage\n"
|
||||||
"of patched code binaries for specific\n"
|
"of patched code binaries and\n"
|
||||||
"games.\n\n"
|
"custom RomFS for specific games.\n\n"
|
||||||
"Also makes certain DLCs for\n"
|
"Also makes certain DLCs for\n"
|
||||||
"out-of-region games work.\n\n"
|
"out-of-region games work.\n\n"
|
||||||
|
"Enabling this requires the\n"
|
||||||
|
"archive patch to be applied.\n\n"
|
||||||
"Refer to the wiki for instructions.",
|
"Refer to the wiki for instructions.",
|
||||||
|
|
||||||
"Enable showing the current NAND/FIRM:\n\n"
|
"Enable showing the current NAND/FIRM:\n\n"
|
||||||
|
@ -53,7 +53,7 @@ enum singleOptions
|
|||||||
USESYSFIRM,
|
USESYSFIRM,
|
||||||
LOADEXTFIRMSANDMODULES,
|
LOADEXTFIRMSANDMODULES,
|
||||||
USECUSTOMPATH,
|
USECUSTOMPATH,
|
||||||
USELANGEMUANDCODE,
|
PATCHGAMES,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
PATCHACCESS
|
PATCHACCESS
|
||||||
|
@ -195,11 +195,18 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, boo
|
|||||||
ret += patchKernel9Panic(arm9Section, kernel9Size);
|
ret += patchKernel9Panic(arm9Section, kernel9Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CONFIG(PATCHACCESS))
|
bool patchAccess = CONFIG(PATCHACCESS),
|
||||||
|
patchGames = CONFIG(PATCHGAMES);
|
||||||
|
|
||||||
|
if(patchAccess || patchGames)
|
||||||
{
|
{
|
||||||
ret += patchArm11SvcAccessChecks(arm11SvcHandler, (u32 *)(arm11Section1 + firm->section[1].size));
|
ret += patchK11ModuleChecks(arm11Section1, firm->section[1].size, &freeK11Space, patchGames);
|
||||||
ret += patchK11ModuleChecks(arm11Section1, firm->section[1].size, &freeK11Space);
|
|
||||||
ret += patchP9AccessChecks(process9Offset, process9Size);
|
if(patchAccess)
|
||||||
|
{
|
||||||
|
ret += patchArm11SvcAccessChecks(arm11SvcHandler, (u32 *)(arm11Section1 + firm->section[1].size));
|
||||||
|
ret += patchP9AccessChecks(process9Offset, process9Size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -429,13 +429,13 @@ u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space)
|
u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space, bool patchGames)
|
||||||
{
|
{
|
||||||
/* We have to detour a function in the ARM11 kernel because builtin modules
|
/* We have to detour a function in the ARM11 kernel because builtin modules
|
||||||
are compressed in memory and are only decompressed at runtime */
|
are compressed in memory and are only decompressed at runtime */
|
||||||
|
|
||||||
//Check that we have enough free space
|
//Check that we have enough free space
|
||||||
if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) != 0xFFFFFFFF) return 0;
|
if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) != 0xFFFFFFFF) return patchGames ? 1 : 0;
|
||||||
|
|
||||||
//Look for the code that decompresses the .code section of the builtin modules
|
//Look for the code that decompresses the .code section of the builtin modules
|
||||||
const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D};
|
const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D};
|
||||||
|
@ -54,7 +54,7 @@ u32 patchKernel9Panic(u8 *pos, u32 size);
|
|||||||
u32 patchKernel11Panic(u8 *pos, u32 size);
|
u32 patchKernel11Panic(u8 *pos, u32 size);
|
||||||
u32 patchP9AccessChecks(u8 *pos, u32 size);
|
u32 patchP9AccessChecks(u8 *pos, u32 size);
|
||||||
u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos);
|
u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos);
|
||||||
u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space);
|
u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space, bool patchGames);
|
||||||
u32 patchUnitInfoValueSet(u8 *pos, u32 size);
|
u32 patchUnitInfoValueSet(u8 *pos, u32 size);
|
||||||
u32 patchLgySignatureChecks(u8 *pos, u32 size);
|
u32 patchLgySignatureChecks(u8 *pos, u32 size);
|
||||||
u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size);
|
u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size);
|
||||||
|
@ -93,7 +93,8 @@ void newPin(bool allowSkipping, u32 pinMode)
|
|||||||
|
|
||||||
if(!pressed) continue;
|
if(!pressed) continue;
|
||||||
|
|
||||||
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password
|
//Add character to password
|
||||||
|
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
||||||
|
|
||||||
//Visualize character on screen
|
//Visualize character on screen
|
||||||
drawCharacter(enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
drawCharacter(enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
||||||
@ -200,7 +201,8 @@ bool verifyPin(u32 pinMode)
|
|||||||
|
|
||||||
if(!pressed) continue;
|
if(!pressed) continue;
|
||||||
|
|
||||||
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed); //Add character to password
|
//Add character to password
|
||||||
|
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
||||||
|
|
||||||
//Visualize character on screen
|
//Visualize character on screen
|
||||||
drawCharacter((char)enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
drawCharacter((char)enteredPassword[cnt], true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE);
|
||||||
|
Reference in New Issue
Block a user