From aaf79dfa03dc99f4b3037504e05568601e59a46a Mon Sep 17 00:00:00 2001 From: Kenzzer Date: Sun, 19 May 2024 15:08:48 +0200 Subject: [PATCH] Downgrade to C++17 --- AMBuildScript | 4 +- public/safetyhook/safetyhook.cpp | 62 +++++++++++++---------- public/safetyhook/safetyhook.hpp | 87 ++++++++++++++++++++++---------- 3 files changed, 99 insertions(+), 54 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index 8038b6fa21..0795866a4a 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -247,7 +247,7 @@ class SMConfig(object): if cxx.target.arch in ['x86', 'x86_64']: cxx.cflags += ['-msse'] - cxx.cxxflags += ['-std=c++20'] + cxx.cxxflags += ['-std=c++17'] cxx.cxxflags += [ '-fno-threadsafe-statics', @@ -330,7 +330,7 @@ class SMConfig(object): '/EHsc', '/GR-', '/TP', - '/std:c++20', + '/std:c++17', ] cxx.linkflags += [ 'kernel32.lib', diff --git a/public/safetyhook/safetyhook.cpp b/public/safetyhook/safetyhook.cpp index 57ee76d4ce..88a859a87f 100644 --- a/public/safetyhook/safetyhook.cpp +++ b/public/safetyhook/safetyhook.cpp @@ -54,21 +54,25 @@ struct VmAccess { bool write : 1; bool execute : 1; + constexpr VmAccess(bool pread, bool pwrite, bool pexecute) : read(pread), write(pwrite), execute(pexecute) {}; + constexpr bool operator==(const VmAccess& other) const { return read == other.read && write == other.write && execute == other.execute; } }; -constexpr VmAccess VM_ACCESS_R{.read = true, .write = false, .execute = false}; -constexpr VmAccess VM_ACCESS_RW{.read = true, .write = true, .execute = false}; -constexpr VmAccess VM_ACCESS_RX{.read = true, .write = false, .execute = true}; -constexpr VmAccess VM_ACCESS_RWX{.read = true, .write = true, .execute = true}; +constexpr VmAccess VM_ACCESS_R(true, false, false); +constexpr VmAccess VM_ACCESS_RW(true, true, false); +constexpr VmAccess VM_ACCESS_RX(true, false, true); +constexpr VmAccess VM_ACCESS_RWX(true, true, true); struct VmBasicInfo { uint8_t* address; size_t size; VmAccess access; bool is_free; + + constexpr VmBasicInfo() : address(nullptr), size(0), access(VM_ACCESS_RWX), is_free(false) {} }; tl::expected vm_allocate(uint8_t* address, size_t size, VmAccess access); @@ -1357,10 +1361,14 @@ tl::expected Allocator::allocate_nearby_memory( } 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) { - const size_t delta = (address > desired_address) ? address - desired_address : desired_address - address; - return delta <= max_distance; - }); + bool ret = true; + for (auto& desired_address = desired_addresses.begin(); desired_address != desired_addresses.end(); desired_address++) { + auto& value = *desired_address; + + const size_t delta = (address > value) ? address - value : value - address; + ret &= (delta <= max_distance); + } + return ret; } Allocator::Memory::~Memory() { @@ -1454,18 +1462,18 @@ tl::expected vm_query(uint8_t* address) { return tl::unexpected{OsError::FAILED_TO_QUERY}; } - VmAccess access{ - .read = (mbi.Protect & (PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)) != 0, - .write = (mbi.Protect & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) != 0, - .execute = (mbi.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)) != 0, - }; + VmAccess access( + (mbi.Protect & (PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)) != 0, + (mbi.Protect & (PAGE_READWRITE | PAGE_EXECUTE_READWRITE)) != 0, + (mbi.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)) != 0 + ); - return VmBasicInfo{ - .address = static_cast(mbi.AllocationBase), - .size = mbi.RegionSize, - .access = access, - .is_free = mbi.State == MEM_FREE, - }; + VmBasicInfo retInfo; + retInfo.address = static_cast(mbi.AllocationBase); + retInfo.size = mbi.RegionSize; + retInfo.access = access; + retInfo.is_free = (mbi.State == MEM_FREE); + return retInfo; } bool vm_is_readable(uint8_t* address, size_t size) { @@ -1578,13 +1586,15 @@ class TrapManager final { } void add_trap(uint8_t* from, uint8_t* to, size_t len) { - m_traps.insert_or_assign(from, TrapInfo{.from_page_start = align_down(from, 0x1000), - .from_page_end = align_up(from + len, 0x1000), - .from = from, - .to_page_start = align_down(to, 0x1000), - .to_page_end = align_up(to + len, 0x1000), - .to = to, - .len = len}); + TrapInfo info; + info.from_page_start = align_down(from, 0x1000); + info.from_page_end = align_up(from + len, 0x1000); + info.from = from; + info.to_page_start = align_down(to, 0x1000); + info.to_page_end = align_up(to + len, 0x1000); + info.to = to; + info.len = len; + m_traps.insert_or_assign(from, info); } private: diff --git a/public/safetyhook/safetyhook.hpp b/public/safetyhook/safetyhook.hpp index 70453d867f..701f71d7ce 100644 --- a/public/safetyhook/safetyhook.hpp +++ b/public/safetyhook/safetyhook.hpp @@ -297,8 +297,9 @@ template constexpr void store(uint8_t* address, const T& value) { std::copy_n(reinterpret_cast(&value), sizeof(T), address); } -template -concept FnPtr = requires(T f) { std::is_pointer_v&& std::is_function_v>; }; +//template +//concept FnPtr = requires(T f) { std::is_pointer_v&& std::is_function_v>; }; +typedef void* FnPtr; bool is_executable(uint8_t* address); @@ -364,46 +365,71 @@ class InlineHook final { /// @param err The Allocator::Error that failed. /// @return The new BAD_ALLOCATION error. [[nodiscard]] static Error bad_allocation(Allocator::Error err) { - return {.type = BAD_ALLOCATION, .allocator_error = err}; + Error retErr; + retErr.type = BAD_ALLOCATION; + retErr.allocator_error = err; + return retErr; } /// @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(uint8_t* ip) { - return {.type = FAILED_TO_DECODE_INSTRUCTION, .ip = ip}; + Error retErr; + retErr.type = FAILED_TO_DECODE_INSTRUCTION; + retErr.ip = ip; + return retErr; } /// @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(uint8_t* ip) { - return {.type = SHORT_JUMP_IN_TRAMPOLINE, .ip = ip}; + Error retErr; + retErr.type = SHORT_JUMP_IN_TRAMPOLINE; + retErr.ip = ip; + return retErr; } /// @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(uint8_t* ip) { - return {.type = IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE, .ip = ip}; + Error retErr; + retErr.type = IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE; + retErr.ip = ip; + return retErr; } /// @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(uint8_t* ip) { - return {.type = UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE, .ip = ip}; + Error retErr; + retErr.type = UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE; + retErr.ip = ip; + return retErr; } /// @brief Create a FAILED_TO_UNPROTECT error. /// @param ip The IP of the problematic instruction. /// @return The new FAILED_TO_UNPROTECT error. - [[nodiscard]] static Error failed_to_unprotect(uint8_t* ip) { return {.type = FAILED_TO_UNPROTECT, .ip = ip}; } + [[nodiscard]] static Error failed_to_unprotect(uint8_t* ip) { + Error retErr; + retErr.type = FAILED_TO_UNPROTECT; + retErr.ip = ip; + return retErr; + } /// @brief Create a NOT_ENOUGH_SPACE error. /// @param ip The IP of the problematic instruction. /// @return The new NOT_ENOUGH_SPACE error. - [[nodiscard]] static Error not_enough_space(uint8_t* ip) { return {.type = NOT_ENOUGH_SPACE, .ip = ip}; } + [[nodiscard]] static Error not_enough_space(uint8_t* ip) { + Error retErr; + retErr.type = NOT_ENOUGH_SPACE; + retErr.ip = ip; + return retErr; + } }; /// @brief Flags for InlineHook. @@ -429,10 +455,10 @@ class InlineHook final { /// @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 tl::expected create( + /*[[nodiscard]] static tl::expected create( FnPtr auto target, FnPtr auto destination, Flags flags = Default) { return create(reinterpret_cast(target), reinterpret_cast(destination), flags); - } + }*/ /// @brief Create an inline hook with a given Allocator. /// @param allocator The allocator to use. @@ -451,10 +477,10 @@ class InlineHook final { /// @param flags The flags to use. /// @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). - [[nodiscard]] static tl::expected create( + /*[[nodiscard]] static tl::expected create( const std::shared_ptr& allocator, FnPtr auto target, FnPtr auto destination, Flags flags = Default) { return create(allocator, reinterpret_cast(target), reinterpret_cast(destination), flags); - } + }*/ InlineHook() = default; InlineHook(const InlineHook&) = delete; @@ -768,14 +794,20 @@ class MidHook final { /// @param err The Allocator::Error that failed. /// @return The new BAD_ALLOCATION error. [[nodiscard]] static Error bad_allocation(Allocator::Error err) { - return {.type = BAD_ALLOCATION, .allocator_error = err}; + Error retErr; + retErr.type = BAD_ALLOCATION; + retErr.allocator_error = err; + return retErr; } /// @brief Create a BAD_INLINE_HOOK error. /// @param err The InlineHook::Error that failed. /// @return The new BAD_INLINE_HOOK error. [[nodiscard]] static Error bad_inline_hook(InlineHook::Error err) { - return {.type = BAD_INLINE_HOOK, .inline_hook_error = err}; + Error retErr; + retErr.type = BAD_INLINE_HOOK; + retErr.inline_hook_error = err; + return retErr; } }; @@ -802,10 +834,10 @@ class MidHook final { /// @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 tl::expected create( + /*[[nodiscard]] static tl::expected create( FnPtr auto target, MidHookFn destination_fn, Flags flags = Default) { return create(reinterpret_cast(target), destination_fn, flags); - } + }*/ /// @brief Creates a new MidHook object with a given Allocator. /// @param allocator The Allocator to use. @@ -825,10 +857,10 @@ class MidHook final { /// @param flags The flags to use. /// @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). - [[nodiscard]] static tl::expected create(const std::shared_ptr& allocator, + /*[[nodiscard]] static tl::expected create(const std::shared_ptr& allocator, FnPtr auto target, MidHookFn destination_fn, Flags flags = Default) { return create(allocator, reinterpret_cast(target), destination_fn, flags); - } + }*/ MidHook() = default; MidHook(const MidHook&) = delete; @@ -999,7 +1031,10 @@ class VmtHook final { /// @param err The Allocator::Error that failed. /// @return The new BAD_ALLOCATION error. [[nodiscard]] static Error bad_allocation(Allocator::Error err) { - return {.type = BAD_ALLOCATION, .allocator_error = err}; + Error retErr; + retErr.type = BAD_ALLOCATION; + retErr.allocator_error = err; + return retErr; } }; @@ -1030,7 +1065,7 @@ class VmtHook final { /// @brief Hooks a method in the VMT. /// @param index The index of the method to hook. /// @param new_function The new function to use. - [[nodiscard]] tl::expected hook_method(size_t index, FnPtr auto new_function) { + [[nodiscard]] tl::expected hook_method(size_t index, FnPtr new_function) { VmHook hook{}; ++index; // Skip RTTI pointer. @@ -1068,10 +1103,10 @@ namespace safetyhook { /// @param destination The address of the destination function. /// @param flags The flags to use. /// @return The InlineHook object. -[[nodiscard]] InlineHook create_inline( +/*[[nodiscard]] InlineHook create_inline( FnPtr auto target, FnPtr auto destination, InlineHook::Flags flags = InlineHook::Default) { return create_inline(reinterpret_cast(target), reinterpret_cast(destination), flags); -} +}*/ /// @brief Easy to use API for creating a MidHook. /// @param target the address of the function to hook. @@ -1085,9 +1120,9 @@ namespace safetyhook { /// @param destination The destination function. /// @param flags The flags to use. /// @return The MidHook object. -[[nodiscard]] MidHook create_mid(FnPtr auto target, MidHookFn destination, MidHook::Flags flags = MidHook::Default) { +/*[[nodiscard]] MidHook create_mid(FnPtr auto target, MidHookFn destination, MidHook::Flags flags = MidHook::Default) { return create_mid(reinterpret_cast(target), destination, flags); -} +}*/ /// @brief Easy to use API for creating a VmtHook. /// @param object The object to hook. @@ -1099,7 +1134,7 @@ namespace safetyhook { /// @param index The index of the method to hook. /// @param destination The destination function. /// @return The VmHook object. -[[nodiscard]] VmHook create_vm(VmtHook& vmt, size_t index, FnPtr auto destination) { +[[nodiscard]] inline VmHook create_vm(VmtHook& vmt, size_t index, FnPtr destination) { if (auto hook = vmt.hook_method(index, destination)) { return std::move(*hook); } else {