Files
gtav-src/tools_ng/script/coding/mod/RIM/Source/Hooking.cpp
T
2025-09-29 00:52:08 +02:00

326 lines
8.1 KiB
C++
Executable File

//Hooking.cpp
#include "stdafx.h"
using namespace Memory;
HMODULE _hmoduleDLL;
HANDLE mainFiber;
DWORD wakeAt;
static eGameState* m_gameState;
static uint64_t m_worldPtr;
static BlipList* m_blipList;
static Hooking::NativeRegistration** m_registrationTable;
static std::unordered_map<uint64_t,Hooking::NativeHandler> m_handlerCache;
HWND Hooking::hWindow;
/* Start Hooking */
BOOL CALLBACK ProcessWindow(HWND hWnd, LPARAM lParam)
{
const int buffSize = 255;
WCHAR buff[buffSize];
int lenText = GetWindowText(hWnd, (LPWSTR)buff, buffSize - 1);
if (lenText == 0)
{
return true;
}
// Logic to find the game binary
// First filter on the phrase "game"
if (wcsstr(buff, GAME_WINDOW_NAME) != NULL)
{
lParam = (LPARAM)hWnd;
}
return true;
}
void ProcessWindows(LPARAM lParam)
{
EnumWindows(ProcessWindow, (LPARAM)lParam);
}
bool Hooking::FindGameWindow()
{
ProcessWindows((LPARAM)hWindow);
if (hWindow != NULL)
return true;
else
return false;
}
void Hooking::Start(HMODULE hmoduleDLL)
{
_hmoduleDLL = hmoduleDLL;
Log::Init(hmoduleDLL);
DEBUGMSG("Hooking Started...");
DEBUGMSG("Finding window...");
while (hWindow == NULL)
{
FindGameWindow();
Sleep(100);
}
DEBUGMSG("Window found!");
FindPatterns();
if (!InitializeHooks())
{
DEBUGMSG("Hook init failed!!!");
Cleanup();
return;
}
DEBUGMSG("Hooking complete!");
}
/* Hooks */
// Initialization
BOOL Hooking::InitializeHooks()
{
BOOL returnVal = TRUE;
// Input hook
if (!iHook.Initialize()) {
Log::Error("Failed to initialize InputHook");
returnVal = FALSE;
}
// init minhook
if (MH_Initialize() != MH_OK) {
Log::Error("MinHook failed to initialize");
returnVal = FALSE;
}
// init native hook
if (!HookNatives()) {
Log::Error("Failed to initialize NativeHooks");
returnVal = FALSE;
}
// DX11 Hook
DX11.reset(new DX11Hook());
DX11->InitDevice(hWindow);
return returnVal;
}
/* Native Hook Function */
template <typename T>
bool Native(DWORD64 hash, LPVOID hookFunction, T** trampoline)
{
if (*reinterpret_cast<LPVOID*>(trampoline) != NULL)
return true;
auto originalFunction = Hooking::GetNativeHandler(hash);
if (originalFunction != 0) {
MH_STATUS createHookStatus = MH_CreateHook(originalFunction, hookFunction, reinterpret_cast<LPVOID*>(trampoline));
if (((createHookStatus == MH_OK) || (createHookStatus == MH_ERROR_ALREADY_CREATED)) && (MH_EnableHook(originalFunction) == MH_OK))
{
DEBUGMSG("Hooked Native 0x%#p", hash);
return true;
}
else
{
Log::Error("Failed to hook native! MH_STATUS: %i", createHookStatus);
}
}
return false;
}
/* Native Hook Function */
template <typename T>
bool RageSecPushHook(LPVOID pPushFunc, LPVOID hookFunction, T** trampoline)
{
if (*reinterpret_cast<LPVOID*>(trampoline) != NULL)
return true;
Hooking::RageSecPush originalFunction = (Hooking::RageSecPush)pPushFunc;
if (originalFunction != 0) {
MH_STATUS createHookStatus = MH_CreateHook(originalFunction, hookFunction, reinterpret_cast<LPVOID*>(trampoline));
if (((createHookStatus == MH_OK) || (createHookStatus == MH_ERROR_ALREADY_CREATED)) && (MH_EnableHook(originalFunction) == MH_OK))
{
DEBUGMSG("Hooked Native 0x%#p", pPushFunc);
return true;
}
}
return false;
}
Hooking::NativeHandler ORIG_GET_FRAME_COUNT = NULL;
void* __cdecl MY_GET_FRAME_COUNT(NativeContext *cxt)
{
static int lastFrame = 0;
int thisFrame = cxt->GetArgument<int>(0);
if (thisFrame != lastFrame) {
lastFrame = thisFrame;
Hooking::onTickInit();
} ORIG_GET_FRAME_COUNT(cxt);
return cxt;
}
Hooking::RageSecPush ORIG_RAGE_PUSH = NULL;
char __fastcall MY_RAGE_PUSH(void * _this, Hooking::RageSecObject * o)
{
Log::Msg("RageHook: Attempted RagSec action %08x... Blocking security action...", o->type);
o->type = 0xD79AD02D; // REACT_INVALID
return ORIG_RAGE_PUSH(_this, o);
}
bool Hooking::HookNatives()
{
auto pRagePush = pattern("44 8B 99 08 E0 00 00 4C 8B C9 B9 00 04 00 00 4C 8B D2 44 3B D9 0F 8D AB 00 00 00 45 8B 81 00 E0 00 00 33 C0 41 FF C0 44 3B C1 44 0F 44 C0 41 8B 02");
return true
// native hooks
#ifndef RDR3
&& RageSecPushHook(pRagePush.count(1).get(0).getAddress(), &MY_RAGE_PUSH, &ORIG_RAGE_PUSH) // This should disable the anticheat
#endif
//&& Native(0xFC8202EFC642E6F2, &MY_GET_FRAME_COUNT, &ORIG_GET_FRAME_COUNT);
&& Native(0x10FAB35428CCC9D7, &MY_GET_FRAME_COUNT, &ORIG_GET_FRAME_COUNT); // Use MP session check. It's called a fuckton so be careful.
}
void __stdcall ScriptFunction(LPVOID lpParameter)
{
ScriptMain();
Log::Fatal("Failed scriptFiber");
}
void Hooking::onTickInit()
{
if (mainFiber == nullptr)
mainFiber = ConvertThreadToFiber(nullptr);
if (timeGetTime() < wakeAt)
return;
static HANDLE scriptFiber;
if (scriptFiber)
SwitchToFiber(scriptFiber);
else
scriptFiber = CreateFiber(NULL, ScriptFunction, nullptr);
}
/* Pattern Scanning */
void Hooking::FailPatterns(const char* name, pattern ptn)
{
Log::Error("finding %s", name);
Cleanup();
}
void Hooking::FindPatterns()
{
auto p_fixVector3Result = pattern("83 79 18 00 48 8B D1 74 4A FF 4A 18"); // RDR PASS
auto p_gameState = pattern("EC 38 8B 05 ? ? ? ? 85 C0 0F 84"); // CLoadingScreens::AreActive()
auto p_nativeTable = pattern("73 2C 76 78 48 8B 43 40 48 8D 0D"); //RDR PASS -> 11 byte sig
char * c_location = nullptr;
// Executable Base Address
DEBUGMSG("baseAddr\t\t 0x%p", get_base());
// Executable End Address
DEBUGMSG("endAddr\t\t 0x%p", get_base() + get_size());
// Get game state
c_location = p_gameState.count(1).get(0).get<char>(4);
DEBUGMSG("Finding Game State...");
//while (c_location == nullptr) Sleep(10);
//c_location == nullptr ? FailPatterns("gameState", p_gameState) : m_gameState = reinterpret_cast<decltype(m_gameState)>(c_location + *(int32_t*)c_location + 5);
// Get vector3 result fixer function
DEBUGMSG("Finding Vector3 Result Fixer...");
auto void_location = p_fixVector3Result.count(1).get(0).get<void>(0);
if (void_location != nullptr) scrNativeCallContext::SetVectorResults = (void(*)(scrNativeCallContext*))(void_location);
// Get native registration table
DEBUGMSG("Finding Native Registration...");
c_location = p_nativeTable.count(1).get(0).get<char>(11);
c_location == nullptr ? FailPatterns("native registration Table", p_nativeTable) : m_registrationTable = reinterpret_cast<decltype(m_registrationTable)>(c_location + *(int32_t*)c_location + 4);
// Get blip list
//c_location = p_blipList.count(1).get(0).get<char>(0);
//c_location == nullptr ? FailPatterns("blip List", p_blipList) : _blipList = (BlipList*)(c_location + *reinterpret_cast<int*>(c_location + 3) + 7);
DEBUGMSG("Initializing natives");
CrossMapping::initNativeMap();
// Check if game is ready
Log::Msg("Checking if game is ready...");
//while (!*m_gameState == GameStatePlaying) {
// Sleep(100);
//}
Log::Msg("Game ready");
}
static Hooking::NativeHandler _Handler(uint64_t origHash) {
uint64_t newHash = CrossMapping::MapNative(origHash);
if (newHash == 0) {
return nullptr;
}
Hooking::NativeRegistration * table = m_registrationTable[newHash & 0xFF];
for (; table; table = table->nextRegistration)
{
for (uint32_t i = 0; i < table->numEntries; i++)
{
if (newHash == table->hashes[i])
{
return table->handlers[i];
}
}
}
return nullptr;
}
Hooking::NativeHandler Hooking::GetNativeHandler(uint64_t origHash)
{
auto& handler = m_handlerCache[origHash];
if (handler == nullptr)
{
handler = _Handler(origHash);
}
return handler;
}
eGameState Hooking::GetGameState()
{
return *m_gameState;
}
/*
Not in RDR2 yet
BlipList* Hooking::GetBlipList()
{
return m_blipList;
}
*/
void WAIT(DWORD ms)
{
wakeAt = timeGetTime() + ms;
SwitchToFiber(mainFiber);
}
/* Clean Up */
void Hooking::Cleanup()
{
Log::Msg("CleanUp: RIMHook");
iHook.keyboardHandlerUnregister(OnKeyboardMessage);
iHook.Remove();
MH_Uninitialize();
FreeLibraryAndExitThread(_hmoduleDLL, 0);
}