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