SafetyHook: C:/M/B/src/safetyhook-0.6.5/include/safetyhook/inline_hook.hpp Source File

SafetyHook

Loading...
Searching...
No Matches
inline_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 <memory>
10#include <mutex>
11#include <utility>
12#include <vector>
13#else
14import std.compat;
15#endif
16
17#include "safetyhook/allocator.hpp"
18#include "safetyhook/common.hpp"
19#include "safetyhook/utility.hpp"
20
21namespace safetyhook {
23 class SAFETYHOOK_API InlineHook final {
24public:
26 struct Error {
28 enum : uint8_t {
29 BAD_ALLOCATION,
30 FAILED_TO_DECODE_INSTRUCTION,
31 SHORT_JUMP_IN_TRAMPOLINE,
32 IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE,
33 UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE,
34 FAILED_TO_UNPROTECT,
35 NOT_ENOUGH_SPACE,
36 } type;
37
39 union {
40 Allocator::Error allocator_error;
41 uint8_t* ip;
42 };
43
47 [[nodiscard]] static Error bad_allocation(Allocator::Error err) {
48 Error error{};
49 error.type = BAD_ALLOCATION;
50 error.allocator_error = err;
51 return error;
52 }
53
57 [[nodiscard]] static Error failed_to_decode_instruction(uint8_t* ip) {
58 Error error{};
59 error.type = FAILED_TO_DECODE_INSTRUCTION;
60 error.ip = ip;
61 return error;
62 }
63
67 [[nodiscard]] static Error short_jump_in_trampoline(uint8_t* ip) {
68 Error error{};
69 error.type = SHORT_JUMP_IN_TRAMPOLINE;
70 error.ip = ip;
71 return error;
72 }
73
77 [[nodiscard]] static Error ip_relative_instruction_out_of_range(uint8_t* ip) {
78 Error error{};
79 error.type = IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE;
80 error.ip = ip;
81 return error;
82 }
83
87 [[nodiscard]] static Error unsupported_instruction_in_trampoline(uint8_t* ip) {
88 Error error{};
89 error.type = UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE;
90 error.ip = ip;
91 return error;
92 }
93
97 [[nodiscard]] static Error failed_to_unprotect(uint8_t* ip) {
98 Error error{};
99 error.type = FAILED_TO_UNPROTECT;
100 error.ip = ip;
101 return error;
102 }
103
107 [[nodiscard]] static Error not_enough_space(uint8_t* ip) {
108 Error error{};
109 error.type = NOT_ENOUGH_SPACE;
110 error.ip = ip;
111 return error;
112 }
113 };
114
116 enum Flags : int {
117 Default = 0,
118 StartDisabled = 1 << 0,
119 };
120
128 [[nodiscard]] static std::expected<InlineHook, Error> create(
129 void* target, void* destination, Flags flags = Default);
130
138 template <typename T, typename U>
139 [[nodiscard]] static std::expected<InlineHook, Error> create(T target, U destination, Flags flags = Default) {
140 return create(reinterpret_cast<void*>(target), reinterpret_cast<void*>(destination), flags);
141 }
142
150 [[nodiscard]] static std::expected<InlineHook, Error> create(
151 const std::shared_ptr<Allocator>& allocator, void* target, void* destination, Flags flags = Default);
152
160 template <typename T, typename U>
161 [[nodiscard]] static std::expected<InlineHook, Error> create(
162 const std::shared_ptr<Allocator>& allocator, T target, U destination, Flags flags = Default) {
163 return create(allocator, reinterpret_cast<void*>(target), reinterpret_cast<void*>(destination), flags);
164 }
165
166 InlineHook() = default;
167 InlineHook(const InlineHook&) = delete;
168 InlineHook(InlineHook&& other) noexcept;
169 InlineHook& operator=(const InlineHook&) = delete;
170 InlineHook& operator=(InlineHook&& other) noexcept;
171 ~InlineHook();
172
176 void reset();
177
180 [[nodiscard]] uint8_t* target() const { return m_target; }
181
184 [[nodiscard]] uintptr_t target_address() const { return reinterpret_cast<uintptr_t>(m_target); }
185
188 [[nodiscard]] uint8_t* destination() const { return m_destination; }
189
192 [[nodiscard]] uintptr_t destination_address() const { return reinterpret_cast<uintptr_t>(m_destination); }
193
196 [[nodiscard]] const Allocation& trampoline() const { return m_trampoline; }
197
200 explicit operator bool() const { return static_cast<bool>(m_trampoline); }
201
205 template <typename T> [[nodiscard]] T original() const { return reinterpret_cast<T>(m_trampoline.address()); }
206
209 [[nodiscard]] const auto& original_bytes() const { return m_original_bytes; }
210
217 template <typename RetT = void, typename... Args> RetT call(Args... args) {
218 std::scoped_lock lock{m_mutex};
219 return m_trampoline ? original<RetT (*)(Args...)>()(args...) : RetT();
220 }
221
228 template <typename RetT = void, typename... Args> RetT ccall(Args... args) {
229 std::scoped_lock lock{m_mutex};
230 return m_trampoline ? original<RetT(SAFETYHOOK_CCALL*)(Args...)>()(args...) : RetT();
231 }
232
239 template <typename RetT = void, typename... Args> RetT thiscall(Args... args) {
240 std::scoped_lock lock{m_mutex};
241 return m_trampoline ? original<RetT(SAFETYHOOK_THISCALL*)(Args...)>()(args...) : RetT();
242 }
243
250 template <typename RetT = void, typename... Args> RetT stdcall(Args... args) {
251 std::scoped_lock lock{m_mutex};
252 return m_trampoline ? original<RetT(SAFETYHOOK_STDCALL*)(Args...)>()(args...) : RetT();
253 }
254
261 template <typename RetT = void, typename... Args> RetT fastcall(Args... args) {
262 std::scoped_lock lock{m_mutex};
263 return m_trampoline ? original<RetT(SAFETYHOOK_FASTCALL*)(Args...)>()(args...) : RetT();
264 }
265
274 template <typename RetT = void, typename... Args> RetT unsafe_call(Args... args) {
275 return original<RetT (*)(Args...)>()(args...);
276 }
277
286 template <typename RetT = void, typename... Args> RetT unsafe_ccall(Args... args) {
287 return original<RetT(SAFETYHOOK_CCALL*)(Args...)>()(args...);
288 }
289
298 template <typename RetT = void, typename... Args> RetT unsafe_thiscall(Args... args) {
299 return original<RetT(SAFETYHOOK_THISCALL*)(Args...)>()(args...);
300 }
301
310 template <typename RetT = void, typename... Args> RetT unsafe_stdcall(Args... args) {
311 return original<RetT(SAFETYHOOK_STDCALL*)(Args...)>()(args...);
312 }
313
322 template <typename RetT = void, typename... Args> RetT unsafe_fastcall(Args... args) {
323 return original<RetT(SAFETYHOOK_FASTCALL*)(Args...)>()(args...);
324 }
325
327 [[nodiscard]] std::expected<void, Error> enable();
328
330 [[nodiscard]] std::expected<void, Error> disable();
331
333 [[nodiscard]] bool enabled() const { return m_enabled; }
334
335private:
336 friend class MidHook;
337
338 enum class Type {
339 Unset,
340 E9,
341 FF,
342 };
343
344 uint8_t* m_target{};
345 uint8_t* m_destination{};
346 Allocation m_trampoline{};
347 std::vector<uint8_t> m_original_bytes{};
348 uintptr_t m_trampoline_size{};
349 std::recursive_mutex m_mutex{};
350 bool m_enabled{};
351 Type m_type{Type::Unset};
352
353 std::expected<void, Error> setup(
354 const std::shared_ptr<Allocator>& allocator, uint8_t* target, uint8_t* destination);
355 std::expected<void, Error> e9_hook(const std::shared_ptr<Allocator>& allocator);
356
357#if SAFETYHOOK_ARCH_X86_64
358 std::expected<void, Error> ff_hook(const std::shared_ptr<Allocator>& allocator);
359#endif
360
361 void destroy();
362};
363} // namespace safetyhook
allocator.hpp
Allocator for allocating memory near target addresses.
safetyhook::Allocation
A memory allocation.
Definition allocator.hpp:22
safetyhook::Allocator::Error
Error
The error type returned by the allocate functions.
Definition allocator.hpp:80
safetyhook::InlineHook
An inline hook.
Definition inline_hook.hpp:23
safetyhook::InlineHook::stdcall
RetT stdcall(Args... args)
Calls the original function.
Definition inline_hook.hpp:250
safetyhook::InlineHook::unsafe_fastcall
RetT unsafe_fastcall(Args... args)
Calls the original function.
Definition inline_hook.hpp:322
safetyhook::InlineHook::enable
std::expected< void, Error > enable()
Enable the hook.
safetyhook::InlineHook::target
uint8_t * target() const
Get a pointer to the target.
Definition inline_hook.hpp:180
safetyhook::InlineHook::unsafe_thiscall
RetT unsafe_thiscall(Args... args)
Calls the original function.
Definition inline_hook.hpp:298
safetyhook::InlineHook::thiscall
RetT thiscall(Args... args)
Calls the original function.
Definition inline_hook.hpp:239
safetyhook::InlineHook::create
static std::expected< InlineHook, Error > create(T target, U destination, Flags flags=Default)
Create an inline hook.
Definition inline_hook.hpp:139
safetyhook::InlineHook::reset
void reset()
Reset the hook.
safetyhook::InlineHook::target_address
uintptr_t target_address() const
Get the target address.
Definition inline_hook.hpp:184
safetyhook::InlineHook::create
static std::expected< InlineHook, Error > create(void *target, void *destination, Flags flags=Default)
Create an inline hook.
safetyhook::InlineHook::unsafe_stdcall
RetT unsafe_stdcall(Args... args)
Calls the original function.
Definition inline_hook.hpp:310
safetyhook::InlineHook::fastcall
RetT fastcall(Args... args)
Calls the original function.
Definition inline_hook.hpp:261
safetyhook::InlineHook::create
static std::expected< InlineHook, Error > create(const std::shared_ptr< Allocator > &allocator, T target, U destination, Flags flags=Default)
Create an inline hook with a given Allocator.
Definition inline_hook.hpp:161
safetyhook::InlineHook::call
RetT call(Args... args)
Calls the original function.
Definition inline_hook.hpp:217
safetyhook::InlineHook::unsafe_call
RetT unsafe_call(Args... args)
Calls the original function.
Definition inline_hook.hpp:274
safetyhook::InlineHook::Flags
Flags
Flags for InlineHook.
Definition inline_hook.hpp:116
safetyhook::InlineHook::StartDisabled
@ StartDisabled
Start the hook disabled.
Definition inline_hook.hpp:118
safetyhook::InlineHook::Default
@ Default
Default flags.
Definition inline_hook.hpp:117
safetyhook::InlineHook::destination
uint8_t * destination() const
Get a pointer ot the destination.
Definition inline_hook.hpp:188
safetyhook::InlineHook::enabled
bool enabled() const
Check if the hook is enabled.
Definition inline_hook.hpp:333
safetyhook::InlineHook::ccall
RetT ccall(Args... args)
Calls the original function.
Definition inline_hook.hpp:228
safetyhook::InlineHook::disable
std::expected< void, Error > disable()
Disable the hook.
safetyhook::InlineHook::trampoline
const Allocation & trampoline() const
Get the trampoline Allocation.
Definition inline_hook.hpp:196
safetyhook::InlineHook::original
T original() const
Returns the address of the trampoline to call the original function.
Definition inline_hook.hpp:205
safetyhook::InlineHook::unsafe_ccall
RetT unsafe_ccall(Args... args)
Calls the original function.
Definition inline_hook.hpp:286
safetyhook::InlineHook::destination_address
uintptr_t destination_address() const
Get the destination address.
Definition inline_hook.hpp:192
safetyhook::InlineHook::original_bytes
const auto & original_bytes() const
Returns a vector containing the original bytes of the target function.
Definition inline_hook.hpp:209
safetyhook::InlineHook::create
static std::expected< InlineHook, Error > create(const std::shared_ptr< Allocator > &allocator, void *target, void *destination, Flags flags=Default)
Create an inline hook with a given Allocator.
safetyhook::MidHook
A mid function hook.
Definition mid_hook.hpp:25
InlineHook::Error
Error type for InlineHook.
Definition inline_hook.hpp:26
safetyhook::InlineHook::Error
Error type for InlineHook.
Definition inline_hook.hpp:26
safetyhook::InlineHook::Error::UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE
@ UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE
An unsupported instruction was found in the trampoline.
Definition inline_hook.hpp:33
safetyhook::InlineHook::Error::NOT_ENOUGH_SPACE
@ NOT_ENOUGH_SPACE
Not enough space to create the hook.
Definition inline_hook.hpp:35
safetyhook::InlineHook::Error::IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE
@ IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE
An IP-relative instruction is out of range.
Definition inline_hook.hpp:32
safetyhook::InlineHook::Error::FAILED_TO_UNPROTECT
@ FAILED_TO_UNPROTECT
Failed to unprotect memory.
Definition inline_hook.hpp:34
safetyhook::InlineHook::Error::FAILED_TO_DECODE_INSTRUCTION
@ FAILED_TO_DECODE_INSTRUCTION
Failed to decode an instruction.
Definition inline_hook.hpp:30
safetyhook::InlineHook::Error::SHORT_JUMP_IN_TRAMPOLINE
@ SHORT_JUMP_IN_TRAMPOLINE
The trampoline contains a short jump.
Definition inline_hook.hpp:31
safetyhook::InlineHook::Error::BAD_ALLOCATION
@ BAD_ALLOCATION
An error occurred when allocating memory.
Definition inline_hook.hpp:29
safetyhook::InlineHook::Error::ip
uint8_t * ip
IP of the problematic instruction.
Definition inline_hook.hpp:41
safetyhook::InlineHook::Error::unsupported_instruction_in_trampoline
static Error unsupported_instruction_in_trampoline(uint8_t *ip)
Create a UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE error.
Definition inline_hook.hpp:87
safetyhook::InlineHook::Error::short_jump_in_trampoline
static Error short_jump_in_trampoline(uint8_t *ip)
Create a SHORT_JUMP_IN_TRAMPOLINE error.
Definition inline_hook.hpp:67
safetyhook::InlineHook::Error::not_enough_space
static Error not_enough_space(uint8_t *ip)
Create a NOT_ENOUGH_SPACE error.
Definition inline_hook.hpp:107
safetyhook::InlineHook::Error::failed_to_decode_instruction
static Error failed_to_decode_instruction(uint8_t *ip)
Create a FAILED_TO_DECODE_INSTRUCTION error.
Definition inline_hook.hpp:57
safetyhook::InlineHook::Error::ip_relative_instruction_out_of_range
static Error ip_relative_instruction_out_of_range(uint8_t *ip)
Create a IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE error.
Definition inline_hook.hpp:77
safetyhook::InlineHook::Error::type
enum safetyhook::InlineHook::Error::@117140120162227036312220076232265130216375157224 type
The type of error.
safetyhook::InlineHook::Error::bad_allocation
static Error bad_allocation(Allocator::Error err)
Create a BAD_ALLOCATION error.
Definition inline_hook.hpp:47
safetyhook::InlineHook::Error::allocator_error
Allocator::Error allocator_error
Allocator error information.
Definition inline_hook.hpp:40
safetyhook::InlineHook::Error::failed_to_unprotect
static Error failed_to_unprotect(uint8_t *ip)
Create a FAILED_TO_UNPROTECT error.
Definition inline_hook.hpp:97