#include "STDInclude.hpp" namespace Utils { std::map Hook::Interceptor::IReturn; std::map Hook::Interceptor::ICallbacks; void Hook::Signature::Process() { if (Hook::Signature::Signatures.empty()) return; char* start = reinterpret_cast(Hook::Signature::Start); unsigned int sigCount = Hook::Signature::Signatures.size(); Hook::Signature::Container* containers = Hook::Signature::Signatures.data(); for (size_t i = 0; i < Hook::Signature::Length; ++i) { char* address = start + i; for (unsigned int k = 0; k < sigCount; ++k) { Hook::Signature::Container* container = &containers[k]; unsigned int j = 0; for (j = 0; j < strlen(container->Mask); ++j) { if (container->Mask[j] != '?' &&container->Signature[j] != address[j]) { break; } } if (j == strlen(container->Mask)) { container->Callback(address); } } } } void Hook::Signature::Add(Hook::Signature::Container& container) { Hook::Signature::Signatures.push_back(container); } void Hook::Interceptor::Install(void* place, void(*stub)()) { return Hook::Interceptor::Install(reinterpret_cast(place), stub); } void Hook::Interceptor::Install(void** place, void(*stub)()) { Hook::Interceptor::IReturn[place] = *place; Hook::Interceptor::ICallbacks[place] = stub; *place = Hook::Interceptor::InterceptionStub; } void __declspec(naked) Hook::Interceptor::InterceptionStub() { __asm { sub esp, 4h // Reserve space on the stack for the return address pushad // Store registers lea eax, [esp + 20h] // Load initial stack pointer push eax // Push it onto the stack call RunCallback // Run the callback based on the given stack pointer call PopReturn // Get the initial return address according to the stack pointer add esp, 4h // Clear the stack mov [esp + 20h], eax // Store the return address at the reserved space popad // Restore the registers retn // Return (jump to our return address) } } void Hook::Interceptor::RunCallback(void* place) { auto iCallback = Hook::Interceptor::ICallbacks.find(place); if (iCallback != Hook::Interceptor::ICallbacks.end()) { iCallback->second(); Hook::Interceptor::ICallbacks.erase(iCallback); } } void* Hook::Interceptor::PopReturn(void* place) { void* retVal = nullptr; auto iReturn = Hook::Interceptor::IReturn.find(place); if (iReturn != Hook::Interceptor::IReturn.end()) { retVal = iReturn->second; Hook::Interceptor::IReturn.erase(iReturn); } return retVal; } Hook::~Hook() { if (Hook::Initialized) { Hook::Uninstall(); } } Hook* Hook::Initialize(DWORD place, void(*stub)(), bool useJump) { return Hook::Initialize(place, reinterpret_cast(stub), useJump); } Hook* Hook::Initialize(DWORD place, void* stub, bool useJump) { return Hook::Initialize(reinterpret_cast(place), stub, useJump); } Hook* Hook::Initialize(void* place, void* stub, bool useJump) { if (Hook::Initialized) return this; Hook::Initialized = true; Hook::UseJump = useJump; Hook::Place = place; Hook::Stub = stub; Hook::Original = static_cast(Hook::Place) + 5 + *reinterpret_cast((static_cast(Hook::Place) + 1)); return this; } Hook* Hook::Install(bool unprotect, bool keepUnportected) { Hook::StateMutex.lock(); if (!Hook::Initialized || Hook::Installed) { Hook::StateMutex.unlock(); return this; } Hook::Installed = true; if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection); memcpy(Hook::Buffer, Hook::Place, sizeof(Hook::Buffer)); char* code = static_cast(Hook::Place); *code = static_cast(Hook::UseJump ? 0xE9 : 0xE8); *reinterpret_cast(code + 1) = reinterpret_cast(Hook::Stub) - (reinterpret_cast(Hook::Place) + 5); if (unprotect && !keepUnportected) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection); FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer)); Hook::StateMutex.unlock(); return this; } void Hook::Quick() { if (Hook::Installed) { Hook::Installed = false; } } Hook* Hook::Uninstall(bool unprotect) { Hook::StateMutex.lock(); if (!Hook::Initialized || !Hook::Installed) { Hook::StateMutex.unlock(); return this; } Hook::Installed = false; if(unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection); memcpy(Hook::Place, Hook::Buffer, sizeof(Hook::Buffer)); if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection); FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer)); Hook::StateMutex.unlock(); return this; } void* Hook::GetAddress() { return Hook::Place; } void Hook::Nop(void* place, size_t length) { DWORD oldProtect; VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &oldProtect); memset(place, 0x90, length); VirtualProtect(place, length, oldProtect, &oldProtect); FlushInstructionCache(GetCurrentProcess(), place, length); } void Hook::Nop(DWORD place, size_t length) { Nop(reinterpret_cast(place), length); } void Hook::SetString(void* place, const char* string, size_t length) { DWORD oldProtect; VirtualProtect(place, length + 1, PAGE_EXECUTE_READWRITE, &oldProtect); strncpy(static_cast(place), string, length); VirtualProtect(place, length + 1, oldProtect, &oldProtect); } void Hook::SetString(DWORD place, const char* string, size_t length) { Hook::SetString(reinterpret_cast(place), string, length); } void Hook::SetString(void* place, const char* string) { Hook::SetString(place, string, strlen(static_cast(place))); } void Hook::SetString(DWORD place, const char* string) { Hook::SetString(reinterpret_cast(place), string); } void Hook::RedirectJump(void* place, void* stub) { char* operandPtr = static_cast(place) + 2; int newOperand = reinterpret_cast(stub) - (reinterpret_cast(place) + 6); Utils::Hook::Set(operandPtr, newOperand); } void Hook::RedirectJump(DWORD place, void* stub) { Hook::RedirectJump(reinterpret_cast(place), stub); } }