Codehandler can now be hooked almost anywhere
This commit is contained in:
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.
16
dolreader.py
16
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)
|
||||
|
|
47
kernel.py
47
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)
|
58
loader.cpp
58
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 <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();
|
||||
}
|
Reference in a new issue