/*Credits to riidefi for hook code, cache asm, and teaching me C*/ #define dcbst(_val) asm volatile("dcbst 0, %0" : : "r"(_val)) #define dcbf(_val) asm volatile("dcbf 0, %0" : : "r"(_val)) #define icbi(_val) asm volatile("icbi 0, %0" : : "r"(_val)) typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8; typedef int BOOL; typedef u32 unk32; enum { FALSE, TRUE }; enum { NULL }; struct Info { u32 allocsize; u32 _loaderSize; u32 _loaderFullSize; struct CodeList *_codelistPointer; u32 _wiiVIHook[4]; u32 _gcnVIHook[8]; }; struct CodeList { u16 mBaseASM; u16 mUpperBase; u16 mOffsetASM; u16 mLowerOffset; }; struct DiscInfo { u8 mDiscID; u16 mGameCode; u8 mRegionCode; u16 mMakerCode; u8 mDiscNumber; u8 mDiscVersion; u8 mAudioStreaming; u8 mStreamBufferSize; u8 mUnknown[12]; u32 mWiiMagic; u32 mGCNMagic; u32 mUnknown2[2]; u32 mRAMSize; u32 mUnknown3[2]; u32 *mHeapPointer; u32 mHeapMirror; u32 mFstSize; u32 mData[(0x3110 - 0x40) / 4]; u32 mWiiHeap; }; struct Info gInfo = { .allocsize = 0, ._loaderSize = 0, ._loaderFullSize = 0, ._codelistPointer = (struct CodeList *)0x800018F8, ._wiiVIHook = {0x7CE33B78, 0x38870034, 0x38A70038, 0x38C7004C}, ._gcnVIHook = {0x7C030034, 0x38830020, 0x5485083C, 0x7C7F2A14, 0xA0030000, 0x7C7D2A14, 0x20A4003F, 0xB0030000}, }; static inline void flushAddr(void *addr) { dcbf(addr); icbi(addr); } static inline void directWrite(u32 *addr, u32 ptr) { addr[0] = ptr; flushAddr(addr); } static inline void directBranchEx(void *addr, void *ptr, BOOL link) { directWrite((u32 *)(addr), ((((u32)(ptr) - (u32)(addr)) & 0x3ffffff) | 0x48000000 | !!link)); } void (*_init_registers)(void) = &gInfo; void (*_codeHandler)(void) = &gInfo; static inline u32 *findFunction(u32 *hookData, u32 *start, u32 end, u32 arrayLength) { u32 index = 0; for (u32 i = 0; (u32)&start[i] < end; ++i) { if (start[i] == hookData[index]) index = index + 1; else index = 0; if (index >= (arrayLength - 1)) { if ((u32)&start[i] < &gInfo || (u32)&start[i] > (u32)&gInfo + 0x100) { return &start[i]; } } } return NULL; } void hookFunction(u32 *start, u32 hookInstruction, u32 hookTo) { int i = 0; while (start[i] != hookInstruction) { ++i; } directBranchEx((u32 *)(&start[i]), (void *)(hookTo), FALSE); } static inline void overwriteValue(u32 *addr, u32 newValue) { addr[0] = newValue; flushAddr(&addr[0]); } void initMods(struct DiscInfo *baseAddress) { struct Info *infoPointer = &gInfo; const u32 *geckoPointerInit = (u32 *)(u32)baseAddress + 0x18F8; u32 sizeDiff = infoPointer->_loaderFullSize - infoPointer->_loaderSize; const u32 *sourcePointer = (u32 *)(infoPointer); if (infoPointer->_codelistPointer) { if (baseAddress->mWiiMagic) { baseAddress->mHeapPointer = (u32)baseAddress->mWiiHeap - infoPointer->allocsize; baseAddress->mWiiHeap = (u32)baseAddress->mHeapPointer; } else if (baseAddress->mGCNMagic) { baseAddress->mHeapPointer = (u32)baseAddress->mHeapPointer - infoPointer->allocsize; } if (infoPointer->_loaderFullSize > 0 && infoPointer->_loaderSize > 0) { while (sizeDiff > 0) { sizeDiff = sizeDiff - 4; baseAddress->mHeapPointer[sizeDiff / 4] = sourcePointer[sizeDiff / 4]; } infoPointer->_codelistPointer->mUpperBase = ((u32)baseAddress->mHeapPointer >> 16) & 0xFFFF; infoPointer->_codelistPointer->mLowerOffset = (u32)(baseAddress->mHeapPointer) & 0xFFFF; flushAddr(&infoPointer->_codelistPointer->mUpperBase); flushAddr(&infoPointer->_codelistPointer->mLowerOffset); u32 *functionAddr; if (baseAddress->mWiiMagic) { functionAddr = findFunction((u32 *)infoPointer->_wiiVIHook, (u32 *)baseAddress, 0x817FFF00, 0x4); } else { functionAddr = findFunction((u32 *)infoPointer->_gcnVIHook, (u32 *)baseAddress, 0x817FFF00, 0x8); } if (functionAddr) { hookFunction(functionAddr, 0x4E800020, 0x800018A8); } } } } int main() { struct DiscInfo *baseAddress = (struct DiscInfo *)0x80000000; if (baseAddress->mWiiMagic || baseAddress->mGCNMagic) { initMods(baseAddress); (*_codeHandler)(); } (*_init_registers)(); }