Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix FSPXI:ReadFileSHA256 error when reading exactly one block from NoCrypto gamecard NCCH ExeFS files #1829

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arm9/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -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*)
Expand Down
3 changes: 3 additions & 0 deletions arm9/source/firm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 4 additions & 0 deletions arm9/source/large_patches.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
58 changes: 58 additions & 0 deletions arm9/source/large_patches.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
73 changes: 73 additions & 0 deletions arm9/source/patches.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
1 change: 1 addition & 0 deletions arm9/source/patches.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);