diff --git a/format.ps1 b/format.ps1 index ffb2fc6..4df26f9 100644 --- a/format.ps1 +++ b/format.ps1 @@ -1,4 +1,4 @@ -Get-ChildItem -Path .\src, .\include, .\tests -Include *.hpp, *.cpp -Recurse | +Get-ChildItem -Path .\src, .\include, .\tests, .\unittest -Include *.hpp, *.cpp -Recurse | ForEach-Object { Write-Output $_.FullName &clang-format -i -style=file $_.FullName diff --git a/include/safetyhook/allocator.hpp b/include/safetyhook/allocator.hpp index 4bd6219..fb88366 100644 --- a/include/safetyhook/allocator.hpp +++ b/include/safetyhook/allocator.hpp @@ -26,9 +26,13 @@ class Allocation final { /// @note This is called automatically when the Allocation object is destroyed. void free(); + /// @brief Returns a pointer to the data of the allocation. + /// @return Pointer to the data of the allocation. + [[nodiscard]] uint8_t* data() const noexcept { return m_address; } + /// @brief Returns the address of the allocation. /// @return The address of the allocation. - [[nodiscard]] uintptr_t address() const noexcept { return m_address; } + [[nodiscard]] uintptr_t address() const noexcept { return (uintptr_t)m_address; } /// @brief Returns the size of the allocation. /// @return The size of the allocation. @@ -36,16 +40,16 @@ class Allocation final { /// @brief Tests if the allocation is valid. /// @return True if the allocation is valid, false otherwise. - explicit operator bool() const noexcept { return m_address != 0 && m_size != 0; } + explicit operator bool() const noexcept { return m_address != nullptr && m_size != 0; } protected: friend Allocator; - Allocation(std::shared_ptr allocator, uintptr_t address, size_t size) noexcept; + Allocation(std::shared_ptr allocator, uint8_t* address, size_t size) noexcept; private: std::shared_ptr m_allocator{}; - uintptr_t m_address{}; + uint8_t* m_address{}; size_t m_size{}; }; @@ -78,27 +82,27 @@ class Allocator final : public std::enable_shared_from_this { [[nodiscard]] std::expected allocate(size_t size); /// @brief Allocates memory near a target address. - /// @param desired_address The target address. + /// @param desired_addresses The target address. /// @param size The size of the allocation. /// @param max_distance The maximum distance from the target address. /// @return The Allocation or an Allocator::Error if the allocation failed. [[nodiscard]] std::expected allocate_near( - const std::vector& desired_addresses, size_t size, size_t max_distance = 0x7FFF'FFFF); + const std::vector& desired_addresses, size_t size, size_t max_distance = 0x7FFF'FFFF); protected: friend Allocation; - void free(uintptr_t address, size_t size); + void free(uint8_t* address, size_t size); private: struct FreeNode { std::unique_ptr next{}; - uintptr_t start{}; - uintptr_t end{}; + uint8_t* start{}; + uint8_t* end{}; }; struct Memory { - uintptr_t address{}; + uint8_t* address{}; size_t size{}; std::unique_ptr freelist{}; @@ -111,13 +115,13 @@ class Allocator final : public std::enable_shared_from_this { Allocator() = default; [[nodiscard]] std::expected internal_allocate_near( - const std::vector& desired_addresses, size_t size, size_t max_distance = 0x7FFF'FFFF); - void internal_free(uintptr_t address, size_t size); + const std::vector& desired_addresses, size_t size, size_t max_distance = 0x7FFF'FFFF); + void internal_free(uint8_t* address, size_t size); static void combine_adjacent_freenodes(Memory& memory); - [[nodiscard]] static std::expected allocate_nearby_memory( - const std::vector& desired_addresses, size_t size, size_t max_distance); + [[nodiscard]] static std::expected allocate_nearby_memory( + const std::vector& desired_addresses, size_t size, size_t max_distance); [[nodiscard]] static bool in_range( - uintptr_t address, const std::vector& desired_addresses, size_t max_distance); + uint8_t* address, const std::vector& desired_addresses, size_t max_distance); }; } // namespace safetyhook \ No newline at end of file diff --git a/include/safetyhook/easy.hpp b/include/safetyhook/easy.hpp index 2583c58..93d1c63 100644 --- a/include/safetyhook/easy.hpp +++ b/include/safetyhook/easy.hpp @@ -11,23 +11,33 @@ namespace safetyhook { /// @param target The address of the function to hook. /// @param destination The address of the destination function. /// @return The InlineHook object. -InlineHook create_inline(void* target, void* destination); +[[nodiscard]] InlineHook create_inline(void* target, void* destination); /// @brief Easy to use API for creating an InlineHook. +/// @tparam T The type of the function to hook. /// @param target The address of the function to hook. /// @param destination The address of the destination function. /// @return The InlineHook object. -InlineHook create_inline(uintptr_t target, uintptr_t destination); +template + requires std::is_function_v +[[nodiscard]] InlineHook create_inline(T* target, T* destination) { + return create_inline(reinterpret_cast(target), reinterpret_cast(destination)); +} /// @brief Easy to use API for creating a MidHook. /// @param target the address of the function to hook. /// @param destination The destination function. /// @return The MidHook object. -MidHook create_mid(void* target, MidHookFn destination); +[[nodiscard]] MidHook create_mid(void* target, MidHookFn destination); /// @brief Easy to use API for creating a MidHook. +/// @tparam T The type of the function to hook. /// @param target the address of the function to hook. /// @param destination The destination function. /// @return The MidHook object. -MidHook create_mid(uintptr_t target, MidHookFn destination); +template + requires std::is_function_v +[[nodiscard]] MidHook create_mid(T* target, MidHookFn destination) { + return create_mid(reinterpret_cast(target), destination); +} } // namespace safetyhook \ No newline at end of file diff --git a/include/safetyhook/inline_hook.hpp b/include/safetyhook/inline_hook.hpp index 364da57..f66b87f 100644 --- a/include/safetyhook/inline_hook.hpp +++ b/include/safetyhook/inline_hook.hpp @@ -30,7 +30,7 @@ class InlineHook final { /// @brief Extra information about the error. union { Allocator::Error allocator_error; ///< Allocator error information. - uintptr_t ip; ///< IP of the problematic instruction. + uint8_t* ip; ///< IP of the problematic instruction. }; /// @brief Create a BAD_ALLOCATION error. @@ -43,28 +43,28 @@ class InlineHook final { /// @brief Create a FAILED_TO_DECODE_INSTRUCTION error. /// @param ip The IP of the problematic instruction. /// @return The new FAILED_TO_DECODE_INSTRUCTION error. - [[nodiscard]] static Error failed_to_decode_instruction(uintptr_t ip) { + [[nodiscard]] static Error failed_to_decode_instruction(uint8_t* ip) { return {.type = FAILED_TO_DECODE_INSTRUCTION, .ip = ip}; } /// @brief Create a SHORT_JUMP_IN_TRAMPOLINE error. /// @param ip The IP of the problematic instruction. /// @return The new SHORT_JUMP_IN_TRAMPOLINE error. - [[nodiscard]] static Error short_jump_in_trampoline(uintptr_t ip) { + [[nodiscard]] static Error short_jump_in_trampoline(uint8_t* ip) { return {.type = SHORT_JUMP_IN_TRAMPOLINE, .ip = ip}; } /// @brief Create a IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE error. /// @param ip The IP of the problematic instruction. /// @return The new IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE error. - [[nodiscard]] static Error ip_relative_instruction_out_of_range(uintptr_t ip) { + [[nodiscard]] static Error ip_relative_instruction_out_of_range(uint8_t* ip) { return {.type = IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE, .ip = ip}; } /// @brief Create a UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE error. /// @param ip The IP of the problematic instruction. /// @return The new UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE error. - [[nodiscard]] static Error unsupported_instruction_in_trampoline(uintptr_t ip) { + [[nodiscard]] static Error unsupported_instruction_in_trampoline(uint8_t* ip) { return {.type = UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE, .ip = ip}; } }; @@ -78,12 +78,17 @@ class InlineHook final { [[nodiscard]] static std::expected create(void* target, void* destination); /// @brief Create an inline hook. + /// @tparam T The type of the function to hook. /// @param target The address of the function to hook. /// @param destination The destination address. /// @return The InlineHook or an InlineHook::Error if an error occurred. /// @note This will use the default global Allocator. /// @note If you don't care about error handling, use the easy API (safetyhook::create_inline). - [[nodiscard]] static std::expected create(uintptr_t target, uintptr_t destination); + template + requires std::is_function_v + [[nodiscard]] static std::expected create(T* target, T* destination) { + return create(reinterpret_cast(target), reinterpret_cast(destination)); + } /// @brief Create an inline hook with a given Allocator. /// @param allocator The allocator to use. @@ -95,13 +100,18 @@ class InlineHook final { const std::shared_ptr& allocator, void* target, void* destination); /// @brief Create an inline hook with a given Allocator. + /// @tparam T The type of the function to hook. /// @param allocator The allocator to use. /// @param target The address of the function to hook. /// @param destination The destination address. /// @return The InlineHook or an InlineHook::Error if an error occurred. /// @note If you don't care about error handling, use the easy API (safetyhook::create_inline). + template + requires std::is_function_v [[nodiscard]] static std::expected create( - const std::shared_ptr& allocator, uintptr_t target, uintptr_t destination); + const std::shared_ptr& allocator, T* target, T* destination) { + return create(allocator, reinterpret_cast(target), reinterpret_cast(destination)); + } InlineHook() = default; InlineHook(const InlineHook&) = delete; @@ -115,13 +125,21 @@ class InlineHook final { /// @note This is called automatically in the destructor. void reset(); + /// @brief Get a pointer to the target. + /// @return A pointer to the target. + [[nodiscard]] uint8_t* target() const { return m_target; } + /// @brief Get the target address. /// @return The target address. - [[nodiscard]] uintptr_t target() const { return m_target; } + [[nodiscard]] uintptr_t target_address() const { return reinterpret_cast(m_target); } + + /// @brief Get a pointer ot the destination. + /// @return A pointer to the destination. + [[nodiscard]] uint8_t* destination() const { return m_destination; } /// @brief Get the destination address. /// @return The destination address. - [[nodiscard]] size_t destination() const { return m_destination; } + [[nodiscard]] uintptr_t destination_address() const { return reinterpret_cast(m_destination); } /// @brief Get the trampoline Allocation. /// @return The trampoline Allocation. @@ -252,15 +270,15 @@ class InlineHook final { } private: - uintptr_t m_target{}; - uintptr_t m_destination{}; + uint8_t* m_target{}; + uint8_t* m_destination{}; Allocation m_trampoline{}; std::vector m_original_bytes{}; uintptr_t m_trampoline_size{}; std::recursive_mutex m_mutex{}; std::expected setup( - const std::shared_ptr& allocator, uintptr_t target, uintptr_t destination); + const std::shared_ptr& allocator, uint8_t* target, uint8_t* destination); std::expected e9_hook(const std::shared_ptr& allocator); #ifdef _M_X64 diff --git a/include/safetyhook/mid_hook.hpp b/include/safetyhook/mid_hook.hpp index 67af3ea..c5574b4 100644 --- a/include/safetyhook/mid_hook.hpp +++ b/include/safetyhook/mid_hook.hpp @@ -56,12 +56,17 @@ class MidHook final { [[nodiscard]] static std::expected create(void* target, MidHookFn destination); /// @brief Creates a new MidHook object. + /// @tparam T The type of the function to hook. /// @param target The address of the function to hook. /// @param destination The destination function. /// @return The MidHook object or a MidHook::Error if an error occurred. /// @note This will use the default global Allocator. /// @note If you don't care about error handling, use the easy API (safetyhook::create_mid). - [[nodiscard]] static std::expected create(uintptr_t target, MidHookFn destination); + template + requires std::is_function_v + [[nodiscard]] static std::expected create(T* target, MidHookFn destination) { + return create(reinterpret_cast(target), destination); + } /// @brief Creates a new MidHook object with a given Allocator. /// @param allocator The Allocator to use. @@ -73,13 +78,18 @@ class MidHook final { const std::shared_ptr& allocator, void* target, MidHookFn destination); /// @brief Creates a new MidHook object with a given Allocator. + /// @tparam T The type of the function to hook. /// @param allocator The Allocator to use. /// @param target The address of the function to hook. /// @param destination The destination function. /// @return The MidHook object or a MidHook::Error if an error occurred. /// @note If you don't care about error handling, use the easy API (safetyhook::create_mid). + template + requires std::is_function_v [[nodiscard]] static std::expected create( - const std::shared_ptr& allocator, uintptr_t target, MidHookFn destination); + const std::shared_ptr& allocator, T* target, MidHookFn destination) { + return create(allocator, reinterpret_cast(target), destination); + } MidHook() = default; MidHook(const MidHook&) = delete; @@ -93,9 +103,13 @@ class MidHook final { /// @note This is called automatically in the destructor. void reset(); - /// @brief Get the target address. - /// @return The target address. - [[nodiscard]] uintptr_t target() const { return m_target; } + /// @brief Get a pointer to the target. + /// @return A pointer to the target. + [[nodiscard]] uint8_t* target() const { return m_target; } + + /// @brief Get the address of the target. + /// @return The address of the target. + [[nodiscard]] uintptr_t target_address() const { return reinterpret_cast(m_target); } /// @brief Get the destination function. /// @return The destination function. @@ -107,11 +121,11 @@ class MidHook final { private: InlineHook m_hook{}; - uintptr_t m_target{}; + uint8_t* m_target{}; Allocation m_stub{}; MidHookFn m_destination{}; std::expected setup( - const std::shared_ptr& allocator, uintptr_t target, MidHookFn destination); + const std::shared_ptr& allocator, uint8_t* target, MidHookFn destination); }; } // namespace safetyhook \ No newline at end of file diff --git a/include/safetyhook/thread_freezer.hpp b/include/safetyhook/thread_freezer.hpp index 14711e2..4cd5127 100644 --- a/include/safetyhook/thread_freezer.hpp +++ b/include/safetyhook/thread_freezer.hpp @@ -24,5 +24,5 @@ void execute_while_frozen( /// @param ctx The thread context to modify. /// @param old_ip The old IP address. /// @param new_ip The new IP address. -void fix_ip(CONTEXT& ctx, uintptr_t old_ip, uintptr_t new_ip); +void fix_ip(CONTEXT& ctx, uint8_t* old_ip, uint8_t* new_ip); } // namespace safetyhook \ No newline at end of file diff --git a/include/safetyhook/utility.hpp b/include/safetyhook/utility.hpp new file mode 100644 index 0000000..277266e --- /dev/null +++ b/include/safetyhook/utility.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +namespace safetyhook { +template constexpr void store(uint8_t* address, const T& value) { + std::copy_n(reinterpret_cast(&value), sizeof(T), address); +} +} // namespace safetyhook \ No newline at end of file diff --git a/src/allocator.cpp b/src/allocator.cpp index 0128e51..5b496a2 100644 --- a/src/allocator.cpp +++ b/src/allocator.cpp @@ -8,12 +8,16 @@ #include namespace safetyhook { -constexpr auto align_up(uintptr_t address, size_t align) { - return (address + align - 1) & ~(align - 1); +template constexpr T align_up(T address, size_t align) { + const auto unaligned_address = (uintptr_t)address; + const auto aligned_address = (unaligned_address + align - 1) & ~(align - 1); + return (T)aligned_address; } -constexpr auto align_down(uintptr_t address, size_t align) { - return address & ~(align - 1); +template constexpr T align_down(T address, size_t align) { + const auto unaligned_address = (uintptr_t)address; + const auto aligned_address = unaligned_address & ~(align - 1); + return (T)aligned_address; } Allocation::Allocation(Allocation&& other) noexcept { @@ -28,7 +32,7 @@ Allocation& Allocation::operator=(Allocation&& other) noexcept { m_address = other.m_address; m_size = other.m_size; - other.m_address = 0; + other.m_address = nullptr; other.m_size = 0; } @@ -40,15 +44,15 @@ Allocation::~Allocation() { } void Allocation::free() { - if (m_allocator && m_address != 0 && m_size != 0) { + if (m_allocator && m_address != nullptr && m_size != 0) { m_allocator->free(m_address, m_size); - m_address = 0; + m_address = nullptr; m_size = 0; m_allocator.reset(); } } -Allocation::Allocation(std::shared_ptr allocator, uintptr_t address, size_t size) noexcept +Allocation::Allocation(std::shared_ptr allocator, uint8_t* address, size_t size) noexcept : m_allocator{std::move(allocator)}, m_address{address}, m_size{size} { } @@ -78,18 +82,18 @@ std::expected Allocator::allocate(size_t size) { } std::expected Allocator::allocate_near( - const std::vector& desired_addresses, size_t size, size_t max_distance) { + const std::vector& desired_addresses, size_t size, size_t max_distance) { std::scoped_lock lock{m_mutex}; return internal_allocate_near(desired_addresses, size, max_distance); } -void Allocator::free(uintptr_t address, size_t size) { +void Allocator::free(uint8_t* address, size_t size) { std::scoped_lock lock{m_mutex}; return internal_free(address, size); } std::expected Allocator::internal_allocate_near( - const std::vector& desired_addresses, size_t size, size_t max_distance) { + const std::vector& desired_addresses, size_t size, size_t max_distance) { // First search through our list of allocations for a free block that is large // enough. for (const auto& allocation : m_memory) { @@ -99,7 +103,7 @@ std::expected Allocator::internal_allocate_near( for (auto node = allocation->freelist.get(); node != nullptr; node = node->next.get()) { // Enough room? - if (node->end - node->start < size) { + if (static_cast(node->end - node->start) < size) { continue; } @@ -139,7 +143,7 @@ std::expected Allocator::internal_allocate_near( return Allocation{shared_from_this(), *allocation_address, size}; } -void Allocator::internal_free(uintptr_t address, size_t size) { +void Allocator::internal_free(uint8_t* address, size_t size) { for (const auto& allocation : m_memory) { if (allocation->address > address || allocation->address + allocation->size < address) { continue; @@ -186,24 +190,23 @@ void Allocator::combine_adjacent_freenodes(Memory& memory) { } } -std::expected Allocator::allocate_nearby_memory( - const std::vector& desired_addresses, size_t size, size_t max_distance) { +std::expected Allocator::allocate_nearby_memory( + const std::vector& desired_addresses, size_t size, size_t max_distance) { if (desired_addresses.empty()) { if (const auto result = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); result != nullptr) { - return reinterpret_cast(result); + return static_cast(result); } return std::unexpected{Error::BAD_VIRTUAL_ALLOC}; } - auto attempt_allocation = [&](uintptr_t p) -> uintptr_t { + auto attempt_allocation = [&](uint8_t* p) -> uint8_t* { if (!in_range(p, desired_addresses, max_distance)) { - return 0; + return nullptr; } - return reinterpret_cast( - VirtualAlloc(reinterpret_cast(p), size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)); + return static_cast(VirtualAlloc(p, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)); }; SYSTEM_INFO si{}; @@ -211,26 +214,26 @@ std::expected Allocator::allocate_nearby_memory( GetSystemInfo(&si); auto desired_address = desired_addresses[0]; - auto search_start = std::numeric_limits::min(); - auto search_end = std::numeric_limits::max(); + auto search_start = reinterpret_cast(std::numeric_limits::min()); + auto search_end = reinterpret_cast(std::numeric_limits::max()); - if (desired_address > max_distance) { + if (static_cast(desired_address - search_start) > max_distance) { search_start = desired_address - max_distance; } - if (std::numeric_limits::max() - desired_address > max_distance) { + if (static_cast(search_end - desired_address) > max_distance) { search_end = desired_address + max_distance; } - search_start = std::max(search_start, reinterpret_cast(si.lpMinimumApplicationAddress)); - search_end = std::min(search_end, reinterpret_cast(si.lpMaximumApplicationAddress)); + search_start = std::max(search_start, static_cast(si.lpMinimumApplicationAddress)); + search_end = std::min(search_end, static_cast(si.lpMaximumApplicationAddress)); desired_address = align_up(desired_address, si.dwAllocationGranularity); MEMORY_BASIC_INFORMATION mbi{}; // Search backwards from the desired_address. for (auto p = desired_address; p > search_start && in_range(p, desired_addresses, max_distance); - p = align_down(reinterpret_cast(mbi.AllocationBase) - 1, si.dwAllocationGranularity)) { - if (VirtualQuery(reinterpret_cast(p), &mbi, sizeof(mbi)) == 0) { + p = align_down(static_cast(mbi.AllocationBase) - 1, si.dwAllocationGranularity)) { + if (VirtualQuery(p, &mbi, sizeof(mbi)) == 0) { break; } @@ -246,7 +249,7 @@ std::expected Allocator::allocate_nearby_memory( // Search forwards from the desired_address. for (auto p = desired_address; p < search_end && in_range(p, desired_addresses, max_distance); p += mbi.RegionSize) { - if (VirtualQuery(reinterpret_cast(p), &mbi, sizeof(mbi)) == 0) { + if (VirtualQuery(p, &mbi, sizeof(mbi)) == 0) { break; } @@ -254,7 +257,7 @@ std::expected Allocator::allocate_nearby_memory( continue; } - if (auto allocation_address = attempt_allocation(p); allocation_address != 0) { + if (auto allocation_address = attempt_allocation(p); allocation_address != nullptr) { return allocation_address; } } @@ -262,14 +265,14 @@ std::expected Allocator::allocate_nearby_memory( return std::unexpected{Error::NO_MEMORY_IN_RANGE}; } -bool Allocator::in_range(uintptr_t address, const std::vector& desired_addresses, size_t max_distance) { +bool Allocator::in_range(uint8_t* address, const std::vector& desired_addresses, size_t max_distance) { return std::ranges::all_of(desired_addresses, [&](const auto& desired_address) { - auto delta = (address > desired_address) ? address - desired_address : desired_address - address; + const size_t delta = (address > desired_address) ? address - desired_address : desired_address - address; return delta <= max_distance; }); } Allocator::Memory::~Memory() { - VirtualFree(reinterpret_cast(address), 0, MEM_RELEASE); + VirtualFree(address, 0, MEM_RELEASE); } } // namespace safetyhook \ No newline at end of file diff --git a/src/easy.cpp b/src/easy.cpp index ede1097..2508007 100644 --- a/src/easy.cpp +++ b/src/easy.cpp @@ -2,10 +2,6 @@ namespace safetyhook { InlineHook create_inline(void* target, void* destination) { - return create_inline(reinterpret_cast(target), reinterpret_cast(destination)); -} - -InlineHook create_inline(uintptr_t target, uintptr_t destination) { if (auto hook = InlineHook::create(target, destination)) { return std::move(*hook); } else { @@ -14,14 +10,11 @@ InlineHook create_inline(uintptr_t target, uintptr_t destination) { } MidHook create_mid(void* target, MidHookFn destination) { - return create_mid(reinterpret_cast(target), destination); -} - -MidHook create_mid(uintptr_t target, MidHookFn destination) { if (auto hook = MidHook::create(target, destination)) { return std::move(*hook); } else { return {}; } } + } // namespace safetyhook \ No newline at end of file diff --git a/src/inline_hook.cpp b/src/inline_hook.cpp index 1331104..59cb9ac 100644 --- a/src/inline_hook.cpp +++ b/src/inline_hook.cpp @@ -12,20 +12,21 @@ #include #include +#include #include namespace safetyhook { class UnprotectMemory { public: - UnprotectMemory(uintptr_t address, size_t size) : m_address{address}, m_size{size} { - VirtualProtect(reinterpret_cast(m_address), m_size, PAGE_EXECUTE_READWRITE, &m_protect); + UnprotectMemory(uint8_t* address, size_t size) : m_address{address}, m_size{size} { + VirtualProtect(m_address, m_size, PAGE_EXECUTE_READWRITE, &m_protect); } - ~UnprotectMemory() { VirtualProtect(reinterpret_cast(m_address), m_size, m_protect, &m_protect); } + ~UnprotectMemory() { VirtualProtect(m_address, m_size, m_protect, &m_protect); } private: - uintptr_t m_address{}; + uint8_t* m_address{}; size_t m_size{}; DWORD m_protect{}; }; @@ -62,16 +63,16 @@ struct TrampolineEpilogueE9 { #pragma pack(pop) #ifdef _M_X64 -static auto make_jmp_ff(uintptr_t src, uintptr_t dst, uintptr_t data) { +static auto make_jmp_ff(uint8_t* src, uint8_t* dst, uint8_t* data) { JmpFF jmp{}; jmp.offset = static_cast(data - src - sizeof(jmp)); - *reinterpret_cast(data) = dst; + store(data, dst); return jmp; } -static void emit_jmp_ff(uintptr_t src, uintptr_t dst, uintptr_t data, size_t size = sizeof(JmpFF)) { +static void emit_jmp_ff(uint8_t* src, uint8_t* dst, uint8_t* data, size_t size = sizeof(JmpFF)) { if (size < sizeof(JmpFF)) { return; } @@ -79,14 +80,14 @@ static void emit_jmp_ff(uintptr_t src, uintptr_t dst, uintptr_t data, size_t siz UnprotectMemory unprotect{src, size}; if (size > sizeof(JmpFF)) { - std::fill_n(reinterpret_cast(src), size, static_cast(0x90)); + std::fill_n(src, size, static_cast(0x90)); } - *reinterpret_cast(src) = make_jmp_ff(src, dst, data); + store(src, make_jmp_ff(src, dst, data)); } #endif -constexpr auto make_jmp_e9(uintptr_t src, uintptr_t dst) { +constexpr auto make_jmp_e9(uint8_t* src, uint8_t* dst) { JmpE9 jmp{}; jmp.offset = static_cast(dst - src - sizeof(jmp)); @@ -94,7 +95,7 @@ constexpr auto make_jmp_e9(uintptr_t src, uintptr_t dst) { return jmp; } -static void emit_jmp_e9(uintptr_t src, uintptr_t dst, size_t size = sizeof(JmpE9)) { +static void emit_jmp_e9(uint8_t* src, uint8_t* dst, size_t size = sizeof(JmpE9)) { if (size < sizeof(JmpE9)) { return; } @@ -102,13 +103,13 @@ static void emit_jmp_e9(uintptr_t src, uintptr_t dst, size_t size = sizeof(JmpE9 UnprotectMemory unprotect{src, size}; if (size > sizeof(JmpE9)) { - std::fill_n(reinterpret_cast(src), size, static_cast(0x90)); + std::fill_n(src, size, static_cast(0x90)); } - *reinterpret_cast(src) = make_jmp_e9(src, dst); + store(src, make_jmp_e9(src, dst)); } -static bool decode(ZydisDecodedInstruction* ix, uintptr_t ip) { +static bool decode(ZydisDecodedInstruction* ix, uint8_t* ip) { ZydisDecoder decoder{}; ZyanStatus status; @@ -124,27 +125,20 @@ static bool decode(ZydisDecodedInstruction* ix, uintptr_t ip) { return false; } - return ZYAN_SUCCESS(ZydisDecoderDecodeInstruction(&decoder, nullptr, reinterpret_cast(ip), 15, ix)); + return ZYAN_SUCCESS(ZydisDecoderDecodeInstruction(&decoder, nullptr, ip, 15, ix)); } std::expected InlineHook::create(void* target, void* destination) { return create(Allocator::global(), target, destination); } -std::expected InlineHook::create(uintptr_t target, uintptr_t destination) { - return create(Allocator::global(), target, destination); -} - std::expected InlineHook::create( const std::shared_ptr& allocator, void* target, void* destination) { - return create(allocator, reinterpret_cast(target), reinterpret_cast(destination)); -} - -std::expected InlineHook::create( - const std::shared_ptr& allocator, uintptr_t target, uintptr_t destination) { InlineHook hook{}; - if (const auto setup_result = hook.setup(allocator, target, destination); !setup_result) { + if (const auto setup_result = + hook.setup(allocator, reinterpret_cast(target), reinterpret_cast(destination)); + !setup_result) { return std::unexpected{setup_result.error()}; } @@ -184,13 +178,13 @@ void InlineHook::reset() { } std::expected InlineHook::setup( - const std::shared_ptr& allocator, uintptr_t target, uintptr_t destination) { + const std::shared_ptr& allocator, uint8_t* target, uint8_t* destination) { m_target = target; m_destination = destination; - if (const auto e9_result = e9_hook(allocator); !e9_result) { + if (auto e9_result = e9_hook(allocator); !e9_result) { #ifdef _M_X64 - if (const auto ff_result = ff_hook(allocator); !ff_result) { + if (auto ff_result = ff_hook(allocator); !ff_result) { return ff_result; } #else @@ -205,17 +199,16 @@ std::expected InlineHook::e9_hook(const std::shared_ptr m_original_bytes.clear(); m_trampoline_size = sizeof(TrampolineEpilogueE9); - std::vector desired_addresses{m_target}; + std::vector desired_addresses{m_target}; ZydisDecodedInstruction ix{}; - for (uintptr_t ip = m_target; ip < m_target + sizeof(JmpE9); ip += ix.length) { + for (auto ip = m_target; ip < m_target + sizeof(JmpE9); ip += ix.length) { if (!decode(&ix, ip)) { return std::unexpected{Error::failed_to_decode_instruction(ip)}; } m_trampoline_size += ix.length; - m_original_bytes.insert( - m_original_bytes.end(), reinterpret_cast(ip), reinterpret_cast(ip) + ix.length); + m_original_bytes.insert(m_original_bytes.end(), ip, ip + ix.length); const auto is_relative = (ix.attributes & ZYDIS_ATTRIB_IS_RELATIVE) != 0; @@ -248,8 +241,7 @@ std::expected InlineHook::e9_hook(const std::shared_ptr m_trampoline = std::move(*trampoline_allocation); - for (uintptr_t ip = m_target, tramp_ip = m_trampoline.address(); ip < m_target + m_original_bytes.size(); - ip += ix.length) { + for (auto ip = m_target, tramp_ip = m_trampoline.data(); ip < m_target + m_original_bytes.size(); ip += ix.length) { if (!decode(&ix, ip)) { m_trampoline.free(); return std::unexpected{Error::failed_to_decode_instruction(ip)}; @@ -258,44 +250,44 @@ std::expected InlineHook::e9_hook(const std::shared_ptr const auto is_relative = (ix.attributes & ZYDIS_ATTRIB_IS_RELATIVE) != 0; if (is_relative && ix.raw.disp.size == 32) { - std::copy_n(reinterpret_cast(ip), ix.length, reinterpret_cast(tramp_ip)); - const auto target_address = ip + ix.length + static_cast(ix.raw.disp.value); - const auto new_disp = static_cast(target_address - (tramp_ip + ix.length)); - *reinterpret_cast(tramp_ip + ix.raw.disp.offset) = new_disp; + std::copy_n(ip, ix.length, tramp_ip); + const auto target_address = ip + ix.length + ix.raw.disp.value; + const auto new_disp = target_address - (tramp_ip + ix.length); + store(tramp_ip + ix.raw.disp.offset, static_cast(new_disp)); tramp_ip += ix.length; } else if (is_relative && ix.raw.imm[0].size == 32) { - std::copy_n(reinterpret_cast(ip), ix.length, reinterpret_cast(tramp_ip)); - const auto target_address = ip + ix.length + static_cast(ix.raw.imm[0].value.s); - const auto new_disp = static_cast(target_address - (tramp_ip + ix.length)); - *reinterpret_cast(tramp_ip + ix.raw.imm[0].offset) = new_disp; + std::copy_n(ip, ix.length, tramp_ip); + const auto target_address = ip + ix.length + ix.raw.imm[0].value.s; + const auto new_disp = target_address - (tramp_ip + ix.length); + store(tramp_ip + ix.raw.imm[0].offset, static_cast(new_disp)); tramp_ip += ix.length; } else if (ix.meta.category == ZYDIS_CATEGORY_COND_BR && ix.meta.branch_type == ZYDIS_BRANCH_TYPE_SHORT) { - const auto target_address = ip + ix.length + static_cast(ix.raw.imm[0].value.s); - auto new_disp = static_cast(target_address - (tramp_ip + 6)); + const auto target_address = ip + ix.length + ix.raw.imm[0].value.s; + auto new_disp = target_address - (tramp_ip + 6); // Handle the case where the target is now in the trampoline. if (target_address < m_target + m_original_bytes.size()) { - new_disp = static_cast(ix.raw.imm[0].value.s); + new_disp = static_cast(ix.raw.imm[0].value.s); } - *reinterpret_cast(tramp_ip) = 0x0F; - *reinterpret_cast(tramp_ip + 1) = 0x10 + ix.opcode; - *reinterpret_cast(tramp_ip + 2) = new_disp; + *tramp_ip = 0x0F; + *(tramp_ip + 1) = 0x10 + ix.opcode; + store(tramp_ip + 2, static_cast(new_disp)); tramp_ip += 6; } else if (ix.meta.category == ZYDIS_CATEGORY_UNCOND_BR && ix.meta.branch_type == ZYDIS_BRANCH_TYPE_SHORT) { - const auto target_address = ip + ix.length + static_cast(ix.raw.imm[0].value.s); - auto new_disp = static_cast(target_address - (tramp_ip + 5)); + const auto target_address = ip + ix.length + ix.raw.imm[0].value.s; + auto new_disp = target_address - (tramp_ip + 5); // Handle the case where the target is now in the trampoline. if (target_address < m_target + m_original_bytes.size()) { - new_disp = static_cast(ix.raw.imm[0].value.s); + new_disp = static_cast(ix.raw.imm[0].value.s); } - *reinterpret_cast(tramp_ip) = 0xE9; - *reinterpret_cast(tramp_ip + 1) = new_disp; + *tramp_ip = 0xE9; + store(tramp_ip + 1, static_cast(new_disp)); tramp_ip += 5; } else { - std::copy_n(reinterpret_cast(ip), ix.length, reinterpret_cast(tramp_ip)); + std::copy_n(ip, ix.length, tramp_ip); tramp_ip += ix.length; } } @@ -304,16 +296,16 @@ std::expected InlineHook::e9_hook(const std::shared_ptr m_trampoline.address() + m_trampoline_size - sizeof(TrampolineEpilogueE9)); // jmp from trampoline to original. - auto src = reinterpret_cast(&trampoline_epilogue->jmp_to_original); + auto src = reinterpret_cast(&trampoline_epilogue->jmp_to_original); auto dst = m_target + m_original_bytes.size(); emit_jmp_e9(src, dst); // jmp from trampoline to destination. - src = reinterpret_cast(&trampoline_epilogue->jmp_to_destination); + src = reinterpret_cast(&trampoline_epilogue->jmp_to_destination); dst = m_destination; #ifdef _M_X64 - auto data = reinterpret_cast(&trampoline_epilogue->destination_address); + auto data = reinterpret_cast(&trampoline_epilogue->destination_address); emit_jmp_ff(src, dst, data); #else emit_jmp_e9(src, dst); @@ -323,12 +315,12 @@ std::expected InlineHook::e9_hook(const std::shared_ptr execute_while_frozen( [this, &trampoline_epilogue] { const auto src = m_target; - const auto dst = reinterpret_cast(&trampoline_epilogue->jmp_to_destination); + const auto dst = reinterpret_cast(&trampoline_epilogue->jmp_to_destination); emit_jmp_e9(src, dst, m_original_bytes.size()); }, [this](uint32_t, HANDLE, CONTEXT& ctx) { for (size_t i = 0; i < m_original_bytes.size(); ++i) { - fix_ip(ctx, m_target + i, m_trampoline.address() + i); + fix_ip(ctx, m_target + i, m_trampoline.data() + i); } }); @@ -353,8 +345,7 @@ std::expected InlineHook::ff_hook(const std::shared_ptr return std::unexpected{Error::ip_relative_instruction_out_of_range(ip)}; } - m_original_bytes.insert( - m_original_bytes.end(), reinterpret_cast(ip), reinterpret_cast(ip + ix.length)); + m_original_bytes.insert(m_original_bytes.end(), ip, ip + ix.length); m_trampoline_size += ix.length; } @@ -366,15 +357,15 @@ std::expected InlineHook::ff_hook(const std::shared_ptr m_trampoline = std::move(*trampoline_allocation); - std::copy(m_original_bytes.begin(), m_original_bytes.end(), reinterpret_cast(m_trampoline.address())); + std::copy(m_original_bytes.begin(), m_original_bytes.end(), m_trampoline.data()); - const auto trampoline_epilogue = reinterpret_cast( - m_trampoline.address() + m_trampoline_size - sizeof(TrampolineEpilogueFF)); + const auto trampoline_epilogue = + reinterpret_cast(m_trampoline.data() + m_trampoline_size - sizeof(TrampolineEpilogueFF)); // jmp from trampoline to original. - auto src = reinterpret_cast(&trampoline_epilogue->jmp_to_original); + auto src = reinterpret_cast(&trampoline_epilogue->jmp_to_original); auto dst = m_target + m_original_bytes.size(); - auto data = reinterpret_cast(&trampoline_epilogue->original_address); + auto data = reinterpret_cast(&trampoline_epilogue->original_address); emit_jmp_ff(src, dst, data); // jmp from original to trampoline. @@ -387,7 +378,7 @@ std::expected InlineHook::ff_hook(const std::shared_ptr }, [this](uint32_t, HANDLE, CONTEXT& ctx) { for (size_t i = 0; i < m_original_bytes.size(); ++i) { - fix_ip(ctx, m_target + i, m_trampoline.address() + i); + fix_ip(ctx, m_target + i, m_trampoline.data() + i); } }); @@ -405,11 +396,11 @@ void InlineHook::destroy() { execute_while_frozen( [this] { UnprotectMemory unprotect{m_target, m_original_bytes.size()}; - std::copy(m_original_bytes.begin(), m_original_bytes.end(), reinterpret_cast(m_target)); + std::copy(m_original_bytes.begin(), m_original_bytes.end(), m_target); }, [this](uint32_t, HANDLE, CONTEXT& ctx) { for (size_t i = 0; i < m_original_bytes.size(); ++i) { - fix_ip(ctx, m_trampoline.address() + i, m_target + i); + fix_ip(ctx, m_trampoline.data() + i, m_target + i); } }); diff --git a/src/mid_hook.cpp b/src/mid_hook.cpp index 5775398..f0d974c 100644 --- a/src/mid_hook.cpp +++ b/src/mid_hook.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -24,20 +25,12 @@ std::expected MidHook::create(void* target, MidHookFn d return create(Allocator::global(), target, destination); } -std::expected MidHook::create(uintptr_t target, MidHookFn destination) { - return create(Allocator::global(), target, destination); -} - std::expected MidHook::create( const std::shared_ptr& allocator, void* target, MidHookFn destination) { - return create(allocator, reinterpret_cast(target), destination); -} - -std::expected MidHook::create( - const std::shared_ptr& allocator, uintptr_t target, MidHookFn destination) { MidHook hook{}; - if (const auto setup_result = hook.setup(allocator, target, destination); !setup_result) { + if (const auto setup_result = hook.setup(allocator, reinterpret_cast(target), destination); + !setup_result) { return std::unexpected{setup_result.error()}; } @@ -67,7 +60,7 @@ void MidHook::reset() { } std::expected MidHook::setup( - const std::shared_ptr& allocator, uintptr_t target, MidHookFn destination) { + const std::shared_ptr& allocator, uint8_t* target, MidHookFn destination) { m_target = target; m_destination = destination; @@ -79,19 +72,19 @@ std::expected MidHook::setup( m_stub = std::move(*stub_allocation); - std::copy_n(asm_data, sizeof(asm_data), reinterpret_cast(m_stub.address())); + std::copy_n(asm_data, sizeof(asm_data), m_stub.data()); #ifdef _M_X64 - *reinterpret_cast(m_stub.address() + sizeof(asm_data) - 16) = m_destination; + store(m_stub.data() + sizeof(asm_data) - 16, m_destination); #else - *reinterpret_cast(m_stub.address() + sizeof(asm_data) - 8) = m_destination; + store(m_stub.data() + sizeof(asm_data) - 8, m_destination); // 32-bit has some relocations we need to fix up as well. - *reinterpret_cast(m_stub.address() + 0xA + 2) = m_stub.address() + sizeof(asm_data) - 8; - *reinterpret_cast(m_stub.address() + 0x1C + 2) = m_stub.address() + sizeof(asm_data) - 4; + store(m_stub.data() + 0xA + 2, m_stub.data() + sizeof(asm_data) - 8); + store(m_stub.data() + 0x1C + 2, m_stub.data() + sizeof(asm_data) - 4); #endif - auto hook_result = InlineHook::create(allocator, m_target, m_stub.address()); + auto hook_result = InlineHook::create(allocator, m_target, m_stub.data()); if (!hook_result) { m_stub.free(); @@ -101,9 +94,9 @@ std::expected MidHook::setup( m_hook = std::move(*hook_result); #ifdef _M_X64 - *reinterpret_cast(m_stub.address() + sizeof(asm_data) - 8) = m_hook.trampoline().address(); + store(m_stub.data() + sizeof(asm_data) - 8, m_hook.trampoline().data()); #else - *reinterpret_cast(m_stub.address() + sizeof(asm_data) - 4) = m_hook.trampoline().address(); + store(m_stub.data() + sizeof(asm_data) - 4, m_hook.trampoline().data()); #endif return {}; diff --git a/src/thread_freezer.cpp b/src/thread_freezer.cpp index 088b39b..364ad73 100644 --- a/src/thread_freezer.cpp +++ b/src/thread_freezer.cpp @@ -110,15 +110,15 @@ void execute_while_frozen( } } -void fix_ip(CONTEXT& ctx, uintptr_t old_ip, uintptr_t new_ip) { +void fix_ip(CONTEXT& ctx, uint8_t* old_ip, uint8_t* new_ip) { #ifdef _M_X64 auto ip = ctx.Rip; #else auto ip = ctx.Eip; #endif - if (ip == old_ip) { - ip = new_ip; + if (ip == reinterpret_cast(old_ip)) { + ip = reinterpret_cast(new_ip); } #ifdef _M_X64 diff --git a/tests/test2.cpp b/tests/test2.cpp index 216889e..53eb3cb 100644 --- a/tests/test2.cpp +++ b/tests/test2.cpp @@ -38,9 +38,9 @@ int main() { #error "Unsupported architecture" #endif - auto ip = (uintptr_t)add_42; + auto ip = reinterpret_cast(add_42); - while (*(uint8_t*)ip != 0xC3) { + while (*ip != 0xC3) { ZydisDecodedInstruction ix{}; ZydisDecoderDecodeInstruction(&decoder, nullptr, reinterpret_cast(ip), 15, &ix); diff --git a/unittest/inline_hook.cpp b/unittest/inline_hook.cpp index 22fff12..7f87e46 100644 --- a/unittest/inline_hook.cpp +++ b/unittest/inline_hook.cpp @@ -1,6 +1,6 @@ #include -#include #include +#include TEST_CASE("Function hooked multiple times", "[inline_hook]") { struct Target { @@ -16,7 +16,7 @@ TEST_CASE("Function hooked multiple times", "[inline_hook]") { static std::string fn(std::string name) { return hook0.call(name + " and bob"); } }; - auto hook0_result = SafetyHookInline::create(reinterpret_cast(Target::fn), reinterpret_cast(Hook0::fn)); + auto hook0_result = SafetyHookInline::create(Target::fn, Hook0::fn); REQUIRE(hook0_result); @@ -31,7 +31,7 @@ TEST_CASE("Function hooked multiple times", "[inline_hook]") { static std::string fn(std::string name) { return hook1.call(name + " and alice"); } }; - auto hook1_result = SafetyHookInline::create(reinterpret_cast(Target::fn), reinterpret_cast(Hook1::fn)); + auto hook1_result = SafetyHookInline::create(Target::fn, Hook1::fn); REQUIRE(hook1_result); @@ -46,7 +46,7 @@ TEST_CASE("Function hooked multiple times", "[inline_hook]") { static std::string fn(std::string name) { return hook2.call(name + " and eve"); } }; - auto hook2_result = SafetyHookInline::create(reinterpret_cast(Target::fn), reinterpret_cast(Hook2::fn)); + auto hook2_result = SafetyHookInline::create(Target::fn, Hook2::fn); REQUIRE(hook2_result); @@ -61,7 +61,7 @@ TEST_CASE("Function hooked multiple times", "[inline_hook]") { static std::string fn(std::string name) { return hook3.call(name + " and carol"); } }; - auto hook3_result = SafetyHookInline::create(reinterpret_cast(Target::fn), reinterpret_cast(Hook3::fn)); + auto hook3_result = SafetyHookInline::create(Target::fn, Hook3::fn); REQUIRE(hook3_result); @@ -89,7 +89,7 @@ TEST_CASE("Function with multiple args hooked", "[inline_hook]") { static int add(int x, int y) { return add_hook.call(x * 2, y * 2); } }; - auto add_hook_result = SafetyHookInline::create(reinterpret_cast(Target::add), reinterpret_cast(AddHook::add)); + auto add_hook_result = SafetyHookInline::create(Target::add, AddHook::add); REQUIRE(add_hook_result); @@ -128,7 +128,7 @@ TEST_CASE("Active function is hooked and unhooked", "[inline_hook]") { static std::string say_hello(int times [[maybe_unused]]) { return hook.call(1337); } }; - auto hook_result = SafetyHookInline::create(reinterpret_cast(Target::say_hello), reinterpret_cast(Hook::say_hello)); + auto hook_result = SafetyHookInline::create(Target::say_hello, Hook::say_hello); REQUIRE(hook_result); @@ -153,9 +153,7 @@ TEST_CASE("Function with short unconditional branch is hooked", "[inline-hook]") static SafetyHookInline hook; struct Hook { - static int __fastcall fn() { - return hook.fastcall() + 42; - }; + static int __fastcall fn() { return hook.fastcall() + 42; }; }; Xbyak::CodeGenerator cg{}; @@ -173,7 +171,7 @@ TEST_CASE("Function with short unconditional branch is hooked", "[inline-hook]") REQUIRE(fn() == 1); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); REQUIRE(fn() == 43); @@ -189,9 +187,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { static SafetyHookInline hook; struct Hook { - static int __fastcall fn(int x) { - return hook.fastcall(x) + 42; - }; + static int __fastcall fn(int x) { return hook.fastcall(x) + 42; }; }; Xbyak::CodeGenerator cg{}; @@ -217,7 +213,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 0); CHECK(fn(9) == 0); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 43); CHECK(fn(8) == 42); @@ -238,7 +234,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 1); CHECK(fn(9) == 0); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 43); CHECK(fn(8) == 43); @@ -259,7 +255,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 0); CHECK(fn(9) == 0); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 43); CHECK(fn(8) == 42); @@ -280,7 +276,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 1); CHECK(fn(9) == 0); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 43); CHECK(fn(8) == 43); @@ -301,7 +297,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 1); CHECK(fn(9) == 1); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 42); CHECK(fn(8) == 43); @@ -322,7 +318,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 0); CHECK(fn(9) == 1); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 42); CHECK(fn(8) == 42); @@ -343,7 +339,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 1); CHECK(fn(9) == 1); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 42); CHECK(fn(8) == 43); @@ -364,7 +360,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 0); CHECK(fn(9) == 1); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 42); CHECK(fn(8) == 42); @@ -385,7 +381,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 1); CHECK(fn(9) == 1); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 43); CHECK(fn(8) == 43); @@ -406,7 +402,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 0); CHECK(fn(9) == 1); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 42); CHECK(fn(8) == 42); @@ -427,7 +423,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 1); CHECK(fn(9) == 1); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 42); CHECK(fn(8) == 43); @@ -448,7 +444,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 0); CHECK(fn(9) == 1); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 43); CHECK(fn(8) == 42); @@ -469,7 +465,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 0); CHECK(fn(9) == 0); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 42); CHECK(fn(8) == 42); @@ -490,7 +486,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 1); CHECK(fn(9) == 0); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 43); CHECK(fn(8) == 43); @@ -511,7 +507,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 0); CHECK(fn(9) == 0); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 43); CHECK(fn(8) == 42); @@ -532,7 +528,7 @@ TEST_CASE("Function with short conditional branch is hooked", "[inline-hook]") { CHECK(fn(8) == 1); CHECK(fn(9) == 0); - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); CHECK(fn(7) == 42); CHECK(fn(8) == 43); @@ -557,20 +553,18 @@ TEST_CASE("Function with short jump inside trampoline", "[inline-hook]") { cg.mov(eax, 42); cg.ret(); cg.nop(10, false); - - const auto fn = cg.getCode(); + + const auto fn = cg.getCode(); REQUIRE(fn() == 42); static SafetyHookInline hook; struct Hook { - static int fn() { - return hook.call() + 1; - } + static int fn() { return hook.call() + 1; } }; - hook = safetyhook::create_inline(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + hook = safetyhook::create_inline(fn, Hook::fn); REQUIRE(fn() == 43); diff --git a/unittest/inline_hook.x86_64.cpp b/unittest/inline_hook.x86_64.cpp index a7fdcd2..77d489e 100644 --- a/unittest/inline_hook.x86_64.cpp +++ b/unittest/inline_hook.x86_64.cpp @@ -1,8 +1,8 @@ #if defined(_M_X64) #include -#include #include +#include void asciiz(Xbyak::CodeGenerator& cg, const char* str) { while (*str) { @@ -19,7 +19,7 @@ TEST_CASE("Function with RIP-relative operand is hooked", "[inline-hook-x86_64]" Xbyak::CodeGenerator cg{}; Xbyak::Label str_label{}; - cg.lea(rax, ptr [rip + str_label]); + cg.lea(rax, ptr[rip + str_label]); cg.ret(); for (auto i = 0; i < 10; ++i) { @@ -29,7 +29,7 @@ TEST_CASE("Function with RIP-relative operand is hooked", "[inline-hook-x86_64]" cg.L(str_label); asciiz(cg, "Hello"); - const auto fn = cg.getCode(); + const auto fn = cg.getCode(); REQUIRE((fn() == "Hello"sv)); @@ -39,7 +39,7 @@ TEST_CASE("Function with RIP-relative operand is hooked", "[inline-hook-x86_64]" static const char* fn() { return "Hello, world!"; } }; - auto hook_result = SafetyHookInline::create(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + auto hook_result = SafetyHookInline::create(fn, Hook::fn); REQUIRE(hook_result); @@ -77,7 +77,7 @@ TEST_CASE("Function with no nearby memory is hooked", "[inline-hook-x86_64]") { static int fn(int a) { return hook.call(a) * a; } }; - auto hook_result = SafetyHookInline::create(reinterpret_cast(fn), reinterpret_cast(Hook::fn)); + auto hook_result = SafetyHookInline::create(fn, Hook::fn); REQUIRE(hook_result); diff --git a/unittest/mid_hook.cpp b/unittest/mid_hook.cpp index 7de2045..e611c11 100644 --- a/unittest/mid_hook.cpp +++ b/unittest/mid_hook.cpp @@ -3,20 +3,18 @@ TEST_CASE("Mid hook to change a register", "[mid_hook]") { struct Target { - __declspec(noinline) static int __fastcall add_42(int a) { - return a + 42; - } + __declspec(noinline) static int __fastcall add_42(int a) { return a + 42; } }; REQUIRE(Target::add_42(0) == 42); - + static SafetyHookMid hook; struct Hook { static void add_42(SafetyHookContext& ctx) { #if defined(_M_X64) ctx.rcx = 1337 - 42; -#elif defined(_M_IX86) +#elif defined(_M_IX86) ctx.ecx = 1337 - 42; #else #error "Unsupported architecture" @@ -24,7 +22,7 @@ TEST_CASE("Mid hook to change a register", "[mid_hook]") { } }; - auto hook_result = SafetyHookMid::create(reinterpret_cast(Target::add_42), Hook::add_42); + auto hook_result = SafetyHookMid::create(Target::add_42, Hook::add_42); REQUIRE(hook_result);