diff --git a/arm9/linker.ld b/arm9/linker.ld index aa5ac8288..ee0f66ced 100644 --- a/arm9/linker.ld +++ b/arm9/linker.ld @@ -46,6 +46,7 @@ SECTIONS chainloader.o(.text*) i2c.o(.text*) arm9_exception_handlers.o(.text*) + *(.large_patch.readFileSHA256Vtab11) KEEP (*(.emunand_patch)) *(.arm9_exception_handlers.rodata*) diff --git a/arm9/source/firm.c b/arm9/source/firm.c index 60044e454..fe18026f3 100755 --- a/arm9/source/firm.c +++ b/arm9/source/firm.c @@ -587,6 +587,9 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora ret += patchP9AccessChecks(process9Offset, process9Size); + //Patch stubbed vtable function 11 of an FSPXI:ReadFileSHA256 auxiliary object + ret += patchReadFileSHA256Vtab11(process9Offset, process9Size, process9MemAddr); + mergeSection0(NATIVE_FIRM, firmVersion, loadFromStorage); firm->section[0].size = 0; diff --git a/arm9/source/large_patches.h b/arm9/source/large_patches.h index 6c99243b4..0af83ac04 100644 --- a/arm9/source/large_patches.h +++ b/arm9/source/large_patches.h @@ -36,3 +36,7 @@ extern const u8 rebootPatch[]; extern const u32 rebootPatchSize; extern u32 rebootPatchFopenPtr; extern u16 rebootPatchFileName[80+1]; + +extern const u8 readFileSHA256Vtab11Patch[]; +extern const u32 readFileSHA256Vtab11PatchSize; +extern u32 readFileSHA256Vtab11PatchCtorPtr, readFileSHA256Vtab11PatchInitPtr, readFileSHA256Vtab11PatchProcessPtr; \ No newline at end of file diff --git a/arm9/source/large_patches.s b/arm9/source/large_patches.s index c66f63b5f..74f1ae07b 100644 --- a/arm9/source/large_patches.s +++ b/arm9/source/large_patches.s @@ -225,3 +225,61 @@ _rebootPatchEnd: .global rebootPatchSize rebootPatchSize: .word _rebootPatchEnd - rebootPatch + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.section .large_patch.readFileSHA256Vtab11, "aw", %progbits +.arm +.align 4 + +.global readFileSHA256Vtab11Patch +readFileSHA256Vtab11Patch: //Result Write(this, u32 off, u8 *data, u32 size) + push {r0-r4, lr} + + @ Allocate memory for DataChainProcessor struct + sub sp, #0x14 + push {sp} + + @ DataChainProcessor::DataChainProcessor(&proc); + ldr r0, [sp] + ldr r4, readFileSHA256Vtab11PatchCtorPtr + blx r4 + + @ DataChainProcessor::Init(&proc, data, size); + ldr r0, [sp] + ldr r1, [sp, #0x20] + ldr r2, [sp, #0x24] + ldr r4, readFileSHA256Vtab11PatchInitPtr + blx r4 + + @ DataChainProcessor::Process(&proc, this, off, 0, size); + ldr r0, [sp] + + ldr r1, [sp, #0x24] + str r1, [sp] @ size argument + + ldr r1, [sp, #0x18] + ldr r2, [sp, #0x1c] + mov r3, #0 + ldr r4, readFileSHA256Vtab11PatchProcessPtr + blx r4 + + add sp, #0x18 + pop {r0-r4, pc} + +.global readFileSHA256Vtab11PatchCtorPtr +.global readFileSHA256Vtab11PatchInitPtr +.global readFileSHA256Vtab11PatchProcessPtr + +readFileSHA256Vtab11PatchCtorPtr: .word 0 @ Pointer to DataChainProcessor::DataChainProcessor +readFileSHA256Vtab11PatchInitPtr: .word 0 @ Pointer to DataChainProcessor::Init +readFileSHA256Vtab11PatchProcessPtr: .word 0 @ Pointer to DataChainProcessor::ProcessBytes + +.pool +.balign 4 + +_readFileSHA256Vtab11PatchEnd: + +.global readFileSHA256Vtab11PatchSize +readFileSHA256Vtab11PatchSize: + .word _readFileSHA256Vtab11PatchEnd - readFileSHA256Vtab11Patch \ No newline at end of file diff --git a/arm9/source/patches.c b/arm9/source/patches.c index f1d7589ff..e97605d78 100644 --- a/arm9/source/patches.c +++ b/arm9/source/patches.c @@ -847,3 +847,76 @@ u32 patchLgyK11(u8 *section1, u32 section1Size, u8 *section2, u32 section2Size) return 0; } + +static bool getVtableAddress(u8 *pos, u32 size, const u8 *pattern, u32 patternSize, s32 patternOff, u32 memAddr, u32 *vtableAddr) +{ + u8 *tmp = memsearch(pos, pattern, size, patternSize); + + if(tmp == NULL) return false; + + u16 *instrPtr = (u16 *)(tmp + patternOff); //ldr rX, [PTR_TO_VTABLE] + if((*instrPtr & 0xf800) != 0x4800) return false; //Check the instruction opcode + + *vtableAddr = *(u32 *)(((u32)instrPtr + 4 + 4*(*instrPtr & 0xff)) & ~0x3); + + if(*vtableAddr < memAddr || *vtableAddr >= memAddr + size) return false; + + return true; +} + +u32 patchReadFileSHA256Vtab11(u8 *pos, u32 size, u32 process9MemAddr) +{ + static const u8 ncchVtableRefPattern[] = {0x77, 0x46, 0x06, 0x74, 0x47, 0x74}; + static const u8 shaVtable1RefPattern[] = {0x00, 0x1f, 0x01, 0x60, 0x20, 0x30}; + static const u8 shaVtable2RefPattern[] = {0x00, 0x1f, 0x01, 0x60, 0x01, 0x00, 0x20, 0x31}; + + u32 ncchVtableAddr; + if(!getVtableAddress(pos, size, ncchVtableRefPattern, sizeof(ncchVtableRefPattern), sizeof(ncchVtableRefPattern), process9MemAddr, &ncchVtableAddr)) return 1; + + u32 shaVtable1Addr; + if(!getVtableAddress(pos, size, shaVtable1RefPattern, sizeof(shaVtable1RefPattern), -2, process9MemAddr, &shaVtable1Addr)) return 1; + + u32 shaVtable2Addr; + if(!getVtableAddress(pos, size, shaVtable2RefPattern, sizeof(shaVtable2RefPattern), -2, process9MemAddr, &shaVtable2Addr)) return 1; + + u32 *ncchVtable11Ptr = (u32 *)(pos + (ncchVtableAddr - process9MemAddr)) + 11, + *shaVtable1_11Ptr = (u32 *)(pos + (shaVtable1Addr - process9MemAddr)) + 11, + *shaVtable2_11Ptr = (u32 *)(pos + (shaVtable2Addr - process9MemAddr)) + 11; + + if((*ncchVtable11Ptr & 0x1) == 0 || (*shaVtable1_11Ptr & 0x1) == 0 || (*shaVtable2_11Ptr & 0x1) == 0) return 1; //Must be Thumb + + //Find needed function addresses by inspecting all bl branch targets + u16 *ncchWriteFnc = (u16 *)(pos + ((*ncchVtable11Ptr & ~0x1) - process9MemAddr)); + if(*(u32 *)ncchWriteFnc != 0x0005b5f0) return 1; //Check if we got the right function + + readFileSHA256Vtab11PatchCtorPtr = readFileSHA256Vtab11PatchInitPtr = readFileSHA256Vtab11PatchProcessPtr = 0; + + for(; ((*ncchWriteFnc) & 0xff00) != 0xbd00; ncchWriteFnc++) { //Stop whe encountering a pop {..., pc} + if((ncchWriteFnc[0] & 0xf800) != 0xf000 || (ncchWriteFnc[1] & 0xf800) != 0xf800) continue; //Check the instruction opcode + + s32 callOff = ((ncchWriteFnc[0] & 0x07ff) << 11) | (ncchWriteFnc[1] & 0x07ff); + callOff = (callOff & 0x1fffff) - (callOff & 0x200000); + + u32 callTargetAddr = process9MemAddr + ((u8 *)ncchWriteFnc - pos) + 4 + 2*callOff; + + if(callTargetAddr < process9MemAddr || callTargetAddr >= process9MemAddr + size) return false; + + switch(*(u32 *)(pos + (callTargetAddr - process9MemAddr))) { + case 0x60422201: //DataChainProcessor::DataChainProcessor + readFileSHA256Vtab11PatchCtorPtr = callTargetAddr | 0x1; + break; + case 0x000db538: //DataChainProcessor::Init + readFileSHA256Vtab11PatchInitPtr = callTargetAddr | 0x1; + break; + case 0x0006b5f0: //DataChainProcessor::ProcessBytes + readFileSHA256Vtab11PatchProcessPtr = callTargetAddr | 0x1; + break; + } + } + + if(readFileSHA256Vtab11PatchCtorPtr == 0 || readFileSHA256Vtab11PatchInitPtr == 0 || readFileSHA256Vtab11PatchProcessPtr == 0) return 1; + + *shaVtable1_11Ptr = *shaVtable2_11Ptr = (u32) &readFileSHA256Vtab11Patch; //The patched vtable11 function is in ITCM, so we don't have to copy it somewhere else + + return 0; +} \ No newline at end of file diff --git a/arm9/source/patches.h b/arm9/source/patches.h index b77d092a2..57545f657 100644 --- a/arm9/source/patches.h +++ b/arm9/source/patches.h @@ -68,3 +68,4 @@ u32 patchTwlShaHashChecks(u8 *pos, u32 size); u32 patchAgbBootSplash(u8 *pos, u32 size); void patchTwlBg(u8 *pos, u32 size); // silently fails u32 patchLgyK11(u8 *section1, u32 section1Size, u8 *section2, u32 section2Size); +u32 patchReadFileSHA256Vtab11(u8 *pos, u32 size, u32 process9MemAddr);