//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 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 bool Native(DWORD64 hash, LPVOID hookFunction, T** trampoline) { if (*reinterpret_cast(trampoline) != NULL) return true; auto originalFunction = Hooking::GetNativeHandler(hash); if (originalFunction != 0) { MH_STATUS createHookStatus = MH_CreateHook(originalFunction, hookFunction, reinterpret_cast(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 bool RageSecPushHook(LPVOID pPushFunc, LPVOID hookFunction, T** trampoline) { if (*reinterpret_cast(trampoline) != NULL) return true; Hooking::RageSecPush originalFunction = (Hooking::RageSecPush)pPushFunc; if (originalFunction != 0) { MH_STATUS createHookStatus = MH_CreateHook(originalFunction, hookFunction, reinterpret_cast(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(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(4); DEBUGMSG("Finding Game State..."); //while (c_location == nullptr) Sleep(10); //c_location == nullptr ? FailPatterns("gameState", p_gameState) : m_gameState = reinterpret_cast(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(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(11); c_location == nullptr ? FailPatterns("native registration Table", p_nativeTable) : m_registrationTable = reinterpret_cast(c_location + *(int32_t*)c_location + 4); // Get blip list //c_location = p_blipList.count(1).get(0).get(0); //c_location == nullptr ? FailPatterns("blip List", p_blipList) : _blipList = (BlipList*)(c_location + *reinterpret_cast(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); }