Cleanup, re-enabled module patch on N3DS on 8.1, 9.0 and >= 11.0 FIRMs

This commit is contained in:
Aurora 2016-09-02 22:43:15 +02:00
parent b16539408b
commit cce4a6d07f
6 changed files with 59 additions and 94 deletions

View File

@ -42,10 +42,6 @@
; Save the value of all registers ; Save the value of all registers
push {r0-r12} push {r0-r12}
; Clear all the caches, just to be safe
mcr p15, 0, r6, c7, c14, 0
mcr p15, 0, r6, c7, c5, 0
ldr r0, [r0, #(0x80 - 0x7C)] ; Load the .text address ldr r0, [r0, #(0x80 - 0x7C)] ; Load the .text address
ldr r7, [r4] ldr r7, [r4]
ldr r2, [r7, #0x18] ; Load the size of the .text ldr r2, [r7, #0x18] ; Load the size of the .text
@ -115,10 +111,6 @@
out: out:
pop {r0-r12} ; Restore the registers we used pop {r0-r12} ; Restore the registers we used
; Clear all the caches again, just to be safe
mcr p15, 0, r6, c7, c14, 0
mcr p15, 0, r6, c7, c5, 0
ldr r0, [r4] ; Execute the instruction we overwrote in our detour ldr r0, [r4] ; Execute the instruction we overwrote in our detour
bx lr ; Jump back to whoever called us bx lr ; Jump back to whoever called us

View File

@ -84,7 +84,7 @@ void configMenu(bool oldPinStatus)
"( ) Show GBA boot screen in patched AGB_FIRM", "( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Display splash screen before payloads", "( ) Display splash screen before payloads",
"( ) Use a PIN", "( ) Use a PIN",
"( ) Disable access checks (modules: O3DS only)" }; "( ) Disable access checks" };
struct multiOption { struct multiOption {
int posXs[4]; int posXs[4];

View File

@ -350,19 +350,23 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
//Kernel9/Process9 debugging //Kernel9/Process9 debugging
patchArm9ExceptionHandlersInstall(arm9Section, section[2].size); patchArm9ExceptionHandlersInstall(arm9Section, section[2].size);
patchSvcBreak9(arm9Section, section[2].size, (u32)section[2].address); patchSvcBreak9(arm9Section, section[2].size, (u32)section[2].address);
patchKernel9Panic(arm9Section, section[2].size, NATIVE_FIRM); patchKernel9Panic(arm9Section, section[2].size);
//Stub svcBreak11 with "bkpt 65535" //Stub svcBreak11 with "bkpt 65535"
patchSvcBreak11(arm11Section1, arm11SvcTable); patchSvcBreak11(arm11Section1, arm11SvcTable);
//Stub kernel11panic with "bkpt 65534" //Stub kernel11Panic with "bkpt 65534"
patchKernel11Panic(arm11Section1, section[1].size); patchKernel11Panic(arm11Section1, section[1].size);
} }
if(CONFIG(9)) if(CONFIG(9))
{ {
patchArm11SvcAccessChecks(arm11SvcHandler); patchArm11SvcAccessChecks(arm11SvcHandler);
if(!isN3DS) patchK11ModuleChecks(arm11Section1, section[1].size, &freeK11Space);
//FIRMs between 9.3 and 10.4 don't have enough space on N3DS
if(!isN3DS || firmVersion <= 4 || firmVersion >= 0x21)
patchK11ModuleChecks(arm11Section1, section[1].size, &freeK11Space);
patchP9AccessChecks(process9Offset, process9Size); patchP9AccessChecks(process9Offset, process9Size);
} }
} }
@ -381,14 +385,6 @@ static inline void patchLegacyFirm(FirmwareType firmType)
//Apply UNITINFO patch //Apply UNITINFO patch
if(DEV_OPTIONS == 1) patchUnitInfoValueSet(arm9Section, section[3].size); if(DEV_OPTIONS == 1) patchUnitInfoValueSet(arm9Section, section[3].size);
if(DEV_OPTIONS != 2)
{
//Kernel9/Process9 debugging
patchArm9ExceptionHandlersInstall(arm9Section, section[3].size);
patchSvcBreak9(arm9Section, section[3].size, (u32)section[3].address);
patchKernel9Panic(arm9Section, section[3].size, firmType);
}
applyLegacyFirmPatches((u8 *)firm, firmType); applyLegacyFirmPatches((u8 *)firm, firmType);
if(firmType == TWL_FIRM && CONFIG(5)) patchTwlBg((u8 *)firm + section[1].offset); if(firmType == TWL_FIRM && CONFIG(5)) patchTwlBg((u8 *)firm + section[1].offset);

