Merge branch 'master' into developer
Conflicts: Makefile source/firm.c source/patches.c source/patches.h
This commit is contained in:
commit
2fab0be5e8
24
Makefile
24
Makefile
@ -12,7 +12,7 @@ LD := arm-none-eabi-ld
|
|||||||
OC := arm-none-eabi-objcopy
|
OC := arm-none-eabi-objcopy
|
||||||
|
|
||||||
name := Luma3DS
|
name := Luma3DS
|
||||||
version := $(shell git describe --abbrev=0 --tags)
|
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
|
||||||
|
|
||||||
dir_source := source
|
dir_source := source
|
||||||
dir_patches := patches
|
dir_patches := patches
|
||||||
@ -34,8 +34,7 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
bundled = $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/arm9_exceptions.h $(dir_build)/screeninit.h
|
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/arm9_exceptions.h $(dir_build)/injector.h $(dir_build)/loader.h $(dir_build)/screeninit.h
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: launcher a9lh ninjhax
|
all: launcher a9lh ninjhax
|
||||||
|
|
||||||
@ -86,17 +85,23 @@ $(dir_build)/main.bin: $(dir_build)/main.elf
|
|||||||
$(dir_build)/main.elf: $(objects)
|
$(dir_build)/main.elf: $(objects)
|
||||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
$(dir_build)/patches.h: $(dir_patches)/emunand.s $(dir_patches)/reboot.s $(dir_injector)/Makefile
|
$(dir_build)/emunandpatch.h: $(dir_patches)/emunand.s $(dir_injector)/Makefile
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
@armips $<
|
@armips $<
|
||||||
@armips $(word 2,$^)
|
@bin2c -o $@ -n emunand $(@D)/emunand.bin
|
||||||
|
|
||||||
|
$(dir_build)/rebootpatch.h: $(dir_patches)/reboot.s
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
@armips $<
|
||||||
|
@bin2c -o $@ -n reboot $(@D)/reboot.bin
|
||||||
|
|
||||||
|
$(dir_build)/injector.h: $(dir_injector)/Makefile
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
@$(MAKE) -C $(dir_injector)
|
@$(MAKE) -C $(dir_injector)
|
||||||
@mv emunand.bin reboot.bin $(dir_injector)/injector.cxi $(@D)
|
@bin2c -o $@ -n injector $(@D)/injector.cxi
|
||||||
@bin2c -o $@ -n emunand $(@D)/emunand.bin -n reboot $(@D)/reboot.bin -n injector $(@D)/injector.cxi
|
|
||||||
|
|
||||||
$(dir_build)/loader.h: $(dir_loader)/Makefile
|
$(dir_build)/loader.h: $(dir_loader)/Makefile
|
||||||
@$(MAKE) -C $(dir_loader)
|
@$(MAKE) -C $(dir_loader)
|
||||||
@mv $(dir_loader)/loader.bin $(@D)
|
|
||||||
@bin2c -o $@ -n loader $(@D)/loader.bin
|
@bin2c -o $@ -n loader $(@D)/loader.bin
|
||||||
|
|
||||||
$(dir_build)/arm9_exceptions.h: $(dir_arm9_exceptions)/Makefile
|
$(dir_build)/arm9_exceptions.h: $(dir_arm9_exceptions)/Makefile
|
||||||
@ -106,11 +111,10 @@ $(dir_build)/arm9_exceptions.h: $(dir_arm9_exceptions)/Makefile
|
|||||||
|
|
||||||
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
|
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
|
||||||
@$(MAKE) -C $(dir_screeninit)
|
@$(MAKE) -C $(dir_screeninit)
|
||||||
@mv $(dir_screeninit)/screeninit.bin $(@D)
|
|
||||||
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
|
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
|
||||||
|
|
||||||
$(dir_build)/memory.o: CFLAGS += -O3
|
$(dir_build)/memory.o: CFLAGS += -O3
|
||||||
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\""
|
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
|
@ -31,13 +31,13 @@ objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
|||||||
$(call rwildcard, $(dir_source), *.c))
|
$(call rwildcard, $(dir_source), *.c))
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(name).cxi
|
all: ../$(dir_build)/$(name).cxi
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(dir_build)
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
$(name).cxi: $(dir_build)/$(name).elf
|
../$(dir_build)/$(name).cxi: $(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: $(objects)
|
||||||
|
@ -473,6 +473,48 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 0x0004013000003702LL: // RO
|
||||||
|
{
|
||||||
|
static const u8 sigCheckPattern[] = {
|
||||||
|
0x30, 0x40, 0x2D, 0xE9, 0x02, 0x50, 0xA0, 0xE1
|
||||||
|
};
|
||||||
|
static const u8 sha256ChecksPattern1[] = {
|
||||||
|
0x30, 0x40, 0x2D, 0xE9, 0x24, 0xD0, 0x4D, 0xE2
|
||||||
|
};
|
||||||
|
static const u8 sha256ChecksPattern2[] = {
|
||||||
|
0xF8, 0x4F, 0x2D, 0xE9, 0x01, 0x70, 0xA0, 0xE1
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u8 stub[] = {
|
||||||
|
0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 // mov r0, #0; bx lr
|
||||||
|
};
|
||||||
|
|
||||||
|
//Disable CRR0 signature (RSA2048 with SHA256) check
|
||||||
|
patchMemory(code, size,
|
||||||
|
sigCheckPattern,
|
||||||
|
sizeof(sigCheckPattern), 0,
|
||||||
|
stub,
|
||||||
|
sizeof(stub), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
//Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
|
||||||
|
patchMemory(code, size,
|
||||||
|
sha256ChecksPattern1,
|
||||||
|
sizeof(sha256ChecksPattern1), 0,
|
||||||
|
stub,
|
||||||
|
sizeof(stub), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
patchMemory(code, size,
|
||||||
|
sha256ChecksPattern2,
|
||||||
|
sizeof(sha256ChecksPattern2), 0,
|
||||||
|
stub,
|
||||||
|
sizeof(stub), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if(CONFIG(4))
|
if(CONFIG(4))
|
||||||
{
|
{
|
||||||
|
@ -25,13 +25,13 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(name).bin
|
all: ../$(dir_build)/$(name).bin
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(dir_build)
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
$(name).bin: $(dir_build)/$(name).elf
|
../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf
|
||||||
$(OC) -S -O binary $< $@
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
$(dir_build)/$(name).elf: $(objects)
|
$(dir_build)/$(name).elf: $(objects)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.arm.little
|
.arm.little
|
||||||
|
|
||||||
.create "emunand.bin", 0
|
.create "build/emunand.bin", 0
|
||||||
.arm
|
.arm
|
||||||
nand_sd:
|
nand_sd:
|
||||||
; Original code that still needs to be executed.
|
; Original code that still needs to be executed.
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
payload_addr equ 0x23F00000 ; Brahma payload address.
|
payload_addr equ 0x23F00000 ; Brahma payload address.
|
||||||
payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
||||||
|
|
||||||
.create "reboot.bin", 0
|
.create "build/reboot.bin", 0
|
||||||
.arm
|
.arm
|
||||||
; Interesting registers and locations to keep in mind, set before this code is ran:
|
; Interesting registers and locations to keep in mind, set before this code is ran:
|
||||||
; - sp + 0x3A8 - 0x70: FIRM path in exefs.
|
; - sp + 0x3A8 - 0x70: FIRM path in exefs.
|
||||||
|
@ -25,13 +25,13 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(name).bin
|
all: ../$(dir_build)/$(name).bin
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(dir_build)
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
$(name).bin: $(dir_build)/$(name).elf
|
../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf
|
||||||
$(OC) -S -O binary $< $@
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
$(dir_build)/$(name).elf: $(objects)
|
$(dir_build)/$(name).elf: $(objects)
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
#include "emunand.h"
|
#include "emunand.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "fatfs/sdmmc/sdmmc.h"
|
#include "fatfs/sdmmc/sdmmc.h"
|
||||||
|
#include "../build/emunandpatch.h"
|
||||||
|
|
||||||
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
|
void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND)
|
||||||
{
|
{
|
||||||
static u8 *const temp = (u8 *)0x24300000;
|
static u8 *const temp = (u8 *)0x24300000;
|
||||||
|
|
||||||
@ -35,11 +36,19 @@ void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
(*emuNAND)--;
|
(*emuNAND)--;
|
||||||
if(*emuNAND) getEmunandSect(off, head, emuNAND);
|
if(*emuNAND) locateEmuNAND(off, head, emuNAND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getSDMMC(u8 *pos, u32 size)
|
static inline void *getEmuCode(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||||
|
|
||||||
|
//Looking for the last free space before Process9
|
||||||
|
return memsearch(pos + 0x13500, pattern, size - 0x13500, 6) + 0x455;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 getSDMMC(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
//Look for struct code
|
//Look for struct code
|
||||||
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
||||||
@ -48,27 +57,58 @@ u32 getSDMMC(u8 *pos, u32 size)
|
|||||||
return *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
|
return *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getEmuRW(u8 *pos, u32 size, u16 **readOffset, u16 **writeOffset)
|
static inline void patchNANDRW(u8 *pos, u32 size, u32 branchOffset)
|
||||||
{
|
{
|
||||||
|
const u16 nandRedir[2] = {0x4C00, 0x47A0};
|
||||||
|
|
||||||
//Look for read/write code
|
//Look for read/write code
|
||||||
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||||
|
|
||||||
*readOffset = (u16 *)memsearch(pos, pattern, size, 4) - 3;
|
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, 4) - 3;
|
||||||
*writeOffset = (u16 *)memsearch((u8 *)(*readOffset + 5), pattern, 0x100, 4) - 3;
|
u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, 4) - 3;
|
||||||
|
|
||||||
|
*readOffset = nandRedir[0];
|
||||||
|
readOffset[1] = nandRedir[1];
|
||||||
|
((u32 *)readOffset)[1] = branchOffset;
|
||||||
|
*writeOffset = nandRedir[0];
|
||||||
|
writeOffset[1] = nandRedir[1];
|
||||||
|
((u32 *)writeOffset)[1] = branchOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 *getMPU(u8 *pos, u32 size)
|
static inline void patchMPU(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
|
const u32 mpuPatch[3] = {0x00360003, 0x00200603, 0x001C0603};
|
||||||
|
|
||||||
//Look for MPU pattern
|
//Look for MPU pattern
|
||||||
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||||
|
|
||||||
return (u32 *)memsearch(pos, pattern, size, 4);
|
u32 *off = (u32 *)memsearch(pos, pattern, size, 4);
|
||||||
|
|
||||||
|
off[0] = mpuPatch[0];
|
||||||
|
off[6] = mpuPatch[1];
|
||||||
|
off[9] = mpuPatch[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getEmuCode(u8 *pos)
|
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive)
|
||||||
{
|
{
|
||||||
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
//Copy emuNAND code
|
||||||
|
void *emuCodeOffset = getEmuCode(arm9Section, arm9SectionSize);
|
||||||
|
memcpy(emuCodeOffset, emunand, emunand_size);
|
||||||
|
|
||||||
//Looking for the last free space before Process9
|
//Add the data of the found emuNAND
|
||||||
return memsearch(pos + 0x13500, pattern, 0x1000, 6) + 0x455;
|
u32 *pos_offset = (u32 *)memsearch(emuCodeOffset, "NAND", emunand_size, 4);
|
||||||
|
u32 *pos_header = (u32 *)memsearch(emuCodeOffset, "NCSD", emunand_size, 4);
|
||||||
|
*pos_offset = emuOffset;
|
||||||
|
*pos_header = emuHeader;
|
||||||
|
|
||||||
|
//Find and add the SDMMC struct
|
||||||
|
u32 *pos_sdmmc = (u32 *)memsearch(emuCodeOffset, "SDMC", emunand_size, 4);
|
||||||
|
*pos_sdmmc = getSDMMC(process9Offset, process9Size);
|
||||||
|
|
||||||
|
//Add emuNAND hooks
|
||||||
|
u32 branchOffset = (u32)emuCodeOffset - branchAdditive;
|
||||||
|
patchNANDRW(process9Offset, process9Size, branchOffset);
|
||||||
|
|
||||||
|
//Set MPU for emu code region
|
||||||
|
patchMPU(arm9Section, arm9SectionSize);
|
||||||
}
|
}
|
@ -8,8 +8,5 @@
|
|||||||
|
|
||||||
#define NCSD_MAGIC 0x4453434E
|
#define NCSD_MAGIC 0x4453434E
|
||||||
|
|
||||||
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
|
void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND);
|
||||||
u32 getSDMMC(u8 *pos, u32 size);
|
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive);
|
||||||
void getEmuRW(u8 *pos, u32 size, u16 **readOffset, u16 **writeOffset);
|
|
||||||
u32 *getMPU(u8 *pos, u32 size);
|
|
||||||
void *getEmuCode(u8 *pos);
|
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "diskio.h" /* FatFs lower layer API */
|
#include "diskio.h" /* FatFs lower layer API */
|
||||||
#include "sdmmc/sdmmc.h"
|
#include "sdmmc/sdmmc.h"
|
||||||
|
#include "../crypto.h"
|
||||||
|
|
||||||
/* Definitions of physical drive number for each media */
|
/* Definitions of physical drive number for each media */
|
||||||
#define SDCARD 0
|
#define SDCARD 0
|
||||||
|
@ -2,4 +2,3 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "../../types.h"
|
#include "../../types.h"
|
||||||
#include "../../crypto.h"
|
|
208
source/firm.c
208
source/firm.c
@ -14,7 +14,7 @@
|
|||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "screeninit.h"
|
#include "screeninit.h"
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
#include "../build/patches.h"
|
#include "../build/injector.h"
|
||||||
|
|
||||||
static firmHeader *const firm = (firmHeader *)0x24000000;
|
static firmHeader *const firm = (firmHeader *)0x24000000;
|
||||||
static const firmSectionHeader *section;
|
static const firmSectionHeader *section;
|
||||||
@ -222,13 +222,13 @@ void main(void)
|
|||||||
//If we need to boot emuNAND, make sure it exists
|
//If we need to boot emuNAND, make sure it exists
|
||||||
if(nandType)
|
if(nandType)
|
||||||
{
|
{
|
||||||
getEmunandSect(&emuOffset, &emuHeader, &nandType);
|
locateEmuNAND(&emuOffset, &emuHeader, &nandType);
|
||||||
if(!nandType) firmSource = 0;
|
if(!nandType) firmSource = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Same if we're using emuNAND as the FIRM source
|
//Same if we're using emuNAND as the FIRM source
|
||||||
else if(firmSource)
|
else if(firmSource)
|
||||||
getEmunandSect(&emuOffset, &emuHeader, &firmSource);
|
locateEmuNAND(&emuOffset, &emuHeader, &firmSource);
|
||||||
|
|
||||||
if(!bootType)
|
if(!bootType)
|
||||||
{
|
{
|
||||||
@ -268,7 +268,7 @@ void main(void)
|
|||||||
stopChrono();
|
stopChrono();
|
||||||
}
|
}
|
||||||
|
|
||||||
launchFirm(!firmType, bootType);
|
launchFirm(firmType, bootType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void loadFirm(u32 firmType, u32 externalFirm)
|
static inline void loadFirm(u32 firmType, u32 externalFirm)
|
||||||
@ -346,24 +346,27 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
|
|||||||
process9MemAddr;
|
process9MemAddr;
|
||||||
u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &process9MemAddr);
|
u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &process9MemAddr);
|
||||||
|
|
||||||
|
//Apply signature patches
|
||||||
|
patchSignatureChecks(process9Offset, process9Size);
|
||||||
|
|
||||||
|
//Apply anti-anti-DG patches for >= 11.0 firmwares
|
||||||
|
if(nativeFirmType == 1) patchTitleInstallMinVersionCheck(process9Offset, process9Size);
|
||||||
|
|
||||||
//Apply emuNAND patches
|
//Apply emuNAND patches
|
||||||
if(nandType) patchEmuNAND(arm9Section, process9Offset, process9Size, emuHeader);
|
if(nandType)
|
||||||
|
{
|
||||||
|
u32 branchAdditive = (u32)firm + section[2].offset - (u32)section[2].address;
|
||||||
|
patchEmuNAND(arm9Section, section[2].size, process9Offset, process9Size, emuOffset, emuHeader, branchAdditive);
|
||||||
|
}
|
||||||
|
|
||||||
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
||||||
else if(a9lhMode) patchFirmWrites(process9Offset, process9Size, 1);
|
else if(a9lhMode) patchFirmWrites(process9Offset, process9Size);
|
||||||
|
|
||||||
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
//Apply firmlaunch patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
||||||
if(nativeFirmType || a9lhMode == 2) patchReboots(process9Offset, process9Size, process9MemAddr);
|
if(nativeFirmType || a9lhMode == 2) patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
|
||||||
|
|
||||||
//Apply signature checks patches
|
|
||||||
u16 *sigOffset,
|
|
||||||
*sigOffset2;
|
|
||||||
getSigChecks(process9Offset, process9Size, &sigOffset, &sigOffset2);
|
|
||||||
*sigOffset = sigPatch[0];
|
|
||||||
sigOffset2[0] = sigPatch[0];
|
|
||||||
sigOffset2[1] = sigPatch[1];
|
|
||||||
|
|
||||||
//Does nothing if svcBackdoor is still there
|
//Does nothing if svcBackdoor is still there
|
||||||
|
if(nativeFirmType == 1) reimplementSvcBackdoor((u8 *)firm + section[1].offset, section[1].size);
|
||||||
if(nativeFirmType == 1) reimplementSvcBackdoor();
|
if(nativeFirmType == 1) reimplementSvcBackdoor();
|
||||||
|
|
||||||
if(DEVMODE)
|
if(DEVMODE)
|
||||||
@ -375,79 +378,32 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
|
|||||||
//Make FCRAM (and VRAM as a side effect) globally executable from arm11 kernel
|
//Make FCRAM (and VRAM as a side effect) globally executable from arm11 kernel
|
||||||
patchKernelFCRAMAndVRAMMappingPermissions();
|
patchKernelFCRAMAndVRAMMappingPermissions();
|
||||||
}
|
}
|
||||||
//Replace the FIRM loader with the injector while copying section0
|
|
||||||
copySection0AndInjectLoader();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void patchEmuNAND(u8 *arm9Section, u8 *process9Offset, u32 process9Size, u32 emuHeader)
|
static inline void patchLegacyFirm(u32 firmType)
|
||||||
{
|
{
|
||||||
//Copy emuNAND code
|
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
void *emuCodeOffset = getEmuCode(arm9Section);
|
if(console)
|
||||||
memcpy(emuCodeOffset, emunand, emunand_size);
|
|
||||||
|
|
||||||
//Add the data of the found emuNAND
|
|
||||||
u32 *pos_offset = (u32 *)memsearch(emuCodeOffset, "NAND", emunand_size, 4);
|
|
||||||
u32 *pos_header = (u32 *)memsearch(emuCodeOffset, "NCSD", emunand_size, 4);
|
|
||||||
*pos_offset = emuOffset;
|
|
||||||
*pos_header = emuHeader;
|
|
||||||
|
|
||||||
//Find and add the SDMMC struct
|
|
||||||
u32 *pos_sdmmc = (u32 *)memsearch(emuCodeOffset, "SDMC", emunand_size, 4);
|
|
||||||
*pos_sdmmc = getSDMMC(process9Offset, process9Size);
|
|
||||||
|
|
||||||
//Calculate offset for the hooks
|
|
||||||
u32 branchOffset = (u32)emuCodeOffset - (u32)firm -
|
|
||||||
section[2].offset + (u32)section[2].address;
|
|
||||||
|
|
||||||
//Add emuNAND hooks
|
|
||||||
u16 *emuRead,
|
|
||||||
*emuWrite;
|
|
||||||
|
|
||||||
getEmuRW(process9Offset, process9Size, &emuRead, &emuWrite);
|
|
||||||
*emuRead = nandRedir[0];
|
|
||||||
emuRead[1] = nandRedir[1];
|
|
||||||
((u32 *)emuRead)[1] = branchOffset;
|
|
||||||
*emuWrite = nandRedir[0];
|
|
||||||
emuWrite[1] = nandRedir[1];
|
|
||||||
((u32 *)emuWrite)[1] = branchOffset;
|
|
||||||
|
|
||||||
//Set MPU for emu code region
|
|
||||||
u32 *mpuOffset = getMPU(arm9Section, section[2].size);
|
|
||||||
*mpuOffset = mpuPatch[0];
|
|
||||||
mpuOffset[6] = mpuPatch[1];
|
|
||||||
mpuOffset[9] = mpuPatch[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void patchReboots(u8 *process9Offset, u32 process9Size, u32 process9MemAddr)
|
|
||||||
{
|
|
||||||
//Calculate offset for the firmlaunch code and fOpen
|
|
||||||
u32 fOpenOffset;
|
|
||||||
void *rebootOffset = getReboot(process9Offset, process9Size, process9MemAddr, &fOpenOffset);
|
|
||||||
|
|
||||||
//Copy firmlaunch code
|
|
||||||
memcpy(rebootOffset, reboot, reboot_size);
|
|
||||||
|
|
||||||
//Put the fOpen offset in the right location
|
|
||||||
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
|
|
||||||
*pos_fopen = fOpenOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void reimplementSvcBackdoor(void)
|
|
||||||
{
|
|
||||||
u8 *arm11Section1 = (u8 *)firm + section[1].offset;
|
|
||||||
|
|
||||||
u32 *exceptionsPage;
|
|
||||||
u32 *svcTable = getSvcAndExceptions(arm11Section1, section[1].size, &exceptionsPage);
|
|
||||||
|
|
||||||
if(!svcTable[0x7B])
|
|
||||||
{
|
{
|
||||||
u32 *freeSpace;
|
arm9Loader((u8 *)firm + section[3].offset, 0);
|
||||||
for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
|
firm->arm9Entry = (u8 *)0x801301C;
|
||||||
|
|
||||||
memcpy(freeSpace, svcBackdoor, 40);
|
|
||||||
|
|
||||||
svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyLegacyFirmPatches((u8 *)firm, firmType, console);}
|
||||||
|
|
||||||
|
static inline void patchSafeFirm(void)
|
||||||
|
{
|
||||||
|
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
||||||
|
|
||||||
|
if(console)
|
||||||
|
{
|
||||||
|
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
|
arm9Loader(arm9Section, 0);
|
||||||
|
firm->arm9Entry = (u8 *)0x801B01C;
|
||||||
|
|
||||||
|
patchFirmWrites(arm9Section, section[2].size);
|
||||||
|
}
|
||||||
|
else patchFirmWriteSafe(arm9Section, section[2].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void copySection0AndInjectLoader(void)
|
static inline void copySection0AndInjectLoader(void)
|
||||||
@ -462,87 +418,17 @@ static inline void copySection0AndInjectLoader(void)
|
|||||||
memcpy(section[0].address + loaderOffset + injector_size, arm11Section0 + loaderOffset + loaderSize, section[0].size - (loaderOffset + loaderSize));
|
memcpy(section[0].address + loaderOffset + injector_size, arm11Section0 + loaderOffset + loaderSize, section[0].size - (loaderOffset + loaderSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void patchSafeFirm(void)
|
static inline void launchFirm(u32 firmType, u32 bootType)
|
||||||
{
|
{
|
||||||
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
//If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector
|
||||||
|
u32 sectionNum;
|
||||||
if(console)
|
if(!firmType)
|
||||||
{
|
{
|
||||||
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
copySection0AndInjectLoader();
|
||||||
arm9Loader(arm9Section, 0);
|
sectionNum = 1;
|
||||||
firm->arm9Entry = (u8 *)0x801B01C;
|
|
||||||
}
|
}
|
||||||
|
else sectionNum = 0;
|
||||||
|
|
||||||
//Apply FIRM0/1 writes patches to protect A9LH
|
|
||||||
patchFirmWrites(arm9Section, section[2].size, console);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void patchFirmWrites(u8 *offset, u32 size, u32 mode)
|
|
||||||
{
|
|
||||||
if(mode)
|
|
||||||
{
|
|
||||||
u16 *writeOffset = getFirmWrite(offset, size);
|
|
||||||
*writeOffset = writeBlock[0];
|
|
||||||
*(writeOffset + 1) = writeBlock[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u16 *writeOffset = getFirmWriteSafe(offset, size);
|
|
||||||
*writeOffset = writeBlockSafe[0];
|
|
||||||
*(writeOffset + 1) = writeBlockSafe[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void patchLegacyFirm(u32 firmType)
|
|
||||||
{
|
|
||||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
|
||||||
if(console)
|
|
||||||
{
|
|
||||||
arm9Loader((u8 *)firm + section[3].offset, 0);
|
|
||||||
firm->arm9Entry = (u8 *)0x801301C;
|
|
||||||
}
|
|
||||||
|
|
||||||
const patchData twlPatches[] = {
|
|
||||||
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
|
||||||
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
|
|
||||||
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
|
|
||||||
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
|
|
||||||
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
|
|
||||||
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
|
|
||||||
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
|
|
||||||
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
|
|
||||||
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
|
|
||||||
},
|
|
||||||
agbPatches[] = {
|
|
||||||
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
|
||||||
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
|
|
||||||
if the matching option was enabled (keep it as last) */
|
|
||||||
u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) :
|
|
||||||
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6));
|
|
||||||
const patchData *patches = firmType == 1 ? twlPatches : agbPatches;
|
|
||||||
|
|
||||||
//Patch
|
|
||||||
for(u32 i = 0; i < numPatches; i++)
|
|
||||||
{
|
|
||||||
switch(patches[i].type)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
memcpy((u8 *)firm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
*(u16 *)((u8 *)firm + patches[i].offset[console] + 2) = 0;
|
|
||||||
case 1:
|
|
||||||
*(u16 *)((u8 *)firm + patches[i].offset[console]) = patches[i].patch.type1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void launchFirm(u32 sectionNum, u32 bootType)
|
|
||||||
{
|
|
||||||
//Copy FIRM sections to respective memory locations
|
//Copy FIRM sections to respective memory locations
|
||||||
for(; sectionNum < 4 && section[sectionNum].size; sectionNum++)
|
for(; sectionNum < 4 && section[sectionNum].size; sectionNum++)
|
||||||
memcpy(section[sectionNum].address, (u8 *)firm + section[sectionNum].offset, section[sectionNum].size);
|
memcpy(section[sectionNum].address, (u8 *)firm + section[sectionNum].offset, section[sectionNum].size);
|
||||||
|
@ -28,23 +28,10 @@ typedef struct firmHeader {
|
|||||||
firmSectionHeader section[4];
|
firmSectionHeader section[4];
|
||||||
} firmHeader;
|
} firmHeader;
|
||||||
|
|
||||||
typedef struct patchData {
|
|
||||||
u32 offset[2];
|
|
||||||
union {
|
|
||||||
u8 type0[8];
|
|
||||||
u16 type1;
|
|
||||||
} patch;
|
|
||||||
u32 type;
|
|
||||||
} patchData;
|
|
||||||
|
|
||||||
static inline void loadFirm(u32 firmType, u32 externalFirm);
|
static inline void loadFirm(u32 firmType, u32 externalFirm);
|
||||||
static inline void patchKernelFCRAMAndVRAMMappingPermissions(void);
|
static inline void patchKernelFCRAMAndVRAMMappingPermissions(void);
|
||||||
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode);
|
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode);
|
||||||
static inline void patchEmuNAND(u8 *arm9Section, u8 *process9Offset, u32 process9Size, u32 emuHeader);
|
|
||||||
static inline void patchReboots(u8 *process9Offset, u32 process9Size, u32 process9MemAddr);
|
|
||||||
static inline void reimplementSvcBackdoor(void);
|
|
||||||
static inline void copySection0AndInjectLoader(void);
|
|
||||||
static inline void patchSafeFirm(void);
|
|
||||||
static void patchFirmWrites(u8 *offset, u32 size, u32 mode);
|
|
||||||
static inline void patchLegacyFirm(u32 firmType);
|
static inline void patchLegacyFirm(u32 firmType);
|
||||||
|
static inline void patchSafeFirm(void);
|
||||||
|
static inline void copySection0AndInjectLoader(void);
|
||||||
static inline void launchFirm(u32 sectionNum, u32 bootType);
|
static inline void launchFirm(u32 sectionNum, u32 bootType);
|
166
source/patches.c
166
source/patches.c
@ -4,36 +4,11 @@
|
|||||||
|
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "config.h"
|
||||||
/**************************************************
|
#include "../build/rebootpatch.h"
|
||||||
* Patches
|
|
||||||
**************************************************/
|
|
||||||
|
|
||||||
const u32 mpuPatch[3] = {0x00360003, 0x00200603, 0x001C0603};
|
|
||||||
|
|
||||||
const u16 nandRedir[2] = {0x4C00, 0x47A0},
|
|
||||||
sigPatch[2] = {0x2000, 0x4770},
|
|
||||||
writeBlock[2] = {0x2000, 0x46C0},
|
|
||||||
writeBlockSafe[2] = {0x2400, 0xE01D};
|
|
||||||
|
|
||||||
const u8 unitInfoPatch = 0xE3;
|
const u8 unitInfoPatch = 0xE3;
|
||||||
|
|
||||||
//Official implementation of svcBackdoor
|
|
||||||
const u8 svcBackdoor[40] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff
|
|
||||||
0x0F, 0x1C, 0x81, 0xE3, //orr r1, r1, #0xf00
|
|
||||||
0x28, 0x10, 0x81, 0xE2, //add r1, r1, #0x28
|
|
||||||
0x00, 0x20, 0x91, 0xE5, //ldr r2, [r1]
|
|
||||||
0x00, 0x60, 0x22, 0xE9, //stmdb r2!, {sp, lr}
|
|
||||||
0x02, 0xD0, 0xA0, 0xE1, //mov sp, r2
|
|
||||||
0x30, 0xFF, 0x2F, 0xE1, //blx r0
|
|
||||||
0x03, 0x00, 0xBD, 0xE8, //pop {r0, r1}
|
|
||||||
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
|
|
||||||
0x11, 0xFF, 0x2F, 0xE1}; //bx r1
|
|
||||||
|
|
||||||
/**************************************************
|
|
||||||
* Functions
|
|
||||||
**************************************************/
|
|
||||||
|
|
||||||
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
||||||
{
|
{
|
||||||
u8 *off = memsearch(pos, "ess9", size, 4);
|
u8 *off = memsearch(pos, "ess9", size, 4);
|
||||||
@ -45,17 +20,32 @@ u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
|||||||
return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200;
|
return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getSigChecks(u8 *pos, u32 size, u16 **off, u16 **off2)
|
void patchSignatureChecks(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
|
const u16 sigPatch[2] = {0x2000, 0x4770};
|
||||||
|
|
||||||
//Look for signature checks
|
//Look for signature checks
|
||||||
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
|
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
|
||||||
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
|
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
|
||||||
|
|
||||||
*off = (u16 *)memsearch(pos, pattern, size, 4);
|
u16 *off = (u16 *)memsearch(pos, pattern, size, 4),
|
||||||
*off2 = (u16 *)(memsearch(pos, pattern2, size, 4) - 1);
|
*off2 = (u16 *)(memsearch(pos, pattern2, size, 4) - 1);
|
||||||
|
|
||||||
|
*off = sigPatch[0];
|
||||||
|
off2[0] = sigPatch[0];
|
||||||
|
off2[1] = sigPatch[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getReboot(u8 *pos, u32 size, u32 process9MemAddr, u32 *fOpenOffset)
|
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
const u8 pattern[] = {0x89, 0x0A, 0x81, 0x42, 0x02, 0xD2};
|
||||||
|
|
||||||
|
u8 *off = memsearch(pos, pattern, size, 6);
|
||||||
|
|
||||||
|
if(off != NULL) off[5] = 0xE0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
|
||||||
{
|
{
|
||||||
//Look for FIRM reboot code
|
//Look for FIRM reboot code
|
||||||
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
|
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
|
||||||
@ -63,26 +53,41 @@ void *getReboot(u8 *pos, u32 size, u32 process9MemAddr, u32 *fOpenOffset)
|
|||||||
u8 *off = memsearch(pos, pattern, size, 4) - 0x10;
|
u8 *off = memsearch(pos, pattern, size, 4) - 0x10;
|
||||||
|
|
||||||
//Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1
|
//Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1
|
||||||
*fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr);
|
u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr);
|
||||||
|
|
||||||
return off;
|
//Copy firmlaunch code
|
||||||
|
memcpy(off, reboot, reboot_size);
|
||||||
|
|
||||||
|
//Put the fOpen offset in the right location
|
||||||
|
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_size, 4);
|
||||||
|
*pos_fopen = fOpenOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 *getFirmWrite(u8 *pos, u32 size)
|
void patchFirmWrites(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
|
const u16 writeBlock[2] = {0x2000, 0x46C0};
|
||||||
|
|
||||||
//Look for FIRM writing code
|
//Look for FIRM writing code
|
||||||
u8 *const off = memsearch(pos, "exe:", size, 4);
|
u8 *const off1 = memsearch(pos, "exe:", size, 4);
|
||||||
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
||||||
|
|
||||||
return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4);
|
u16 *off2 = (u16 *)memsearch(off1 - 0x100, pattern, 0x100, 4);
|
||||||
|
|
||||||
|
off2[0] = writeBlock[0];
|
||||||
|
off2[1] = writeBlock[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 *getFirmWriteSafe(u8 *pos, u32 size)
|
void patchFirmWriteSafe(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
|
const u16 writeBlockSafe[2] = {0x2400, 0xE01D};
|
||||||
|
|
||||||
//Look for FIRM writing code
|
//Look for FIRM writing code
|
||||||
const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
|
const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
|
||||||
|
|
||||||
return (u16 *)memsearch(pos, pattern, size, 4);
|
u16 *off = (u16 *)memsearch(pos, pattern, size, 4);
|
||||||
|
|
||||||
|
off[0] = writeBlockSafe[0];
|
||||||
|
off[1] = writeBlockSafe[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *getUnitInfoValueSet(u8 *pos, u32 size)
|
u8 *getUnitInfoValueSet(u8 *pos, u32 size)
|
||||||
@ -93,6 +98,80 @@ u8 *getUnitInfoValueSet(u8 *pos, u32 size)
|
|||||||
return memsearch(pos, pattern, size, 4) + 3;
|
return memsearch(pos, pattern, size, 4) + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reimplementSvcBackdoor(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
//Official implementation of svcBackdoor
|
||||||
|
const u8 svcBackdoor[40] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff
|
||||||
|
0x0F, 0x1C, 0x81, 0xE3, //orr r1, r1, #0xf00
|
||||||
|
0x28, 0x10, 0x81, 0xE2, //add r1, r1, #0x28
|
||||||
|
0x00, 0x20, 0x91, 0xE5, //ldr r2, [r1]
|
||||||
|
0x00, 0x60, 0x22, 0xE9, //stmdb r2!, {sp, lr}
|
||||||
|
0x02, 0xD0, 0xA0, 0xE1, //mov sp, r2
|
||||||
|
0x30, 0xFF, 0x2F, 0xE1, //blx r0
|
||||||
|
0x03, 0x00, 0xBD, 0xE8, //pop {r0, r1}
|
||||||
|
0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0
|
||||||
|
0x11, 0xFF, 0x2F, 0xE1}; //bx r1
|
||||||
|
|
||||||
|
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif
|
||||||
|
|
||||||
|
u32 *exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB;
|
||||||
|
|
||||||
|
u32 svcOffset = (-((exceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
||||||
|
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
|
||||||
|
while(*svcTable) svcTable++; //Look for SVC0 (NULL)
|
||||||
|
|
||||||
|
if(!svcTable[0x7B])
|
||||||
|
{
|
||||||
|
u32 *freeSpace;
|
||||||
|
for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++);
|
||||||
|
|
||||||
|
memcpy(freeSpace, svcBackdoor, 40);
|
||||||
|
|
||||||
|
svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console)
|
||||||
|
{
|
||||||
|
const patchData twlPatches[] = {
|
||||||
|
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||||
|
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
|
||||||
|
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
|
||||||
|
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
|
||||||
|
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
|
||||||
|
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
|
||||||
|
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
|
||||||
|
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
|
||||||
|
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
|
||||||
|
},
|
||||||
|
agbPatches[] = {
|
||||||
|
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||||
|
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
|
||||||
|
if the matching option was enabled (keep it as last) */
|
||||||
|
u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) :
|
||||||
|
(sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6));
|
||||||
|
const patchData *patches = firmType == 1 ? twlPatches : agbPatches;
|
||||||
|
|
||||||
|
//Patch
|
||||||
|
for(u32 i = 0; i < numPatches; i++)
|
||||||
|
{
|
||||||
|
switch(patches[i].type)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
memcpy(pos + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*(u16 *)(pos + patches[i].offset[console] + 2) = 0;
|
||||||
|
case 1:
|
||||||
|
*(u16 *)(pos + patches[i].offset[console]) = patches[i].patch.type1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u32 getLoader(u8 *pos, u32 *loaderSize)
|
u32 getLoader(u8 *pos, u32 *loaderSize)
|
||||||
{
|
{
|
||||||
u8 *off = pos;
|
u8 *off = pos;
|
||||||
@ -109,16 +188,3 @@ u32 getLoader(u8 *pos, u32 *loaderSize)
|
|||||||
|
|
||||||
return (u32)(off - pos);
|
return (u32)(off - pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 *getSvcAndExceptions(u8 *pos, u32 size, u32 **exceptionsPage)
|
|
||||||
{
|
|
||||||
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif
|
|
||||||
|
|
||||||
*exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB;
|
|
||||||
|
|
||||||
u32 svcOffset = (-(((*exceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
|
||||||
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
|
|
||||||
while(*svcTable) svcTable++; //Look for SVC0 (NULL)
|
|
||||||
|
|
||||||
return svcTable;
|
|
||||||
}
|
|
@ -6,25 +6,21 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
/**************************************************
|
typedef struct patchData {
|
||||||
* Patches
|
u32 offset[2];
|
||||||
**************************************************/
|
union {
|
||||||
const u32 mpuPatch[3];
|
u8 type0[8];
|
||||||
const u16 nandRedir[2],
|
u16 type1;
|
||||||
sigPatch[2],
|
} patch;
|
||||||
writeBlock[2],
|
u32 type;
|
||||||
writeBlockSafe[2];
|
} patchData;
|
||||||
const u8 unitInfoPatch;
|
const u8 unitInfoPatch;
|
||||||
const u8 svcBackdoor[40];
|
|
||||||
|
|
||||||
/**************************************************
|
|
||||||
* Functions
|
|
||||||
**************************************************/
|
|
||||||
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
||||||
void getSigChecks(u8 *pos, u32 size, u16 **off, u16 **off2);
|
void patchSignatureChecks(u8 *pos, u32 size);
|
||||||
void *getReboot(u8 *pos, u32 size, u32 process9MemAddr, u32 *fOpenOffset);
|
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size);
|
||||||
u16 *getFirmWrite(u8 *pos, u32 size);
|
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
||||||
u16 *getFirmWriteSafe(u8 *pos, u32 size);
|
void patchFirmWrites(u8 *pos, u32 size);
|
||||||
|
void patchFirmWriteSafe(u8 *pos, u32 size);
|
||||||
|
void reimplementSvcBackdoor(u8 *pos, u32 size);
|
||||||
|
void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console);
|
||||||
u8 *getUnitInfoValueSet(u8 *pos, u32 size);
|
u8 *getUnitInfoValueSet(u8 *pos, u32 size);
|
||||||
u32 getLoader(u8 *pos, u32 *loaderSize);
|
|
||||||
u32 *getSvcAndExceptions(u8 *pos, u32 size, u32 **exceptionsPage);
|
|
Reference in New Issue
Block a user