326 lines
8.1 KiB
C++
Executable File
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);
|
|
} |