Move patches to patches.c and emunand.c, section 0 copying to launchFirm for consistency

This commit is contained in:
Aurora 2016-05-25 14:34:43 +02:00
parent 859944dc8e
commit 9aeac7af92
12 changed files with 236 additions and 273 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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.

View File

@ -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.

View File

@ -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)

View File

@ -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];
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);