#pragma once #include "nt.hpp" #define HOOK_JUMP true #define HOOK_CALL false namespace utils { class hook final { public: class signature final { public: struct container final { const char* signature; const char* mask; std::function callback; }; signature(void* start, const size_t length) : start_(start), length_(length) { } signature(const DWORD start, const size_t length) : signature(reinterpret_cast(start), length) { } signature() : signature(0x400000, 0x800000) { } void process(); void add(const container& container); private: void* start_; size_t length_; std::vector signatures_; }; class detour { public: detour() = default; detour(void* place, void* target); detour(size_t place, void* target); ~detour(); detour(detour&& other) noexcept { this->operator=(std::move(other)); } detour& operator=(detour&& other) noexcept { if (this != &other) { this->~detour(); this->place_ = other.place_; this->original_ = other.original_; other.place_ = nullptr; other.original_ = nullptr; } return *this; } detour(const detour&) = delete; detour& operator=(const detour&) = delete; void enable() const; void disable() const; void create(void* place, void* target); void create(size_t place, void* target); void clear(); template T* get() const { return static_cast(this->get_original()); } template T invoke(Args ... args) { return static_cast(this->get_original())(args...); } [[nodiscard]] void* get_original() const; private: void* place_{}; void* original_{}; }; hook() : initialized_(false), installed_(false), place_(nullptr), stub_(nullptr), original_(nullptr), use_jump_(false), protection_(0) { ZeroMemory(this->buffer_, sizeof(this->buffer_)); } hook(void* place, void* stub, const bool use_jump = true) : hook() { this->initialize(place, stub, use_jump); } hook(void* place, void (*stub)(), const bool use_jump = true) : hook( place, reinterpret_cast(stub), use_jump) { } hook(const DWORD place, void* stub, const bool use_jump = true) : hook( reinterpret_cast(place), stub, use_jump) { } hook(const DWORD place, const DWORD stub, const bool use_jump = true) : hook( reinterpret_cast(place), reinterpret_cast(stub), use_jump) { } hook(const DWORD place, void (*stub)(), const bool use_jump = true) : hook( reinterpret_cast(place), reinterpret_cast(stub), use_jump) { } hook(const hook&) = delete; hook(const hook&&) = delete; ~hook(); hook* initialize(void* place, void* stub, bool use_jump = true); hook* initialize(DWORD place, void* stub, bool use_jump = true); hook* initialize(DWORD place, void (*stub)(), bool use_jump = true); // For lambdas hook* install(bool unprotect = true, bool keep_unprotected = false); hook* uninstall(bool unprotect = true); void* get_address() const; void* get_original() const; void quick(); static bool iat(nt::library module, const std::string& target_module, const std::string& process, void* stub); static void nop(void* place, size_t length); static void nop(DWORD place, size_t length); template static void set(void* place, T value) { DWORD old_protect; VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect); *static_cast(place) = value; VirtualProtect(place, sizeof(T), old_protect, &old_protect); FlushInstructionCache(GetCurrentProcess(), place, sizeof(T)); } template static void set(const DWORD place, T value) { return set(reinterpret_cast(place), value); } template static T invoke(size_t func, Args ... args) { return reinterpret_cast(func)(args...); } template static T invoke(void* func, Args ... args) { return static_cast(func)(args...); } private: bool initialized_; bool installed_; void* place_; void* stub_; void* original_; char buffer_[5]{}; bool use_jump_; DWORD protection_; std::mutex state_mutex_; }; }