#pragma once #include "signature.hpp" #include #include using namespace asmjit::x86; namespace utils::hook { class assembler : public Assembler { public: using Assembler::Assembler; using Assembler::call; using Assembler::jmp; void pushad64(); void popad64(); void prepare_stack_for_call(); void restore_stack_after_call(); template void call_aligned(T&& target) { this->prepare_stack_for_call(); this->call(std::forward(target)); this->restore_stack_after_call(); } asmjit::Error call(void* target); asmjit::Error jmp(void* target); }; 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_{}; }; bool iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub); void nop(void* place, size_t length); void nop(size_t place, size_t length); void copy(void* place, const void* data, size_t length); void copy(size_t place, const void* data, size_t length); bool is_relatively_far(const void* pointer, const void* data, int offset = 5); void call(void* pointer, void* data); void call(size_t pointer, void* data); void call(size_t pointer, size_t data); void jump(void* pointer, void* data, bool use_far = false); void jump(size_t pointer, void* data, bool use_far = false); void jump(size_t pointer, size_t data, bool use_far = false); void* assemble(const std::function& asm_function); void inject(void* pointer, const void* data); void inject(size_t pointer, const void* data); template T extract(void* address) { auto* const data = static_cast(address); const auto offset = *reinterpret_cast(data); return reinterpret_cast(data + offset + 4); } void* follow_branch(void* address); 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 size_t 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...); } }