Move patches to patches.c and emunand.c, section 0 copying to launchFirm for consistency
This commit is contained in:
parent
859944dc8e
commit
9aeac7af92
19
Makefile
19
Makefile
@ -33,7 +33,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)/screeninit.h
|
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.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
|
||||||
@ -83,22 +83,27 @@ $(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)/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
|
||||||
|
@ -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)
|
||||||
|
@ -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,11 @@ 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 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,7 +49,7 @@ 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 getEmuRW(u8 *pos, u32 size, u16 **readOffset, u16 **writeOffset)
|
||||||
{
|
{
|
||||||
//Look for read/write code
|
//Look for read/write code
|
||||||
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||||
@ -57,7 +58,7 @@ void getEmuRW(u8 *pos, u32 size, u16 **readOffset, u16 **writeOffset)
|
|||||||
*writeOffset = (u16 *)memsearch((u8 *)(*readOffset + 5), pattern, 0x100, 4) - 3;
|
*writeOffset = (u16 *)memsearch((u8 *)(*readOffset + 5), pattern, 0x100, 4) - 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 *getMPU(u8 *pos, u32 size)
|
static inline u32 *getMPU(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
//Look for MPU pattern
|
//Look for MPU pattern
|
||||||
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||||
@ -65,10 +66,49 @@ u32 *getMPU(u8 *pos, u32 size)
|
|||||||
return (u32 *)memsearch(pos, pattern, size, 4);
|
return (u32 *)memsearch(pos, pattern, size, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getEmuCode(u8 *pos)
|
static inline void *getEmuCode(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||||
|
|
||||||
//Looking for the last free space before Process9
|
//Looking for the last free space before Process9
|
||||||
return memsearch(pos + 0x13500, pattern, 0x1000, 6) + 0x455;
|
return memsearch(pos + 0x13500, pattern, size - 0x13500, 6) + 0x455;
|
||||||
|
}
|
||||||
|
|
||||||
|
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive)
|
||||||
|
{
|
||||||
|
//Copy emuNAND code
|
||||||
|
void *emuCodeOffset = getEmuCode(arm9Section, arm9SectionSize);
|
||||||
|
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);
|
||||||
|
|
||||||
|
//Add emuNAND hooks
|
||||||
|
u16 *emuRead,
|
||||||
|
*emuWrite;
|
||||||
|
u32 branchOffset = (u32)emuCodeOffset - branchAdditive;
|
||||||
|
getEmuRW(process9Offset, process9Size, &emuRead, &emuWrite);
|
||||||
|
const u16 nandRedir[2] = {0x4C00, 0x47A0};
|
||||||
|
|
||||||
|
*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, arm9SectionSize);
|
||||||
|
const u32 mpuPatch[3] = {0x00360003, 0x00200603, 0x001C0603};
|
||||||
|
|
||||||
|
*mpuOffset = mpuPatch[0];
|
||||||
|
mpuOffset[6] = mpuPatch[1];
|
||||||
|
mpuOffset[9] = mpuPatch[2];
|
||||||
}
|
}
|
@ -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 emuHeader, u32 branchAdditive);
|
||||||
void getEmuRW(u8 *pos, u32 size, u16 **readOffset, u16 **writeOffset);
|
|
||||||
u32 *getMPU(u8 *pos, u32 size);
|
|
||||||
void *getEmuCode(u8 *pos);
|
|
204
source/firm.c
204
source/firm.c
@ -13,7 +13,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;
|
||||||
@ -180,13 +180,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)
|
||||||
{
|
{
|
||||||
@ -224,7 +224,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)
|
||||||
@ -288,97 +288,47 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
|
|||||||
u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &process9MemAddr);
|
u8 *process9Offset = getProcess9(arm9Section + 0x15000, section[2].size - 0x15000, &process9Size, &process9MemAddr);
|
||||||
|
|
||||||
//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, 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();
|
if(nativeFirmType == 1) reimplementSvcBackdoor((u8 *)firm + section[1].offset, section[1].size);
|
||||||
|
|
||||||
//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)
|
||||||
@ -393,87 +343,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,22 +28,9 @@ 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 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);
|
159
source/patches.c
159
source/patches.c
@ -4,33 +4,8 @@
|
|||||||
|
|
||||||
#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};
|
|
||||||
|
|
||||||
//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)
|
||||||
{
|
{
|
||||||
@ -43,17 +18,23 @@ 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 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};
|
||||||
@ -61,26 +42,115 @@ 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
@ -99,16 +169,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,23 +6,20 @@
|
|||||||
|
|
||||||
#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 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 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
||||||
u16 *getFirmWrite(u8 *pos, u32 size);
|
void patchFirmWrites(u8 *pos, u32 size);
|
||||||
u16 *getFirmWriteSafe(u8 *pos, u32 size);
|
void patchFirmWriteSafe(u8 *pos, u32 size);
|
||||||
|
void reimplementSvcBackdoor(u8 *pos, u32 size);
|
||||||
|
void applyLegacyFirmPatches(u8 *pos, u32 firmType, u32 console);
|
||||||
u32 getLoader(u8 *pos, u32 *loaderSize);
|
u32 getLoader(u8 *pos, u32 *loaderSize);
|
||||||
u32 *getSvcAndExceptions(u8 *pos, u32 size, u32 **exceptionsPage);
|
|
Reference in New Issue
Block a user