diff --git a/bin/codehandler-mini.bin b/bin/codehandler-mini.bin index 8f39134..86bd848 100644 Binary files a/bin/codehandler-mini.bin and b/bin/codehandler-mini.bin differ diff --git a/bin/codehandler.bin b/bin/codehandler.bin index 0027fca..bef77eb 100644 Binary files a/bin/codehandler.bin and b/bin/codehandler.bin differ diff --git a/bin/geckoloader.bin b/bin/geckoloader.bin index d6d57f1..54ab518 100644 Binary files a/bin/geckoloader.bin and b/bin/geckoloader.bin differ diff --git a/dolreader.py b/dolreader.py index 8c43d7e..2c80158 100644 --- a/dolreader.py +++ b/dolreader.py @@ -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) diff --git a/kernel.py b/kernel.py index 0dcb56b..e95dbd3 100644 --- a/kernel.py +++ b/kernel.py @@ -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) \ No newline at end of file diff --git a/loader.cpp b/loader.cpp index cea6536..fa7e725 100644 --- a/loader.cpp +++ b/loader.cpp @@ -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 - 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*)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(); } \ No newline at end of file