SafetyHook
Loading...
Searching...
No Matches
vmt_hook.hpp
Go to the documentation of this file.
1
3
4#pragma once
5
6#ifndef SAFETYHOOK_USE_CXXMODULES
7#include <cstdint>
8#include <expected>
9#include <unordered_map>
10#else
11import std.compat;
12#endif
13
15#include "safetyhook/common.hpp"
16#include "safetyhook/utility.hpp"
17
18namespace safetyhook {
20class SAFETYHOOK_API VmHook final {
21public:
22 VmHook() = default;
23 VmHook(const VmHook&) = delete;
24 VmHook(VmHook&& other) noexcept;
25 VmHook& operator=(const VmHook&) = delete;
26 VmHook& operator=(VmHook&& other) noexcept;
27 ~VmHook();
28
30 void reset();
31
33 template <typename T> [[nodiscard]] T original() const { return reinterpret_cast<T>(m_original_vm); }
34
41 template <typename RetT = void, typename... Args> RetT call(Args... args) {
42 return original<RetT (*)(Args...)>()(args...);
43 }
44
50 template <typename RetT = void, typename... Args> RetT ccall(Args... args) {
51 return original<RetT(SAFETYHOOK_CCALL*)(Args...)>()(args...);
52 }
53
59 template <typename RetT = void, typename... Args> RetT thiscall(Args... args) {
60 return original<RetT(SAFETYHOOK_THISCALL*)(Args...)>()(args...);
61 }
62
68 template <typename RetT = void, typename... Args> RetT stdcall(Args... args) {
69 return original<RetT(SAFETYHOOK_STDCALL*)(Args...)>()(args...);
70 }
71
77 template <typename RetT = void, typename... Args> RetT fastcall(Args... args) {
78 return original<RetT(SAFETYHOOK_FASTCALL*)(Args...)>()(args...);
79 }
80
81private:
82 friend class VmtHook;
83
84 uint8_t* m_original_vm{};
85 uint8_t* m_new_vm{};
86 uint8_t** m_vmt_entry{};
87
88 // This keeps the allocation alive until the hook is destroyed.
89 std::shared_ptr<Allocation> m_new_vmt_allocation{};
90
91 void destroy();
92};
93
95class SAFETYHOOK_API VmtHook final {
96public:
98 struct Error {
100 enum : uint8_t {
102 } type;
103
105 union {
107 };
108
112 [[nodiscard]] static Error bad_allocation(Allocator::Error err) {
113 Error error{};
114 error.type = BAD_ALLOCATION;
115 error.allocator_error = err;
116 return error;
117 }
118 };
119
123 [[nodiscard]] static std::expected<VmtHook, Error> create(void* object);
124
125 VmtHook() = default;
126 VmtHook(const VmtHook&) = delete;
127 VmtHook(VmtHook&& other) noexcept;
128 VmtHook& operator=(const VmtHook&) = delete;
129 VmtHook& operator=(VmtHook&& other) noexcept;
130 ~VmtHook();
131
135 void apply(void* object);
136
139 void remove(void* object);
140
142 void reset();
143
147 template <typename T> [[nodiscard]] std::expected<VmHook, Error> hook_method(size_t index, T new_function) {
148 VmHook hook{};
149
150 ++index; // Skip RTTI pointer.
151 hook.m_original_vm = m_new_vmt[index];
152 store(reinterpret_cast<uint8_t*>(&hook.m_new_vm), new_function);
153 hook.m_vmt_entry = &m_new_vmt[index];
154 hook.m_new_vmt_allocation = m_new_vmt_allocation;
155 m_new_vmt[index] = hook.m_new_vm;
156
157 return hook;
158 }
159
160private:
161 // Map of object instance to their original VMT.
162 std::unordered_map<void*, uint8_t**> m_objects{};
163
164 // The allocation is a shared_ptr, so it can be shared with VmHooks to ensure the memory is kept alive.
165 std::shared_ptr<Allocation> m_new_vmt_allocation{};
166 uint8_t** m_new_vmt{};
167
168 void destroy();
169};
170} // namespace safetyhook
Allocator for allocating memory near target addresses.
Error
The error type returned by the allocate functions.
Definition allocator.hpp:80
A hook class that allows for hooking a single method in a VMT.
Definition vmt_hook.hpp:20
RetT fastcall(Args... args)
Calls the original method with the __fastcall calling convention.
Definition vmt_hook.hpp:77
RetT stdcall(Args... args)
Calls the original method with the __stdcall calling convention.
Definition vmt_hook.hpp:68
T original() const
Gets the original method pointer.
Definition vmt_hook.hpp:33
RetT ccall(Args... args)
Calls the original method with the __cdecl calling convention.
Definition vmt_hook.hpp:50
RetT thiscall(Args... args)
Calls the original method with the __thiscall calling convention.
Definition vmt_hook.hpp:59
void reset()
Removes the hook.
RetT call(Args... args)
Calls the original method.
Definition vmt_hook.hpp:41
A hook class that copies an entire VMT for a given object and replaces it.
Definition vmt_hook.hpp:95
static std::expected< VmtHook, Error > create(void *object)
Creates a new VmtHook object. Will clone the VMT of the given object and replace it.
void reset()
Removes the hook from all objects.
void remove(void *object)
Removes the hook.
void apply(void *object)
Applies the hook.
std::expected< VmHook, Error > hook_method(size_t index, T new_function)
Hooks a method in the VMT.
Definition vmt_hook.hpp:147
Error type for VmtHook.
Definition vmt_hook.hpp:98
enum safetyhook::VmtHook::Error::@156353032152303166214276355163047263003320035063 type
The type of error.
Allocator::Error allocator_error
Allocator error information.
Definition vmt_hook.hpp:106
static Error bad_allocation(Allocator::Error err)
Create a BAD_ALLOCATION error.
Definition vmt_hook.hpp:112
@ BAD_ALLOCATION
An error occurred while allocating memory.
Definition vmt_hook.hpp:101