1
0
Fork 0

Codehandler can now be hooked almost anywhere

This commit is contained in:
JoshuaMKW 2020-08-25 04:28:22 -05:00
parent e01ae32047
commit 01578f3874
6 changed files with 104 additions and 17 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -251,8 +251,20 @@ otherwise it returns None'''
return True
def insert_branch(self, to, _from, lk=0):
tools.write_uint32(self, (to - _from) & 0x3FFFFFF | 0x48000000 | lk)
def insert_branch(self, to: int, _from: int, lk=0):
self.seek(_from)
tools.write_uint32(self, (to - _from) & 0x3FFFFFD | 0x48000000 | lk)
def extract_branch_addr(self, bAddr: int):
self.seek(bAddr)
ppc = tools.read_uint32(self)
if (ppc & 0x2000000):
offset = (ppc & 0x3FFFFFD) - 0x4000000
else:
offset = ppc & 0x3FFFFFD
return bAddr + offset
if __name__ == "__main__":
# Example usage (reading some enemy info from the Pikmin 2 demo from US demo disc 17)

View file

@ -265,6 +265,42 @@ class CodeHandler:
except:
break
def find_variable_data(self):
self._rawData.seek(0)
sample = self._rawData.read(4)
if sample == b'\x00\xDE\xDE\xDE':
return self._rawData.tell() - 4
while sample:
if sample == b'\x00\xDE\xDE\xDE':
return self._rawData.tell() - 4
sample = self._rawData.read(4)
return None
def set_hook_instruction(self, dolFile: DolFile, address: int, varOffset: int, lk=0):
self._rawData.seek(varOffset)
dolFile.seek(address)
ppc = tools.read_uint32(dolFile)
if (((ppc >> 24) & 0xFF) > 0x47 and ((ppc >> 24) & 0xFF) < 0x4C):
to = dolFile.extract_branch_addr(address)
print(f'{to:X}, {self.initAddress:X}, {varOffset:X}, {address:X}')
tools.write_uint32(self._rawData, (to - (self.initAddress + varOffset)) & 0x3FFFFFD | 0x48000000 | lk)
else:
tools.write_uint32(self._rawData, ppc)
def set_variables(self, dolFile: DolFile):
varOffset = self.find_variable_data()
if varOffset is None:
raise RuntimeError(tools.color_text("Variable codehandler data not found", defaultColor=tools.TREDLIT))
self.set_hook_instruction(dolFile, self.hookAddress, varOffset, 0)
self._rawData.seek(varOffset + 4)
tools.write_uint32(self._rawData, ((self.hookAddress + 4) - (self.initAddress + (varOffset + 4))) & 0x3FFFFFD | 0x48000000 | 0)
class KernelLoader:
def __init__(self, f):
@ -516,6 +552,7 @@ class KernelLoader:
if self.codeLocation == 'LEGACY':
codeHandler.allocation = 0x80003000 - (codeHandler.initAddress + codeHandler.handlerLength)
codeHandler.set_variables(dolFile)
hooked = determine_codehook(dolFile, codeHandler, True)
status = self.patch_legacy(codeHandler, dolFile)
legacy = True
@ -601,7 +638,7 @@ def assert_code_hook(dolFile: DolFile, codeHandler: CodeHandler):
elif codeHandler.hookType == 'PAD':
result = sample.find(codeHandler.gcnPADHook)
else:
raise NotImplementedError(f'Unsupported hook type specified ({codeHandler.hookType})')
raise NotImplementedError(tools.color_text(f'Unsupported hook type specified ({codeHandler.hookType})', defaultColor=tools.TREDLIT))
if result >= 0:
dolFile.seek(address, 0)
@ -614,7 +651,7 @@ def assert_code_hook(dolFile: DolFile, codeHandler: CodeHandler):
elif codeHandler.hookType == 'PAD':
result = sample.find(codeHandler.wiiPADHook)
else:
raise NotImplementedError(f'Unsupported hook type specified ({codeHandler.hookType})')
raise NotImplementedError(tools.color_text(f'Unsupported hook type specified ({codeHandler.hookType})', defaultColor=tools.TREDLIT))
if result >= 0:
dolFile.seek(address, 0)
@ -634,4 +671,10 @@ def assert_code_hook(dolFile: DolFile, codeHandler: CodeHandler):
def insert_code_hook(dolFile: DolFile, codeHandler: CodeHandler, address: int):
dolFile.seek(address)
ppc = tools.read_uint32(dolFile)
if ((ppc >> 24) & 0xFF) > 0x3F and ((ppc >> 24) & 0xFF) < 0x48:
raise NotImplementedError(tools.color_text("Hooking the codehandler to a conditional non spr branch is unsupported", defaultColor=tools.TREDLIT))
dolFile.seek(-4, 1)
dolFile.insert_branch(codeHandler.startAddress, address, lk=0)

View file

@ -21,6 +21,8 @@
#define CODEHANDLER 0x800018A8
#define GCT_MAGIC 0x00D0C0DE
#define __start call(0x4948494C)
using u32 = unsigned int;
using u16 = unsigned short;
using u8 = unsigned char;
@ -161,6 +163,15 @@ Info gpModInfo = {
0x43525054,
};
inline u32 extractBranchAddr(u32* bAddr) {
s32 offset;
if (*bAddr & 0x2000000)
offset = (*bAddr & 0x3FFFFFD) - 0x4000000;
else
offset = *bAddr & 0x3FFFFFD;
return (u32)bAddr + offset;
}
namespace Memory {
static void memcpy(u8* to, u8* from, s32 size)
@ -229,10 +240,10 @@ namespace Memory {
}
template <typename T>
static T* single(T* start, T* end, T hookData)
static T* single(T* start, T* end, T match)
{
for (u32 i = 0; &start[i] < end; ++i) {
if (start[i] == hookData) {
if (start[i] == match) {
return &start[i];
}
}
@ -285,7 +296,7 @@ namespace Memory {
inline void xorCrypt(u32* dest, u32* buffer, u32 size)
{
u32 key = this->getKey();
auto key = this->getKey();
for (u32 i = 0; i < size; ++i) {
dest[i] = buffer[i] ^ key;
@ -300,7 +311,7 @@ namespace Memory {
Memory::Crypt gpCryptor = { 0x43595054 };
static bool initMods()
static void initMods()
{
sDisc.setHeap(gpModInfo.allocsize); /*Reallocate the internal heap*/
@ -309,9 +320,6 @@ static bool initMods()
codelistPointer->mUpperBase = (((u32)sDisc.sMetaData.mOSArenaHi + gpModInfo.handlerSize) >> 16) & 0xFFFF;
codelistPointer->mLowerOffset = ((u32)sDisc.sMetaData.mOSArenaHi + gpModInfo.handlerSize) & 0xFFFF;
/*Update the cache, so that the instructions fully update*/
Memory::Cache::flushAddr(&codelistPointer->mBaseASM);
/*Copy codelist to the new allocation*/
if (gpModInfo.crypted) {
Memory::memcpy(sDisc.sMetaData.mOSArenaHi, (u8*)&gpModInfo + sizeof(Info) + 4, gpModInfo.handlerSize);
@ -321,16 +329,40 @@ static bool initMods()
Memory::memcpy(sDisc.sMetaData.mOSArenaHi, (u8*)&gpModInfo + sizeof(Info) + 4, gpModInfo.handlerSize + gpModInfo.codeSize);
}
Memory::Direct::branch((void*)gpModInfo.codehandlerHook, (void*)((u32)sDisc.sMetaData.mOSArenaHi + 0xA8), false);
/*Get codehandler hook resources*/
auto fillInField = Memory::Search::single<u32>((u32*)sDisc.sMetaData.mOSArenaHi, (u32*)(sDisc.sMetaData.mOSArenaHi + 0x600), 0x00DEDEDE);
auto returnAddress = extractBranchAddr((u32*)gpModInfo.codehandlerHook);
auto ppc = *gpModInfo.codehandlerHook;
/*Write hook branch*/
Memory::Direct::branch((void*)gpModInfo.codehandlerHook, (void*)((u32)sDisc.sMetaData.mOSArenaHi + 0xA8), false); //entryhook
/*Temporary nop*/
*fillInField = 0x60000000;
/*Flush the cache so that the instructions update*/
Memory::Cache::flushRange((u8*)sDisc.sMetaData.mOSArenaHi, gpModInfo.handlerSize + gpModInfo.codeSize);
return true;
/*Call the codehandler*/
call((void*)((u32)(sDisc.sMetaData.mOSArenaHi) + 0xA8))();
/*Write original instruction or translate offset data if a branch*/
if (((ppc >> 24) & 0xFF) > 0x47 && ((ppc >> 24) & 0xFF) < 0x4C) {
Memory::Direct::branch((void*)fillInField, (void*)returnAddress, ppc & 1);
} else {
Memory::Direct::write(fillInField, *gpModInfo.codehandlerHook);
}
/*Write branch back to the hook address + 4*/
Memory::Direct::branch((void*)&fillInField[1], (void*)(&gpModInfo.codehandlerHook[1]), false); //return
}
int main()
{
if ((sDisc.detectHomeConsole() != DiscHeader::CONSOLETYPE::Unknown) && initMods() == true)
call((void*)((u32)(sDisc.sMetaData.mOSArenaHi) + 0xA8))(); /*Call the codehandler if successful*/
call(0x4948494C)(); /*Call the game start*/
if (sDisc.detectHomeConsole() != DiscHeader::CONSOLETYPE::Unknown) {
initMods();
}
__start();
}