feat: added inline hook manager

This commit is contained in:
2025-11-18 20:01:46 +01:00
parent 1c3afef164
commit 50fb354983
2 changed files with 136 additions and 0 deletions

31
src/detail/hooking.hpp Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include <cstddef>
#include <vector>
namespace fxn
{
struct HookInfo
{
void* targetFunction;
void* hookFunction;
std::vector<std::byte> originalBytes;
};
class HookingManager
{
private:
std::vector<HookInfo> m_Hooks;
protected:
HookingManager();
~HookingManager();
public:
static HookingManager& GetInstance();
static void Destroy();
public:
bool InstallHook(void* targetFunction, void* hookFunction);
bool RemoveHook(void* targetFunction);
};
}

105
src/impl/hooking.cpp Normal file
View File

@@ -0,0 +1,105 @@
#include <array>
#include <Windows.h>
#include <detail/hooking.hpp>
namespace fxn
{
namespace
{
HookingManager* g_HookingManager = nullptr;
}
HookingManager::HookingManager()
{
}
HookingManager::~HookingManager()
{
for (const auto& hook : m_Hooks)
{
RemoveHook(hook.targetFunction);
}
m_Hooks.clear();
}
HookingManager& HookingManager::GetInstance()
{
if (!g_HookingManager)
{
g_HookingManager = new HookingManager();
}
return *g_HookingManager;
}
void HookingManager::Destroy()
{
if (g_HookingManager)
{
delete g_HookingManager;
}
g_HookingManager = nullptr;
}
bool HookingManager::InstallHook(void* targetFunction, void* hookFunction)
{
/*
mov rax, <hookFunction>
jmp rax
*/
constexpr auto HOOK_SIZE = 12;
constexpr auto HOOK_INSTRUCTION = std::array<std::uint8_t, HOOK_SIZE>
{
0x48, 0xB8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xE0
};
auto hookBytes = HOOK_INSTRUCTION;
*reinterpret_cast<std::uintptr_t*>(&hookBytes[2]) = reinterpret_cast<std::uintptr_t>(hookFunction);
DWORD oldProtect;
if (!VirtualProtect(targetFunction, HOOK_SIZE, PAGE_EXECUTE_READWRITE, &oldProtect))
{
return false;
}
HookInfo hookInfo;
hookInfo.targetFunction = targetFunction;
hookInfo.hookFunction = hookFunction;
hookInfo.originalBytes.resize(HOOK_SIZE);
std::memcpy(hookInfo.originalBytes.data(), targetFunction, HOOK_SIZE);
std::memcpy(targetFunction, hookBytes.data(), HOOK_SIZE);
VirtualProtect(targetFunction, HOOK_SIZE, oldProtect, &oldProtect);
m_Hooks.push_back(std::move(hookInfo));
return true;
}
bool HookingManager::RemoveHook(void* targetFunction)
{
auto it = std::find_if(m_Hooks.begin(), m_Hooks.end(),
[targetFunction](const HookInfo& hook) { return hook.targetFunction == targetFunction; });
if (it == m_Hooks.end())
{
return false;
}
DWORD oldProtect;
if (!VirtualProtect(targetFunction, it->originalBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect))
{
return false;
}
std::memcpy(targetFunction, it->originalBytes.data(), it->originalBytes.size());
VirtualProtect(targetFunction, it->originalBytes.size(), oldProtect, &oldProtect);
m_Hooks.erase(it);
return true;
}
}