#pragma once namespace utils::hook { 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_{}; }; 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 inject(void* pointer, const void* data); void inject(size_t pointer, const void* data); template T extract(void* address) { const auto 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...); } }