View File

@ -237,33 +237,11 @@ void patchTwlBg(u8 *pos)
src2[1] = 0xE800 | ((((u32)dst - (u32)src2 - 4) & 0xFFF) >> 1); src2[1] = 0xE800 | ((((u32)dst - (u32)src2 - 4) & 0xFFF) >> 1);
} }
u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset)
{
//This function has to succeed. Crash if it doesn't (we'll get an exception dump of it anyways)
const u8 callExceptionDispatcherPattern[] = {0x0F, 0x00, 0xBD, 0xE8, 0x13, 0x00, 0x02, 0xF1};
const u8 getTitleIDFromCodeSetPattern[] = {0xDC, 0x05, 0xC0, 0xE1, 0x20, 0x04, 0xA0, 0xE1};
u32 *loadCodeSet = (u32 *)memsearch(pos, getTitleIDFromCodeSetPattern, size, 8);
while((*loadCodeSet >> 20) != 0xE59 || ((*loadCodeSet >> 12) & 0xF) != 0) //ldr r0, [rX, #offset]
loadCodeSet--;
*codeSetOffset = *loadCodeSet & 0xFFF;
return *((u32 *)memsearch(pos, callExceptionDispatcherPattern, size, 8) + 3);
}
void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
{ {
const u8 pattern[] = { const u8 pattern[] = {0x03, 0xA0, 0xE3, 0x18};
0x18, 0x10, 0x80, 0xE5,
0x10, 0x10, 0x80, 0xE5,
0x20, 0x10, 0x80, 0xE5,
0x28, 0x10, 0x80, 0xE5,
}; //i.e when it stores ldr pc, [pc, #-4]
u32* off = (u32 *)(memsearch(pos, pattern, size, sizeof(pattern))); u32* off = (u32 *)(memsearch(pos, pattern, size, 4) + 0x13);
if(off == NULL) return;
off += sizeof(pattern)/4;
for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40 for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40
{ {
@ -286,13 +264,29 @@ void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
} }
} }
u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset)
{
//This function has to succeed. Crash if it doesn't (we'll get an exception dump of it anyways)
const u8 pattern[] = {0xE3, 0xDC, 0x05, 0xC0}, //Get TitleID from CodeSet
pattern2[] = {0xE1, 0x0F, 0x00, 0xBD}; //Call exception dispatcher
u32 *loadCodeSet = (u32 *)(memsearch(pos, pattern, size, 4) - 0xB);
*codeSetOffset = *loadCodeSet & 0xFFF;
return *(u32 *)(memsearch(pos, pattern2, size, 4) + 0xD);
}
void patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) void patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address)
{ {
//Stub svcBreak with "bkpt 65535" so we can debug the panic. /* Stub svcBreak with "bkpt 65535" so we can debug the panic.
//Thanks @yellows8 and others for mentioning this idea on #3dsdev. Thanks @yellows8 and others for mentioning this idea on #3dsdev */
const u8 svcHandlerPattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr
u32 *arm9SvcTable = (u32 *)memsearch(pos, svcHandlerPattern, size, 4); //Look for the svc handler
const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr
u32 *arm9SvcTable = (u32 *)memsearch(pos, pattern, size, 4);
while(*arm9SvcTable) arm9SvcTable++; //Look for SVC0 (NULL) while(*arm9SvcTable) arm9SvcTable++; //Look for SVC0 (NULL)
u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address); u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address);
@ -306,75 +300,58 @@ void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable)
*addr = 0xE12FFF7F; *addr = 0xE12FFF7F;
} }
void patchKernel9Panic(u8 *pos, u32 size, FirmwareType firmType) void patchKernel9Panic(u8 *pos, u32 size)
{ {
if(firmType == TWL_FIRM || firmType == AGB_FIRM) const u8 pattern[] = {0xDF, 0xFF, 0xEA, 0x04};
{
u8 *off = pos + (isN3DS ? 0x723C : 0x69A8);
*(u16 *)off = 0x4778; //bx pc
*(u16 *)(off + 2) = 0x46C0; //nop
*(u32 *)(off + 4) = 0xE12FFF7E; //bkpt 65534
}
else
{
const u8 pattern[] = {0x00, 0x20, 0xA0, 0xE3, 0x02, 0x30, 0xA0, 0xE1, 0x02, 0x10, 0xA0, 0xE1, 0x05, 0x00, 0xA0, 0xE3};
u32 *off = (u32 *)memsearch(pos, pattern, size, 16); u32 *off = (u32 *)(memsearch(pos, pattern, size, 4) - 0x11);
*off = 0xE12FFF7E; *off = 0xE12FFF7E;
}
} }
void patchKernel11Panic(u8 *pos, u32 size) void patchKernel11Panic(u8 *pos, u32 size)
{ {
const u8 pattern[] = {0x02, 0x0B, 0x44, 0xE2, 0x00, 0x10, 0x90, 0xE5}; const u8 pattern[] = {0x02, 0x0B, 0x44, 0xE2};
u32 *off = (u32 *)memsearch(pos, pattern, size, 8); u32 *off = (u32 *)memsearch(pos, pattern, size, 4);
*off = 0xE12FFF7E; *off = 0xE12FFF7E;
} }
void patchP9AccessChecks(u8 *pos, u32 size)
{
const u8 pattern[] = {0xE0, 0x00, 0x40, 0x39};
u16 *off = (u16 *)memsearch(pos, pattern, size, 4) - 7;
off[0] = 0x2001; //mov r0, #1
off[1] = 0x4770; //bx lr
}
void patchArm11SvcAccessChecks(u32 *arm11SvcHandler) void patchArm11SvcAccessChecks(u32 *arm11SvcHandler)
{ {
while(*arm11SvcHandler != 0xE11A0E1B) arm11SvcHandler++; //TST R10, R11,LSL LR while(*arm11SvcHandler != 0xE11A0E1B) arm11SvcHandler++; //TST R10, R11,LSL LR
*arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1 *arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1
} }
//It's mainly Subv's code here: //It's mainly Subv's code here
void patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space) void patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space)
{ {
//We have to detour a function in the ARM11 kernel because builtin modules /* We have to detour a function in the ARM11 kernel because builtin modules
//are compressed in memory and are only decompressed at runtime. are compressed in memory and are only decompressed at runtime */
//Find the code that decompresses the .code section of the builtin modules and detour it with a jump to our code
const u8 pattern[] = { 0x00, 0x00, 0x94, 0xE5, 0x18, 0x10, 0x90, 0xE5, 0x28, 0x20,
0x90, 0xE5, 0x48, 0x00, 0x9D, 0xE5 };
u32 *off = (u32 *)memsearch(pos, pattern, size, 16);
//We couldn't find the code that decompresses the module
if(off == NULL) return;
//Inject our code into the free space //Inject our code into the free space
memcpy(*freeK11Space, k11modules, k11modules_size); memcpy(*freeK11Space, k11modules, k11modules_size);
//Inject a jump instruction to our code at the offset we found //Look for the code that decompresses the .code section of the builtin modules
//Construct a jump (BL) instruction to our code const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D};
u32 offset = ((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF;
*off = offset | (1 << 24) | (0x5 << 25) | (0xE << 28); u32 *off = (u32 *)(memsearch(pos, pattern, size, 4) - 0xB);
//Inject a jump (BL) instruction to our code at the offset we found
*off = 0xEB000000 | (((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF);
(*freeK11Space) += k11modules_size; (*freeK11Space) += k11modules_size;
} }
void patchP9AccessChecks(u8 *pos, u32 size)
{
const u8 pattern[] = {0xE0, 0x00, 0x40, 0x39, 0x08, 0x58};
u16 *off = (u16 *)memsearch(pos, pattern, size, 6) - 7;
off[0] = 0x2001; //mov r0, #1
off[1] = 0x4770; //bx lr
}
void patchUnitInfoValueSet(u8 *pos, u32 size) void patchUnitInfoValueSet(u8 *pos, u32 size)
{ {
//Look for UNITINFO value being set during kernel sync //Look for UNITINFO value being set during kernel sync

View File

@ -61,13 +61,13 @@ void implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u8 **freeK11Space);
void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType); void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
void patchTwlBg(u8 *pos); void patchTwlBg(u8 *pos);
u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset);
void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size); void patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);
u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset);
void patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address); void patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address);
void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable); void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable);
void patchKernel9Panic(u8 *pos, u32 size, FirmwareType firmType); void patchKernel9Panic(u8 *pos, u32 size);
void patchKernel11Panic(u8 *pos, u32 size); void patchKernel11Panic(u8 *pos, u32 size);
void patchP9AccessChecks(u8 *pos, u32 size);
void patchArm11SvcAccessChecks(u32 *arm11SvcHandler); void patchArm11SvcAccessChecks(u32 *arm11SvcHandler);
void patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space); void patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space);
void patchP9AccessChecks(u8 *pos, u32 size);
void patchUnitInfoValueSet(u8 *pos, u32 size); void patchUnitInfoValueSet(u8 *pos, u32 size);