#pragma once #include #include #include #include #include #include "Global.h" #include "utils/Hash.h" // The core api of the hook function //__declspec(dllimport) int HookFunction(void* oldfunc, void** poutold, void* newfunc); // Used to get a server-defined specific function by name extern "C" { LIAPI int HookFunction(void* oldfunc, void** poutold, void* newfunc); LIAPI void* dlsym_real(char const* name); } extern std::vector dlsym_reverse(int addr); template RTN inline VirtualCall(void const* _this, uintptr_t off, Args... args) { return (*(RTN(**)(void const*, Args...))(*(uintptr_t*)_this + off))(_this, args...); } template inline T& dAccess(void* ptr) { return *(T*)(((uintptr_t)ptr) + off); } template inline T const& dAccess(void const* ptr) { return *(T*)(((uintptr_t)ptr) + off); } template inline T& dAccess(void* ptr, uintptr_t off) { return *(T*)(((uintptr_t)ptr) + off); } template inline const T& dAccess(void const* ptr, uintptr_t off) { return *(T*)(((uintptr_t)ptr) + off); } namespace mem { inline std::string ptrToStr(uintptr_t ptr) { std::ostringstream ss; ss << std::hex << ((UINT64)ptr) << std::endl; return ss.str(); } inline void* uintptrToPtr(uintptr_t ptr) { return (void*)ptr; } } // namespace mem #if _HAS_CXX20 template struct FixedString { char buf[N + 1]{}; constexpr FixedString(char const* s) { for (unsigned i = 0; i != N; ++i) buf[i] = s[i]; } constexpr operator char const*() const { return buf; } }; template FixedString(char const (&)[N]) -> FixedString; template __declspec(selectany) void* __dlsym_ptr_cache = dlsym_real(Fn); #define VA_EXPAND(...) __VA_ARGS__ template static inline auto __imp_Call() { return ((ret(*)(p...))(__dlsym_ptr_cache)); } template static inline auto __imp_Call_Sig() { return ((ret(*)(p...))((void*)ModUtils::FindSig(Fn))); } template static inline auto __imp_Call_Addr() { return ((ret(*)(p...))((void*)Fn)); } #define AddrCall(fn, ret, ...) (__imp_Call_Addr()) #define SigCall(fn, ret, ...) (__imp_Call_Sig()) #define AddrCall2(name, fn, ret, ...) (__imp_Call_Addr()) #define SigCall2(name, fn, ret, ...) (__imp_Call_Sig()) #define SymCall(fn, ret, ...) (__imp_Call()) #define SYM(fn) (__dlsym_ptr_cache) #define dlsym(xx) SYM(xx) #else template __declspec(selectany) void* __ptr_cache; template inline static void* dlsym_cache(const char* fn) { if (!__ptr_cache) { __ptr_cache = dlsym_real(fn); } return __ptr_cache; } #define VA_EXPAND(...) __VA_ARGS__ template static inline auto __imp_Call(const char* fn) { return ((ret(*)(p...))(dlsym_cache(fn))); } #define SymCall(fn, ret, ...) (__imp_Call(fn)) #define SYM(fn) (dlsym_cache(fn)) #define dlsym(xx) SYM(xx) #endif class THookRegister { public: THookRegister(void* address, void* hook, void** org) { auto ret = HookFunction(address, org, hook); if (ret != 0) { printf("FailedToHook: %p\n", address); } } THookRegister(char const* sym, void* hook, void** org) { auto found = dlsym_real(sym); if (found == nullptr) { printf("FailedToHook: %p\n", sym); } else { auto ret = HookFunction(found, org, hook); if (ret != 0) { printf("FailedToHook: %s\n", sym); } } } template THookRegister(const char* sym, T hook, void** org) { union { T a; void* b; } hookUnion; hookUnion.a = hook; THookRegister(sym, hookUnion.b, org); } template THookRegister(void* address, T hook, void** org) { union { T a; void* b; } hookUnion; hookUnion.a = hook; THookRegister(address, hookUnion.b, org); } }; #define VA_EXPAND(...) __VA_ARGS__ template struct THookTemplate; template extern THookRegister THookRegisterTemplate; #define _TInstanceHook(class_inh, pclass, iname, sym, ret, ...) \ template <> \ struct THookTemplate class_inh { \ typedef ret (THookTemplate::*original_type)(__VA_ARGS__); \ static original_type& _original() { \ static original_type storage; \ return storage; \ } \ template \ static ret original(pclass* _this, Params&&... params) { \ return (((THookTemplate*)_this)->*_original())(std::forward(params)...); \ } \ ret _hook(__VA_ARGS__); \ }; \ template <> \ static THookRegister THookRegisterTemplate{ \ sym, &THookTemplate::_hook, \ (void**)&THookTemplate::_original()}; \ ret THookTemplate::_hook(__VA_ARGS__) #define _TInstanceDefHook(iname, sym, ret, type, ...) \ _TInstanceHook( \ : public type, type, iname, sym, ret, VA_EXPAND(__VA_ARGS__)) #define _TInstanceNoDefHook(iname, sym, ret, ...) \ _TInstanceHook(, void, iname, sym, ret, VA_EXPAND(__VA_ARGS__)) #define _TStaticHook(pclass, iname, sym, ret, ...) \ template <> \ struct THookTemplate pclass { \ typedef ret (*original_type)(__VA_ARGS__); \ static original_type& _original() { \ static original_type storage; \ return storage; \ } \ template \ static ret original(Params&&... params) { \ return _original()(std::forward(params)...); \ } \ static ret _hook(__VA_ARGS__); \ }; \ template <> \ static THookRegister THookRegisterTemplate{ \ sym, &THookTemplate::_hook, \ (void**)&THookTemplate::_original()}; \ ret THookTemplate::_hook(__VA_ARGS__) #define _TStaticDefHook(iname, sym, ret, type, ...) \ _TStaticHook( \ : public type, iname, sym, ret, VA_EXPAND(__VA_ARGS__)) #define _TStaticNoDefHook(iname, sym, ret, ...) \ _TStaticHook(, iname, sym, ret, VA_EXPAND(__VA_ARGS__)) #define SHook2(iname, ret, sig, ...) _TStaticNoDefHook(iname, (void*)ModUtils::FindSig(sig), ret, VA_EXPAND(__VA_ARGS__)) #define SHook(ret, sig, ...) SHook2(sig, ret, sig, VA_EXPAND(__VA_ARGS__)) #define SStaticHook2(iname, ret, sig, type, ...) \ _TStaticDefHook(iname, (void*)ModUtils::FindSig(sig), ret, type, VA_EXPAND(__VA_ARGS__)) #define SStaticHook(ret, sig, type, ...) SStaticHook2(sig, ret, sig, type, VA_EXPAND(__VA_ARGS__)) #define SClasslessInstanceHook2(iname, ret, sig, ...) \ _TInstanceNoDefHook(iname, (void*)ModUtils::FindSig(sig), ret, VA_EXPAND(__VA_ARGS__)) #define SClasslessInstanceHook(ret, sig, ...) \ SClasslessInstanceHook2(sig, ret, sig, VA_EXPAND(__VA_ARGS__)) #define SInstanceHook2(iname, ret, sig, type, ...) \ _TInstanceDefHook(iname, (void*)ModUtils::FindSig(sig), ret, type, VA_EXPAND(__VA_ARGS__)) #define SInstanceHook(ret, sig, type, ...) \ SInstanceHook2(sig, ret, sig, type, VA_EXPAND(__VA_ARGS__)) #define AHook2(iname, ret, addr, ...) _TStaticNoDefHook(iname, mem::uintptrToPtr(addr), ret, VA_EXPAND(__VA_ARGS__)) #define AHook(ret, addr, ...) AHook2(std::to_string(addr), ret, addr, VA_EXPAND(__VA_ARGS__)) #define AStaticHook2(iname, ret, addr, type, ...) \ _TStaticDefHook(iname, mem::uintptrToPtr(addr), ret, type, VA_EXPAND(__VA_ARGS__)) #define AStaticHook(ret, addr, type, ...) AStaticHook2(std::to_string(addr), ret, addr, type, VA_EXPAND(__VA_ARGS__)) #define AClasslessInstanceHook2(iname, ret, addr, ...) \ _TInstanceNoDefHook(iname, mem::uintptrToPtr(addr), ret, VA_EXPAND(__VA_ARGS__)) #define AClasslessInstanceHook(ret, addr, ...) \ AClasslessInstanceHook2(std::to_string(addr), ret, addr, VA_EXPAND(__VA_ARGS__)) #define AInstanceHook2(iname, ret, addr, type, ...) \ _TInstanceDefHook(iname, mem::uintptrToPtr(addr), ret, type, VA_EXPAND(__VA_ARGS__)) #define AInstanceHook(ret, addr, type, ...) \ AInstanceHook2(std::to_string(addr), ret, addr, type, VA_EXPAND(__VA_ARGS__)) #define THook2(iname, ret, sym, ...) _TStaticNoDefHook(iname, sym, ret, VA_EXPAND(__VA_ARGS__)) #define THook(ret, sym, ...) THook2(sym, ret, sym, VA_EXPAND(__VA_ARGS__)) #define TStaticHook2(iname, ret, sym, type, ...) \ _TStaticDefHook(iname, sym, ret, type, VA_EXPAND(__VA_ARGS__)) #define TStaticHook(ret, sym, type, ...) TStaticHook2(sym, ret, sym, type, VA_EXPAND(__VA_ARGS__)) #define TClasslessInstanceHook2(iname, ret, sym, ...) \ _TInstanceNoDefHook(iname, sym, ret, VA_EXPAND(__VA_ARGS__)) #define TClasslessInstanceHook(ret, sym, ...) \ TClasslessInstanceHook2(sym, ret, sym, VA_EXPAND(__VA_ARGS__)) #define TInstanceHook2(iname, ret, sym, type, ...) \ _TInstanceDefHook(iname, sym, ret, type, VA_EXPAND(__VA_ARGS__)) #define TInstanceHook(ret, sym, type, ...) \ TInstanceHook2(sym, ret, sym, type, VA_EXPAND(__VA_ARGS__))