From 01578f387471f065f14ad8fb1d986b3968350a89 Mon Sep 17 00:00:00 2001 From: JoshuaMKW <60854312+JoshuaMKW@users.noreply.github.com> Date: Tue, 25 Aug 2020 04:28:22 -0500 Subject: [PATCH] Codehandler can now be hooked almost anywhere --- bin/codehandler-mini.bin | Bin 1544 -> 1552 bytes bin/codehandler.bin | Bin 2584 -> 2584 bytes bin/geckoloader.bin | Bin 964 -> 804 bytes dolreader.py | 16 +++++++++-- kernel.py | 47 +++++++++++++++++++++++++++++-- loader.cpp | 58 ++++++++++++++++++++++++++++++--------- 6 files changed, 104 insertions(+), 17 deletions(-) diff --git a/bin/codehandler-mini.bin b/bin/codehandler-mini.bin index 8f3913401af5048ba284545a86e2d95cce69fa16..86bd8489b474386fcd81d3b809da8d974166b868 100644 GIT binary patch delta 66 zcmeC+nZU!t00j*UvPUKgPM@g2I&nofBgZ60V@8+BCX5y=4EOHc+nmEF%)+>3asz7v KPXbH_kOlw;4GzBm delta 51 zcmbQh)4{{T00j*UvIiy#PM@g2I&nofBf}&{V@8L`CX5!F3mAo27fO{MwiJZj20{m_wL=>oWsb@&Uj#R3C9e^i3%J5 DUNR2c delta 57 zcmbOsGDC!i0SX!z6wgc)oIX*3b>fO{Mu*8Jj24><7}?nwk8G~sn8C=C08 diff --git a/bin/geckoloader.bin b/bin/geckoloader.bin index d6d57f14d837ac7b7a58e07e194dc3189c8fe18c..54ab518dfa858ff77395ac524692657678948c94 100644 GIT binary patch delta 522 zcmY+A&1(}u7>9q`9XAnz1X*Rtio_xqEr0hc9FX@bomm4#ODu&}Xs@ZfQUSu@RU z3PKMlTW=~zKIkEb9zDehHX`^pgdA)Vi(qehsBR~sqK7#QFY~<5Jnv#HbQ%)K z=DBES*c{XWcoS#14=r3pGJFL!d<%`O%{|W7W#)&N@7XE>L0wx*HAHr3q?L&D6#ge>XDR6>(J;{bjUu)9c!{?TBCW>`rJ3IeZ};Y ztm|F6zb-kd80RN4n&N;-Fa2gq|#>i4hw7Lv@<%A(qq_`k3KB xfWCD_rnF&;q>d=$ASup&^M7abrI4=tk|TfQ1nW3qNDJ77ZumgXkeheQ))7&*v(Nwl delta 706 zcmZva!D|yi7{%Wt+nCZIIjj&$k+oDzV<=GqPU;djHMC0`LWJ!>@UW6pJScdKFd>t4 z)1r8&G)E7CCNYH^a`50mv|tnejY6!gw;p>C;*mW;)oZ?uy(sfOON+v^Y89MhZ-cG&YHV2`))lzZb?0Oa z>UcJfcvvBi8vI5TaoIvZ)Ml?36I-nK4ROzx~?cz!hE4%Xf@!QSnGEn#$S0-vG^ zSV}_wM>{bV@2YIR++WGaHUd`b>`SVOr~1*FDNoiiVlb-;XIkY?V2XWj+xoGUw2qgP z*6AQ={q!Y8KT<4Bt`>902baZQsrcY}^(uEpzjFQb0zUwpAr#TMUE~8WaS|ztPDHJL zheE+lb(=!xY40Y2Ww#wIHe?fc*2>E81T<=Xb2jcDEI znqbf+k#>mEA!aIRg!mBQgcqTx4~V`75*qvo8;ah5ovq&TxP^EF?pzuCE7MYS_z9Pv zpOV<1Ky?HjhXMC3F*P>8dNjCLp~aNS!uVRIfsPN7dDLQ=-j37 zKLW1NpMS8cdLHebd%|%syj$eki1YX0{2MaDOZQD^R?V-Aazt%-31KOsYE9hh(f$6z Gob?;kr_j;> 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