Skip to content

Commit

Permalink
Downgrade to C++17
Browse files Browse the repository at this point in the history
  • Loading branch information
Kenzzer committed May 19, 2024
1 parent 2ee9a48 commit aaf79df
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 54 deletions.
4 changes: 2 additions & 2 deletions AMBuildScript
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -330,7 +330,7 @@ class SMConfig(object):
'/EHsc',
'/GR-',
'/TP',
'/std:c++20',
'/std:c++17',
]
cxx.linkflags += [
'kernel32.lib',
Expand Down
62 changes: 36 additions & 26 deletions public/safetyhook/safetyhook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t*, OsError> vm_allocate(uint8_t* address, size_t size, VmAccess access);
Expand Down Expand Up @@ -1357,10 +1361,14 @@ tl::expected<uint8_t*, Allocator::Error> Allocator::allocate_nearby_memory(
}

bool Allocator::in_range(uint8_t* address, const std::vector<uint8_t*>& 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() {
Expand Down Expand Up @@ -1454,18 +1462,18 @@ tl::expected<VmBasicInfo, OsError> 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<uint8_t*>(mbi.AllocationBase),
.size = mbi.RegionSize,
.access = access,
.is_free = mbi.State == MEM_FREE,
};
VmBasicInfo retInfo;
retInfo.address = static_cast<uint8_t*>(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) {
Expand Down Expand Up @@ -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:
Expand Down
87 changes: 61 additions & 26 deletions public/safetyhook/safetyhook.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,9 @@ template <typename T> constexpr void store(uint8_t* address, const T& value) {
std::copy_n(reinterpret_cast<const uint8_t*>(&value), sizeof(T), address);
}

template <typename T>
concept FnPtr = requires(T f) { std::is_pointer_v<T>&& std::is_function_v<std::remove_pointer_t<T>>; };
//template <typename T>
//concept FnPtr = requires(T f) { std::is_pointer_v<T>&& std::is_function_v<std::remove_pointer_t<T>>; };
typedef void* FnPtr;

bool is_executable(uint8_t* address);

Expand Down Expand Up @@ -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.
Expand All @@ -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<InlineHook, Error> create(
/*[[nodiscard]] static tl::expected<InlineHook, Error> create(
FnPtr auto target, FnPtr auto destination, Flags flags = Default) {
return create(reinterpret_cast<void*>(target), reinterpret_cast<void*>(destination), flags);
}
}*/

/// @brief Create an inline hook with a given Allocator.
/// @param allocator The allocator to use.
Expand All @@ -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<InlineHook, Error> create(
/*[[nodiscard]] static tl::expected<InlineHook, Error> create(
const std::shared_ptr<Allocator>& allocator, FnPtr auto target, FnPtr auto destination, Flags flags = Default) {
return create(allocator, reinterpret_cast<void*>(target), reinterpret_cast<void*>(destination), flags);
}
}*/

InlineHook() = default;
InlineHook(const InlineHook&) = delete;
Expand Down Expand Up @@ -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;
}
};

Expand All @@ -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<MidHook, Error> create(
/*[[nodiscard]] static tl::expected<MidHook, Error> create(
FnPtr auto target, MidHookFn destination_fn, Flags flags = Default) {
return create(reinterpret_cast<void*>(target), destination_fn, flags);
}
}*/

/// @brief Creates a new MidHook object with a given Allocator.
/// @param allocator The Allocator to use.
Expand All @@ -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<MidHook, Error> create(const std::shared_ptr<Allocator>& allocator,
/*[[nodiscard]] static tl::expected<MidHook, Error> create(const std::shared_ptr<Allocator>& allocator,
FnPtr auto target, MidHookFn destination_fn, Flags flags = Default) {
return create(allocator, reinterpret_cast<void*>(target), destination_fn, flags);
}
}*/

MidHook() = default;
MidHook(const MidHook&) = delete;
Expand Down Expand Up @@ -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;
}
};

Expand Down Expand Up @@ -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<VmHook, Error> hook_method(size_t index, FnPtr auto new_function) {
[[nodiscard]] tl::expected<VmHook, Error> hook_method(size_t index, FnPtr new_function) {
VmHook hook{};

++index; // Skip RTTI pointer.
Expand Down Expand Up @@ -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<void*>(target), reinterpret_cast<void*>(destination), flags);
}
}*/

/// @brief Easy to use API for creating a MidHook.
/// @param target the address of the function to hook.
Expand All @@ -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<void*>(target), destination, flags);
}
}*/

/// @brief Easy to use API for creating a VmtHook.
/// @param object The object to hook.
Expand All @@ -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 {
Expand Down

0 comments on commit aaf79df

Please sign in to comment.