#include "re/hook.h" #include #include #include #include "re/config.h" #include "re/log.h" namespace re { namespace { struct HookDef { const char* name; uint32_t address; void** original; void* replacement; }; // Function-local static: registrations run during static initialisation, in // unspecified order across translation units. std::vector& Registry() { static std::vector hooks; return hooks; } } // namespace HookRegistration::HookRegistration(const char* name, uint32_t address, void** original, void* replacement) { Registry().push_back({name, address, original, replacement}); } int InstallHooks() { int failed = 0; int installed = 0; for (const HookDef& hook : Registry()) { if (!ConfigInt("hooks", hook.name, 1)) { Log("hook %-24s 0x%08x disabled by config", hook.name, hook.address); continue; } // One transaction per hook, so a bad hook does not take the others down. DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); LONG error = DetourAttach(hook.original, hook.replacement); if (error == NO_ERROR) { error = DetourTransactionCommit(); } else { DetourTransactionAbort(); } if (error == NO_ERROR) { ++installed; } else { ++failed; Log("hook %-24s 0x%08x FAILED (error %ld)", hook.name, hook.address, error); } } Log("%d hook(s) installed, %d failed", installed, failed); return failed; } bool AttachRuntimeHook(const char* name, void** original, void* replacement) { const void* target = *original; DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); LONG error = DetourAttach(original, replacement); if (error == NO_ERROR) { error = DetourTransactionCommit(); } else { DetourTransactionAbort(); } if (error != NO_ERROR) { Log("hook %-24s %p FAILED (error %ld)", name, target, error); return false; } Log("hook %-24s %p attached at runtime", name, target); return true; } } // namespace re