10#include "ll/api/base/CompilerPredefine.h"
11#include "ll/api/base/Concepts.h"
12#include "ll/api/base/Macro.h"
13#include "ll/api/memory/Memory.h"
14#include "ll/api/reflection/TypeName.h"
15#include "ll/api/thread/GlobalThreadPauser.h"
22template <
class T,
class Ret,
class... Args>
33template <
class T,
class Ret,
class... Args>
35 using type = Ret (T::*)(Args...)
const;
39using AddConstAtMemberFunT =
typename AddConstAtMemberFun<T>::type;
45enum class HookPriority :
int {
53enum RegisterSaveOptions {
59 SaveAll = SaveR10 | SaveR11 | SaveXmm4 | SaveXmm5
62LLNDAPI
bool shouldHookSuspendThreads();
65hook(FuncPtr target, FuncPtr detour, FuncPtr* originalFunc, HookPriority priority,
bool suspendThreads =
true);
70 FuncPtr* originalFunc,
71 HookPriority priority,
72 RegisterSaveOptions options,
76LLAPI
bool unhook(FuncPtr target, FuncPtr detour,
bool suspendThreads =
true);
78LLAPI
bool hookOptions(FuncPtr target, RegisterSaveOptions options,
bool replace =
true,
bool suspendThreads =
true);
81concept FuncPtrType = std::is_function_v<std::remove_pointer_t<T>> || std::is_member_function_pointer_v<T>;
83template <FuncPtrType T>
84constexpr FuncPtr resolveIdentifier(T identifier) {
85 return toFuncPtr(identifier);
89constexpr FuncPtr resolveIdentifier(
SignatureView identifier) {
90 return identifier.resolve();
94constexpr FuncPtr resolveIdentifier(SymbolView identifier) {
95 return identifier.resolve();
99constexpr FuncPtr resolveIdentifier(uintptr_t address) {
100 return toFuncPtr(address);
104constexpr uintptr_t unchecked(T identifier) {
105 return reinterpret_cast<uintptr_t
>(toFuncPtr(identifier));
108template <
class T, auto>
109 requires(!std::is_member_function_pointer_v<T>)
110consteval bool virtualDetector()
noexcept {
113using ::ll::internal::virtualDetector;
115template <
class... Ts>
119 std::optional<thread::GlobalThreadPauser> pauser;
120 if (shouldHookSuspendThreads()) {
123 (((++Ts::_AutoHookCount == 1) ? Ts::hook(
false) : 0), ...);
125 static void unhook() {
126 std::optional<thread::GlobalThreadPauser> pauser;
127 if (shouldHookSuspendThreads()) {
130 (((--Ts::_AutoHookCount == 0) ? Ts::unhook(
false) : 0), ...);
136 if (
this != std::addressof(other)) {
137 ((++Ts::_AutoHookCount), ...);
149#define LL_HOOK_IMPL(REGISTER, FUNC_PTR, STATIC, CALL, DEF_TYPE, TYPE, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, ...) \
150 struct DEF_TYPE : public TYPE { \
151 inline static ::std::atomic_uint _AutoHookCount{}; \
154 using _FuncPtr = ::ll::memory::FuncPtr; \
155 using HookPriority = ::ll::memory::HookPriority; \
156 using RegisterSaveOptions = ll::memory::RegisterSaveOptions; \
157 using _RawFuncType = RET_TYPE FUNC_PTR(__VA_ARGS__); \
158 using _RawConstFuncType = ::ll::memory::AddConstAtMemberFunT<_RawFuncType>; \
161 struct _ConstDetector { \
162 [[maybe_unused]] static constexpr bool value = false; \
163 explicit constexpr _ConstDetector(T) {} \
166 [[maybe_unused]] _ConstDetector(T) -> _ConstDetector<T>; \
167 [[maybe_unused]] _ConstDetector(_RawFuncType) -> _ConstDetector<_RawFuncType>; \
169 struct _ConstDetector<_RawConstFuncType> { \
170 [[maybe_unused]] static constexpr bool value = true; \
171 explicit constexpr _ConstDetector(_RawConstFuncType) {} \
173 template <class T = _RawFuncType, std::enable_if_t<std::is_member_function_pointer_v<T>, int> = 0> \
174 [[maybe_unused]] _ConstDetector(_RawConstFuncType) -> _ConstDetector<_RawConstFuncType>; \
176 static constexpr bool _IsConstMemberFunction = decltype(_ConstDetector{IDENTIFIER})::value; \
178 using _OriginFuncType = ::std::conditional_t<_IsConstMemberFunction, _RawConstFuncType, _RawFuncType>; \
180 inline static _FuncPtr _HookTarget{}; \
181 inline static _OriginFuncType _OriginalFunc{}; \
184 static consteval void _Detector() { \
185 if constexpr (requires { ::ll::memory::virtualDetector<T, IDENTIFIER>(); }) { \
186 if constexpr (::ll::memory::virtualDetector<T, IDENTIFIER>()) { \
188 ::ll::traits::always_false<T>, \
189 #IDENTIFIER " is a virtual function, you need use prefix $ workaround to hook it." \
197 requires(::std::is_polymorphic_v<TYPE> && ::std::is_base_of_v<T, TYPE>) \
198 [[nodiscard]] TYPE* thisFor() { \
199 return static_cast<decltype(this)>(reinterpret_cast<T*>(this)); \
201 template <class... Args> \
202 STATIC RET_TYPE origin(Args&&... params) { \
203 return CALL(::std::forward<Args>(params)...); \
206 STATIC RET_TYPE detour(__VA_ARGS__); \
208 static int hook(bool suspendThreads = true) { \
209 _Detector<_OriginFuncType>(); \
210 if (!_HookTarget) _HookTarget = ::ll::memory::resolveIdentifier<_OriginFuncType>(IDENTIFIER); \
211 return ::ll::memory::hookEx( \
213 ::ll::memory::toFuncPtr(&DEF_TYPE::detour), \
214 reinterpret_cast<_FuncPtr*>(&_OriginalFunc), \
221 static bool unhook(bool suspendThreads = true) { \
222 return ::ll::memory::unhook(_HookTarget, ::ll::memory::toFuncPtr(&DEF_TYPE::detour), suspendThreads); \
226 RET_TYPE DEF_TYPE::detour(__VA_ARGS__)
228#define LL_AUTO_REG_HOOK_IMPL(FUNC_PTR, STATIC, CALL, DEF_TYPE, ...) \
229 LL_VA_EXPAND(LL_HOOK_IMPL( \
230 inline ::ll::memory::HookRegistrar<DEF_TYPE> DEF_TYPE##AutoRegister, \
238#define LL_MANUAL_REG_HOOK_IMPL(...) LL_VA_EXPAND(LL_HOOK_IMPL(, __VA_ARGS__))
240#define LL_STATIC_HOOK_IMPL(...) LL_VA_EXPAND(LL_MANUAL_REG_HOOK_IMPL((*), static, _OriginalFunc, __VA_ARGS__))
242#define LL_AUTO_STATIC_HOOK_IMPL(...) LL_VA_EXPAND(LL_AUTO_REG_HOOK_IMPL((*), static, _OriginalFunc, __VA_ARGS__))
244#define LL_INSTANCE_HOOK_IMPL(DEF_TYPE, TYPE, ...) \
245 LL_VA_EXPAND(LL_MANUAL_REG_HOOK_IMPL((TYPE::*), , (this->*_OriginalFunc), DEF_TYPE, TYPE, __VA_ARGS__))
247#define LL_AUTO_INSTANCE_HOOK_IMPL(DEF_TYPE, TYPE, ...) \
248 LL_VA_EXPAND(LL_AUTO_REG_HOOK_IMPL((TYPE::*), , (this->*_OriginalFunc), DEF_TYPE, TYPE, __VA_ARGS__))
261#define LL_TYPE_STATIC_HOOK(DEF_TYPE, PRIORITY, TYPE, IDENTIFIER, RET_TYPE, ...) \
262 LL_VA_EXPAND(LL_STATIC_HOOK_IMPL( \
266 RegisterSaveOptions::SaveNone, \
282#define LL_STATIC_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...) \
283 LL_VA_EXPAND(LL_STATIC_HOOK_IMPL( \
285 ::ll::memory::Hook, \
287 RegisterSaveOptions::SaveNone, \
298#define LL_AUTO_TYPE_STATIC_HOOK(DEF_TYPE, PRIORITY, TYPE, IDENTIFIER, RET_TYPE, ...) \
299 LL_VA_EXPAND(LL_AUTO_STATIC_HOOK_IMPL( \
303 RegisterSaveOptions::SaveNone, \
314#define LL_AUTO_STATIC_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...) \
315 LL_VA_EXPAND(LL_AUTO_STATIC_HOOK_IMPL( \
317 ::ll::memory::Hook, \
319 RegisterSaveOptions::SaveNone, \
336#define LL_TYPE_INSTANCE_HOOK(DEF_TYPE, PRIORITY, TYPE, IDENTIFIER, RET_TYPE, ...) \
337 LL_VA_EXPAND(LL_INSTANCE_HOOK_IMPL( \
341 RegisterSaveOptions::SaveNone, \
357#define LL_INSTANCE_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...) \
358 LL_VA_EXPAND(LL_INSTANCE_HOOK_IMPL( \
360 ::ll::memory::Hook, \
362 RegisterSaveOptions::SaveNone, \
373#define LL_AUTO_TYPE_INSTANCE_HOOK(DEF_TYPE, PRIORITY, TYPE, IDENTIFIER, RET_TYPE, ...) \
374 LL_VA_EXPAND(LL_AUTO_INSTANCE_HOOK_IMPL( \
378 RegisterSaveOptions::SaveNone, \
389#define LL_AUTO_INSTANCE_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...) \
390 LL_VA_EXPAND(LL_AUTO_INSTANCE_HOOK_IMPL( \
392 ::ll::memory::Hook, \
394 RegisterSaveOptions::SaveNone, \
412#define LL_TYPE_STATIC_HOOK_EX(DEF_TYPE, PRIORITY, OPTIONS, TYPE, IDENTIFIER, RET_TYPE, ...) \
413 LL_VA_EXPAND(LL_STATIC_HOOK_IMPL(DEF_TYPE, TYPE, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, __VA_ARGS__))
426#define LL_STATIC_HOOK_EX(DEF_TYPE, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, ...) \
428 LL_STATIC_HOOK_IMPL(DEF_TYPE, ::ll::memory::Hook, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, __VA_ARGS__) \
436#define LL_AUTO_TYPE_STATIC_HOOK_EX(DEF_TYPE, PRIORITY, OPTIONS, TYPE, IDENTIFIER, RET_TYPE, ...) \
437 LL_VA_EXPAND(LL_AUTO_STATIC_HOOK_IMPL(DEF_TYPE, TYPE, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, __VA_ARGS__))
444#define LL_AUTO_STATIC_HOOK_EX(DEF_TYPE, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, ...) \
446 LL_AUTO_STATIC_HOOK_IMPL(DEF_TYPE, ::ll::memory::Hook, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, __VA_ARGS__) \
461#define LL_TYPE_INSTANCE_HOOK_EX(DEF_TYPE, PRIORITY, OPTIONS, TYPE, IDENTIFIER, RET_TYPE, ...) \
462 LL_VA_EXPAND(LL_INSTANCE_HOOK_IMPL(DEF_TYPE, TYPE, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, __VA_ARGS__))
475#define LL_INSTANCE_HOOK_EX(DEF_TYPE, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, ...) \
477 LL_INSTANCE_HOOK_IMPL(DEF_TYPE, ::ll::memory::Hook, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, __VA_ARGS__) \
485#define LL_AUTO_TYPE_INSTANCE_HOOK_EX(DEF_TYPE, PRIORITY, OPTIONS, TYPE, IDENTIFIER, RET_TYPE, ...) \
486 LL_VA_EXPAND(LL_AUTO_INSTANCE_HOOK_IMPL(DEF_TYPE, TYPE, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, __VA_ARGS__))
493#define LL_AUTO_INSTANCE_HOOK_EX(DEF_TYPE, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, ...) \
495 LL_AUTO_INSTANCE_HOOK_IMPL(DEF_TYPE, ::ll::memory::Hook, PRIORITY, OPTIONS, IDENTIFIER, RET_TYPE, __VA_ARGS__) \
Definition Signature.h:48