feat: added inline hook manager
This commit is contained in:
31
src/detail/hooking.hpp
Normal file
31
src/detail/hooking.hpp
Normal 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
105
src/impl/hooking.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user