Merge branch 'master' into developer

Conflicts:
	Makefile
	source/firm.c
	source/patches.c
	source/patches.h
This commit is contained in:
TuxSH 2016-05-25 22:28:50 +02:00
commit 2fab0be5e8
15 changed files with 302 additions and 284 deletions

View File

@ -12,7 +12,7 @@ LD := arm-none-eabi-ld
OC := arm-none-eabi-objcopy
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_patches := patches
@ -34,8 +34,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)/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
all: launcher a9lh ninjhax
@ -86,17 +85,23 @@ $(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)/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
@$(MAKE) -C $(dir_screeninit)
@mv $(dir_screeninit)/screeninit.bin $(@D)
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
$(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)
@mkdir -p "$(@D)"

View File

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

View File

@ -472,6 +472,48 @@ void patchCode(u64 progId, u8 *code, u32 size)
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:
if(CONFIG(4))

View File

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

View File

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

View File

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

View File

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

View File

@ -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,19 @@ 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 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
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
@ -48,27 +57,58 @@ 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 patchNANDRW(u8 *pos, u32 size, u32 branchOffset)
{
const u16 nandRedir[2] = {0x4C00, 0x47A0};
//Look for read/write code
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
*readOffset = (u16 *)memsearch(pos, pattern, size, 4) - 3;
*writeOffset = (u16 *)memsearch((u8 *)(*readOffset + 5), pattern, 0x100, 4) - 3;
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, 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
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
return memsearch(pos + 0x13500, pattern, 0x1000, 6) + 0x455;
//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
u32 branchOffset = (u32)emuCodeOffset - branchAdditive;
patchNANDRW(process9Offset, process9Size, branchOffset);
//Set MPU for emu code region
patchMPU(arm9Section, arm9SectionSize);
}

View File

@ -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);
void locateEmuNAND(u32 *off, u32 *head, u32 *emuNAND);
void patchEmuNAND(u8 *arm9Section, u32 arm9SectionSize, u8 *process9Offset, u32 process9Size, u32 emuOffset, u32 emuHeader, u32 branchAdditive);

View File

@ -9,6 +9,7 @@
#include "diskio.h" /* FatFs lower layer API */
#include "sdmmc/sdmmc.h"
#include "../crypto.h"
/* Definitions of physical drive number for each media */
#define SDCARD 0

View File

@ -1,5 +1,4 @@
#pragma once
#include <stdbool.h>
#include "../../types.h"
#include "../../crypto.h"
#include "../../types.h"

View File

@ -14,7 +14,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;
@ -222,13 +222,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)
{
@ -268,7 +268,7 @@ void main(void)
stopChrono();
}
launchFirm(!firmType, bootType);
launchFirm(firmType, bootType);
}
static inline void loadFirm(u32 firmType, u32 externalFirm)
@ -346,24 +346,27 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
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
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
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((u8 *)firm + section[1].offset, section[1].size);
if(nativeFirmType == 1) reimplementSvcBackdoor();
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
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
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)
@ -462,87 +418,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);

View File

@ -28,23 +28,10 @@ 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 patchKernelFCRAMAndVRAMMappingPermissions(void);
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);

View File

@ -4,36 +4,11 @@
#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};
#include "config.h"
#include "../build/rebootpatch.h"
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 *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;
}
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 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
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;
//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];
}
u8 *getUnitInfoValueSet(u8 *pos, u32 size)
@ -93,6 +98,80 @@ u8 *getUnitInfoValueSet(u8 *pos, u32 size)
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)
{
u8 *off = pos;
@ -108,17 +187,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;
}

View File

@ -6,25 +6,21 @@
#include "types.h"
/**************************************************
* Patches
**************************************************/
const u32 mpuPatch[3];
const u16 nandRedir[2],
sigPatch[2],
writeBlock[2],
writeBlockSafe[2];
typedef struct patchData {
u32 offset[2];
union {
u8 type0[8];
u16 type1;
} patch;
u32 type;
} patchData;
const u8 unitInfoPatch;
const u8 svcBackdoor[40];
/**************************************************
* 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);
u8 *getUnitInfoValueSet(u8 *pos, u32 size);
u32 getLoader(u8 *pos, u32 *loaderSize);
u32 *getSvcAndExceptions(u8 *pos, u32 size, u32 **exceptionsPage);
void patchSignatureChecks(u8 *pos, u32 size);
void patchTitleInstallMinVersionCheck(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);
u8 *getUnitInfoValueSet(u8 *pos, u32 size);