From 9aeac7af9270cbbc40987f48a60af4130437bdfb Mon Sep 17 00:00:00 2001 From: Aurora Date: Wed, 25 May 2016 14:34:43 +0200 Subject: [PATCH] Move patches to patches.c and emunand.c, section 0 copying to launchFirm for consistency --- Makefile | 19 +++-- injector/Makefile | 4 +- loader/Makefile | 4 +- patches/emunand.s | 2 +- patches/reboot.s | 2 +- screeninit/Makefile | 4 +- source/emunand.c | 54 ++++++++++-- source/emunand.h | 7 +- source/firm.c | 204 +++++++++----------------------------------- source/firm.h | 17 +--- source/patches.c | 159 +++++++++++++++++++++++----------- source/patches.h | 33 ++++--- 12 files changed, 236 insertions(+), 273 deletions(-) diff --git a/Makefile b/Makefile index 1966720..abcf576 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ $(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 all: launcher a9lh ninjhax @@ -83,22 +83,27 @@ $(dir_build)/main.bin: $(dir_build)/main.elf $(dir_build)/main.elf: $(objects) $(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)" @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) - @mv emunand.bin reboot.bin $(dir_injector)/injector.cxi $(@D) - @bin2c -o $@ -n emunand $(@D)/emunand.bin -n reboot $(@D)/reboot.bin -n injector $(@D)/injector.cxi + @bin2c -o $@ -n injector $(@D)/injector.cxi $(dir_build)/loader.h: $(dir_loader)/Makefile @$(MAKE) -C $(dir_loader) - @mv $(dir_loader)/loader.bin $(@D) @bin2c -o $@ -n loader $(@D)/loader.bin $(dir_build)/screeninit.h: $(dir_screeninit)/Makefile @$(MAKE) -C $(dir_screeninit) - @mv $(dir_screeninit)/screeninit.bin $(@D) @bin2c -o $@ -n screeninit $(@D)/screeninit.bin $(dir_build)/memory.o: CFLAGS += -O3 diff --git a/injector/Makefile b/injector/Makefile index c33e3d8..d568a73 100755 --- a/injector/Makefile +++ b/injector/Makefile @@ -31,13 +31,13 @@ objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ $(call rwildcard, $(dir_source), *.c)) .PHONY: all -all: $(name).cxi +all: ../$(dir_build)/$(name).cxi .PHONY: clean clean: @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 $< $(dir_build)/$(name).elf: $(objects) diff --git a/loader/Makefile b/loader/Makefile index 56f606c..421d9c9 100644 --- a/loader/Makefile +++ b/loader/Makefile @@ -25,13 +25,13 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ $(call rwildcard, $(dir_source), *.s *.c))) .PHONY: all -all: $(name).bin +all: ../$(dir_build)/$(name).bin .PHONY: clean clean: @rm -rf $(dir_build) -$(name).bin: $(dir_build)/$(name).elf +../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf $(OC) -S -O binary $< $@ $(dir_build)/$(name).elf: $(objects) diff --git a/patches/emunand.s b/patches/emunand.s index 2c11126..a7e6cfa 100644 --- a/patches/emunand.s +++ b/patches/emunand.s @@ -1,6 +1,6 @@ .arm.little -.create "emunand.bin", 0 +.create "build/emunand.bin", 0 .arm nand_sd: ; Original code that still needs to be executed. diff --git a/patches/reboot.s b/patches/reboot.s index cedb4af..e662db5 100644 --- a/patches/reboot.s +++ b/patches/reboot.s @@ -3,7 +3,7 @@ payload_addr equ 0x23F00000 ; Brahma payload address. payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do). -.create "reboot.bin", 0 +.create "build/reboot.bin", 0 .arm ; Interesting registers and locations to keep in mind, set before this code is ran: ; - sp + 0x3A8 - 0x70: FIRM path in exefs. diff --git a/screeninit/Makefile b/screeninit/Makefile index 28ed64b..0096fd8 100755 --- a/screeninit/Makefile +++ b/screeninit/Makefile @@ -25,13 +25,13 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ $(call rwildcard, $(dir_source), *.s *.c))) .PHONY: all -all: $(name).bin +all: ../$(dir_build)/$(name).bin .PHONY: clean clean: @rm -rf $(dir_build) -$(name).bin: $(dir_build)/$(name).elf +../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf $(OC) -S -O binary $< $@ $(dir_build)/$(name).elf: $(objects) diff --git a/source/emunand.c b/source/emunand.c index 25834d8..f64def5 100644 --- a/source/emunand.c +++ b/source/emunand.c @@ -5,8 +5,9 @@ #include "emunand.h" #include "memory.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; @@ -35,11 +36,11 @@ void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND) else { (*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 const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; @@ -48,7 +49,7 @@ u32 getSDMMC(u8 *pos, u32 size) 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 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; } -u32 *getMPU(u8 *pos, u32 size) +static inline u32 *getMPU(u8 *pos, u32 size) { //Look for MPU pattern const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; @@ -65,10 +66,49 @@ u32 *getMPU(u8 *pos, u32 size) 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}; //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]; } \ No newline at end of file diff --git a/source/emunand.h b/source/emunand.h index abe8e4a..c39806e 100644 --- a/source/emunand.h +++ b/source/emunand.h @@ -8,8 +8,5 @@ #define NCSD_MAGIC 0x4453434E -void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND); -u32 getSDMMC(u8 *pos, u32 size); -void getEmuRW(u8 *pos, u32 size, u16 **readOffset, u16 **writeOffset); -u32 *getMPU(u8 *pos, u32 size); -void *getEmuCode(u8 *pos); \ No newline at end of file +void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND); +void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuHeader, u32 branchAdditive); \ No newline at end of file diff --git a/source/firm.c b/source/firm.c index 0d9d9bb..225e1c2 100755 --- a/source/firm.c +++ b/source/firm.c @@ -13,7 +13,7 @@ #include "draw.h" #include "screeninit.h" #include "buttons.h" -#include "../build/patches.h" +#include "../build/injector.h" static firmHeader *const firm = (firmHeader *)0x24000000; static const firmSectionHeader *section; @@ -180,13 +180,13 @@ void main(void) //If we need to boot emuNAND, make sure it exists if(nandType) { - getEmunandSect(&emuOffset, &emuHeader, &nandType); + locateEmuNAND(&emuOffset, &emuHeader, &nandType); if(!nandType) firmSource = 0; } //Same if we're using emuNAND as the FIRM source else if(firmSource) - getEmunandSect(&emuOffset, &emuHeader, &firmSource); + locateEmuNAND(&emuOffset, &emuHeader, &firmSource); if(!bootType) { @@ -224,7 +224,7 @@ void main(void) stopChrono(); } - launchFirm(!firmType, bootType); + launchFirm(firmType, bootType); } 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); //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 - 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 - if(nativeFirmType || a9lhMode == 2) patchReboots(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]; + //Apply firmlaunch patches, not on 9.0 FIRM as it breaks firmlaunchhax + if(nativeFirmType || a9lhMode == 2) patchFirmlaunches(process9Offset, process9Size, process9MemAddr); //Does nothing if svcBackdoor is still there - if(nativeFirmType == 1) reimplementSvcBackdoor(); - - //Replace the FIRM loader with the injector while copying section0 - copySection0AndInjectLoader(); + if(nativeFirmType == 1) reimplementSvcBackdoor((u8 *)firm + section[1].offset, section[1].size); } -static inline void patchEmuNAND(u8 *arm9Section, u8 *process9Offset, u32 process9Size, u32 emuHeader) +static inline void patchLegacyFirm(u32 firmType) { - //Copy emuNAND code - void *emuCodeOffset = getEmuCode(arm9Section); - 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]) + //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader + if(console) { - u32 *freeSpace; - for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++); - - memcpy(freeSpace, svcBackdoor, 40); - - svcTable[0x7B] = 0xFFFF0000 + ((u8 *)freeSpace - (u8 *)exceptionsPage); + arm9Loader((u8 *)firm + section[3].offset, 0); + firm->arm9Entry = (u8 *)0x801301C; } + + 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) @@ -393,87 +343,17 @@ static inline void copySection0AndInjectLoader(void) 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(console) + //If we're booting NATIVE_FIRM, section0 needs to be copied separately to inject 3ds_injector + u32 sectionNum; + if(!firmType) { - //Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader - arm9Loader(arm9Section, 0); - firm->arm9Entry = (u8 *)0x801B01C; + copySection0AndInjectLoader(); + sectionNum = 1; } + 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 for(; sectionNum < 4 && section[sectionNum].size; sectionNum++) memcpy(section[sectionNum].address, (u8 *)firm + section[sectionNum].offset, section[sectionNum].size); diff --git a/source/firm.h b/source/firm.h index a4e567f..3115edc 100644 --- a/source/firm.h +++ b/source/firm.h @@ -28,22 +28,9 @@ typedef struct firmHeader { firmSectionHeader section[4]; } 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 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 patchSafeFirm(void); +static inline void copySection0AndInjectLoader(void); static inline void launchFirm(u32 sectionNum, u32 bootType); \ No newline at end of file diff --git a/source/patches.c b/source/patches.c index f7bdfed..6d7af9a 100644 --- a/source/patches.c +++ b/source/patches.c @@ -4,33 +4,8 @@ #include "patches.h" #include "memory.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 -**************************************************/ +#include "config.h" +#include "../build/rebootpatch.h" 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; } -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 const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; - *off = (u16 *)memsearch(pos, pattern, size, 4); - *off2 = (u16 *)(memsearch(pos, pattern2, size, 4) - 1); + u16 *off = (u16 *)memsearch(pos, pattern, size, 4), + *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 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; //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 - u8 *const off = memsearch(pos, "exe:", size, 4); + u8 *const off1 = memsearch(pos, "exe:", size, 4); 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 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) @@ -98,17 +168,4 @@ u32 getLoader(u8 *pos, u32 *loaderSize) *loaderSize = size; 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; } \ No newline at end of file diff --git a/source/patches.h b/source/patches.h index 3caf5f7..c2e51be 100644 --- a/source/patches.h +++ b/source/patches.h @@ -6,23 +6,20 @@ #include "types.h" -/************************************************** -* Patches -**************************************************/ -const u32 mpuPatch[3]; -const u16 nandRedir[2], - sigPatch[2], - writeBlock[2], - writeBlockSafe[2]; -const u8 svcBackdoor[40]; +typedef struct patchData { + u32 offset[2]; + union { + u8 type0[8]; + u16 type1; + } patch; + u32 type; +} patchData; -/************************************************** -* Functions -**************************************************/ u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr); -void getSigChecks(u8 *pos, u32 size, u16 **off, u16 **off2); -void *getReboot(u8 *pos, u32 size, u32 process9MemAddr, u32 *fOpenOffset); -u16 *getFirmWrite(u8 *pos, u32 size); -u16 *getFirmWriteSafe(u8 *pos, u32 size); -u32 getLoader(u8 *pos, u32 *loaderSize); -u32 *getSvcAndExceptions(u8 *pos, u32 size, u32 **exceptionsPage); \ No newline at end of file +void patchSignatureChecks(u8 *pos, u32 size); +void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr); +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); +u32 getLoader(u8 *pos, u32 *loaderSize); \ No newline at end of file