void EnableAutoMipmaps() { enabled = true; WriteJump((void*)0x0078CD2A, GenerateMipmaps_asm); // Hooks the end of the function that converts PVRs to D3D textures #ifdef PALLETIZED_MIPMAPS // This happens every frame for every palletized texture in the scene. Rather inefficient where mipmap generation is concerned. // Assuming somebody can figure out a method of keeping track of palette changes and textures who's mips have already been generated, // we can enable this for mainstream builds. Otherwise it should stay off. WriteJump((void*)0x0078CF06, GeneratePalletizedMipmaps_asm); #endif }
void ConfigureFOV() { static const double default_ratio = 4.0 / 3.0; const uint32_t width = HorizontalResolution; const uint32_t height = VerticalResolution; WriteJump(SetupScreen, SetupScreenFix); // Taking advantage of a nullsub call. WriteCall((void*)0x00513A88, DisplayVideoFrame_FixAspectRatio); // 4:3 and "tallscreen" (5:4, portrait, etc) // We don't need to do anything since these resolutions work fine with the default code. if ((height * default_ratio) == width || (height * default_ratio) > width) return; fov_rads = 0.96712852; // 55.412382 degrees fov_bams = NJM_RAD_ANG(fov_rads); // Function hooks WriteJump(njSetPerspective, njSetPerspective_hook); WriteJump(njSetScreenDist, njSetScreenDist_hook); // Code patches WriteJump((void*)0x0079124A, SetFOV); WriteData((float**)0x00781525, &dummy); // Dirty hack to disable a write to ClippingRelated and keep the floating point stack balanced. WriteData((Angle**)0x0040872B, &last_bams); // Fixes a case of direct access to HorizontalFOV_BAMS WriteData((Angle**)0x00402F01, &last_bams); // Changes return value of GetHorizontalFOV_BAMS njSetPerspective_hook(bams_default); // Stops the Pause Menu from using horizontal stretch in place of vertical stretch in coordinate calculation // Main Pause Menu WriteData((float**)0x00457F69, &VerticalStretch); // Elipse/Oval WriteData((float**)0x004584EE, &VerticalStretch); // Blue Transparent Box WriteData((float**)0x0045802F, &VerticalStretch); // Pause Menu Options // Camera options WriteData((float**)0x00458D5C, &VerticalStretch); // Blue Transparent Box WriteData((float**)0x00458DF4, &VerticalStretch); // Auto Cam WriteData((float**)0x00458E3A, &VerticalStretch); // Free Cam // Controls WriteData((float**)0x0045905A, &VerticalStretch); // Blue Transparent Box WriteData((float**)0x004590BB, &VerticalStretch); // Each Control Element WriteData((float**)0x00459133, &VerticalStretch); // Default Button }
stdc VOID __cdecl EnableHook(ULONG_PTR Function) { HOOK_INFO *hinfo = GetHookInfoFromFunction(Function); if (hinfo) { if(!hinfo->Enabled){ hinfo->Enabled = true; WriteJump((VOID *)hinfo->Function, hinfo->Hook, hinfo->hooktype, hinfo->index ); } } }
stdc VOID __cdecl DisableHook(ULONG_PTR Function) { HOOK_INFO *hinfo = GetHookInfoFromFunction(Function); if (hinfo) { if(hinfo->Enabled){ hinfo->Enabled = false; WriteJump((VOID *)hinfo->Function, hinfo->Bridge, ht_jmp, hinfo->index); } } }
inline void WriteStubGate(Process const& process, void* address, void* stub, void* get_orig_user_ptr_ptr_fn) { using StubT = typename PatchDetourStub<TargetFuncT>; #if defined(HADESMEM_DETAIL_ARCH_X64) auto const stub_gate = GenStubGate64(stub, get_orig_user_ptr_ptr_fn); #elif defined(HADESMEM_DETAIL_ARCH_X86) auto const stub_gate = GenStubGate32(stub, get_orig_user_ptr_ptr_fn); #else #error "[HadesMem] Unsupported architecture." #endif WriteVector(process, address, stub_gate); WriteJump(process, static_cast<std::uint8_t*>(address) + stub_gate.size(), &StubT::Stub, true, nullptr); FlushInstructionCache(process, address, stub_gate.size()); }
stdc BOOL __cdecl HookFunction(ULONG_PTR OriginalFunction, ULONG_PTR NewFunction, char *name, hookType ht) { lastErrorCode = he_None; specificError = hs_None; lastError[0] = 0; if(!initilized){ if( !InitHookEngine() ){ lastErrorCode = he_cantInit; strcpy(lastError,"Can not Initilize HookEngine."); dbgmsg(1,lastError); return FALSE; } } HOOK_INFO *hinfo = GetHookInfoFromFunction(OriginalFunction); if (hinfo) return TRUE; //already hooked... if (g_NumberOfHooks == (MAX_HOOKS - 1)){ lastErrorCode = he_maxHooks; strcpy(lastError,"Maximum number of hooks reached."); dbgmsg(1,lastError); return FALSE; } if(ht > ht_auto){ sprintf(lastError, "Unimplemented hook type asked for"); lastErrorCode = he_UnknownHookType; return false; } hinfo = &g_HookInfo[g_NumberOfHooks]; hinfo->Function = OriginalFunction; hinfo->Hook = NewFunction; hinfo->hooktype = ht; hinfo->index = g_NumberOfHooks; hinfo->ApiName = strdup(name); hinfo->preAlignBytes = CountPreAlignBytes( (BYTE*)OriginalFunction ); hinfo->hookableBytes = HookableBytes( OriginalFunction ); dbgmsg(1, "Hooking %s (0x%llx) -> 0x%llx, pre=%d avail=%d\n", hinfo->ApiName, hinfo->Function , hinfo->Hook , hinfo->preAlignBytes, hinfo->hookableBytes); if( ht == ht_auto ){ if(!AutoChooseHookType(hinfo)){ lastErrorCode = he_cantHook; dbgmsg(1, lastError); ZeroHookInfo(hinfo->index); return FALSE; } dbgmsg(1, "AutoChooseHookType selected %s for %s\n", hook_name[(int)hinfo->hooktype], hinfo->ApiName ); } if( !ValidateHookType(hinfo) ){ lastErrorCode = he_cantHook; dbgmsg(1, lastError); ZeroHookInfo(hinfo->index); return FALSE; } VOID *pBridge = CreateBridge(hinfo); if (pBridge == NULL){ ZeroHookInfo(g_NumberOfHooks); return FALSE; } hinfo->Bridge = (ULONG_PTR) pBridge; hinfo->Enabled = true; OverWriteScratchPad((VOID *)OriginalFunction, hinfo); //make pad were going to overwrite all 0xCC for debugging sake.. if(!WriteJump((VOID *) OriginalFunction, NewFunction, hinfo->hooktype, g_NumberOfHooks)){ //activates hook in api prolog.. ZeroHookInfo(g_NumberOfHooks); return FALSE; } g_NumberOfHooks++; //now its complete.. return TRUE; }
VOID *CreateBridge(HOOK_INFO *hinfo) { if (g_pBridgeBuffer == NULL) return NULL; UINT x = 0; _DecodeResult res; _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; unsigned int decodedInstructionsCount = 0; _DecodeType dt = isX64 ? Decode64Bits : Decode32Bits; _OffsetType offset = 0; ULONG_PTR Function = hinfo->Function; int JumpSize = GetJumpSize(hinfo->hooktype); res = distorm_decode(offset, // offset for buffer (const BYTE *) Function, // buffer to disassemble 50, // function size (code size to disasm) // 50 instr should be _quite_ enough dt, // x86 or x64? decodedInstructions, // decoded instr MAX_INSTRUCTIONS, // array size &decodedInstructionsCount // how many instr were disassembled? ); if (res == DECRES_INPUTERR){ sprintf(lastError, "Could not disassemble address %x", (UINT)Function); //dbgmsg(lastError); lastErrorCode = he_cantDisasm; return NULL; } DWORD InstrSize = 0; VOID *pBridge = (VOID *) &g_pBridgeBuffer[g_CurrentBridgeBufferSize]; //copy full instructions from API to our trampoline. for (x ; x < decodedInstructionsCount; x++) { if (InstrSize >= JumpSize) break; BYTE *pCurInstr = (BYTE *) (InstrSize + (ULONG_PTR) Function); if(logLevel >=3){ dbgmsg(3, "%s+%d \t %-10s %-6s %s", hinfo->ApiName, InstrSize, decodedInstructions[x].instructionHex.p, decodedInstructions[x].mnemonic.p, decodedInstructions[x].operands.p ); } if( UnSupportedOpcode(pCurInstr, hinfo->index) ){ dbgmsg(0, "CreatreBridge::UnSupportedOpcode found missed in pre-Validation?! needed=%d, hookable=%d, cur=%d, type=%s", JumpSize, hinfo->hookableBytes,InstrSize, GetHookName(hinfo->hooktype) ); DebugBreak(); //if we leave here, g_CurrentBridgeBufferSize has been incremented and bytes copied to //the alloced g_pBridgeBuffer, but the API itself is untouched. return NULL; } memcpy(&g_pBridgeBuffer[g_CurrentBridgeBufferSize], (VOID *) pCurInstr, decodedInstructions[x].size); g_CurrentBridgeBufferSize += decodedInstructions[x].size; InstrSize += decodedInstructions[x].size; } hinfo->OverwrittenInstructions = x; hinfo->OverwrittenBytes = InstrSize; //we will 0xCC this many in API latter for debugging sake... //to leave trampoline... hookType ht = isX64 ? ht_jmp : ht_pushret; //both absolute address jumps for safety... bool rv = WriteJump(&g_pBridgeBuffer[g_CurrentBridgeBufferSize], Function + InstrSize, ht, hinfo->index); g_CurrentBridgeBufferSize += GetJumpSize(ht); if(!rv) return NULL; return pBridge; }