Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Feat/MidHook Improvements #39

Merged
merged 3 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions include/safetyhook/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,31 @@
#include <cstdint>

namespace safetyhook {
union Xmm {
uint8_t u8[16];
uint16_t u16[8];
uint32_t u32[4];
uint64_t u64[2];
float f32[4];
double f64[2];
};

/// @brief Context structure for 64-bit MidHook.
/// @details This structure is used to pass the context of the hooked function to the destination allowing full access
/// to the 64-bit registers at the moment the hook is called.
/// @note The structure only provides access to integer registers.
/// @note rip will point to a trampoline containing the replaced instruction(s).
struct Context64 {
uintptr_t rflags, r15, r14, r13, r12, r11, r10, r9, r8, rdi, rsi, rdx, rcx, rbx, rax, rbp, rsp;
Xmm xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15;
uintptr_t rflags, r15, r14, r13, r12, r11, r10, r9, r8, rdi, rsi, rdx, rcx, rbx, rax, rbp, rsp, rip;
};

/// @brief Context structure for 32-bit MidHook.
/// @details This structure is used to pass the context of the hooked function to the destination allowing full access
/// to the 32-bit registers at the moment the hook is called.
/// @note The structure only provides access to integer registers.
/// @note eip will point to a trampoline containing the replaced instruction(s).
struct Context32 {
uintptr_t eflags, edi, esi, edx, ecx, ebx, eax, ebp, esp;
Xmm xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
uintptr_t eflags, edi, esi, edx, ecx, ebx, eax, ebp, esp, eip;
};

/// @brief Context structure for MidHook.
Expand Down
47 changes: 34 additions & 13 deletions src/mid_hook.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <algorithm>
#include <array>

#include <safetyhook/allocator.hpp>
#include <safetyhook/inline_hook.hpp>
Expand All @@ -9,16 +10,36 @@
namespace safetyhook {

#ifdef _M_X64
constexpr uint8_t asm_data[] = {0x54, 0x55, 0x50, 0x53, 0x51, 0x52, 0x56, 0x57, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52,
0x41, 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x9C, 0x48, 0x8D, 0x0C, 0x24, 0x48, 0x89, 0xE3, 0x48,
0x83, 0xEC, 0x30, 0x48, 0x83, 0xE4, 0xF0, 0xFF, 0x15, 0x22, 0x00, 0x00, 0x00, 0x48, 0x89, 0xDC, 0x9D, 0x41, 0x5F,
0x41, 0x5E, 0x41, 0x5D, 0x41, 0x5C, 0x41, 0x5B, 0x41, 0x5A, 0x41, 0x59, 0x41, 0x58, 0x5F, 0x5E, 0x5A, 0x59, 0x5B,
0x58, 0x5D, 0x5C, 0xFF, 0x25, 0x08, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
constexpr auto asm_data = std::to_array<uint8_t>({0xff, 0x35, 0x5c, 0x01, 0x00, 0x00, 0x54, 0x55, 0x50, 0x53, 0x51,
0x52, 0x56, 0x57, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57,
0x9c, 0x48, 0x81, 0xec, 0x00, 0x01, 0x00, 0x00, 0xf3, 0x44, 0x0f, 0x7f, 0xbc, 0x24, 0x10, 0xff, 0xff, 0xff, 0xf3,
0x44, 0x0f, 0x7f, 0xb4, 0x24, 0x20, 0xff, 0xff, 0xff, 0xf3, 0x44, 0x0f, 0x7f, 0xac, 0x24, 0x30, 0xff, 0xff, 0xff,
0xf3, 0x44, 0x0f, 0x7f, 0xa4, 0x24, 0x40, 0xff, 0xff, 0xff, 0xf3, 0x44, 0x0f, 0x7f, 0x9c, 0x24, 0x50, 0xff, 0xff,
0xff, 0xf3, 0x44, 0x0f, 0x7f, 0x94, 0x24, 0x60, 0xff, 0xff, 0xff, 0xf3, 0x44, 0x0f, 0x7f, 0x8c, 0x24, 0x70, 0xff,
0xff, 0xff, 0xf3, 0x44, 0x0f, 0x7f, 0x44, 0x24, 0x80, 0xf3, 0x0f, 0x7f, 0x7c, 0x24, 0x90, 0xf3, 0x0f, 0x7f, 0x74,
0x24, 0xa0, 0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0xb0, 0xf3, 0x0f, 0x7f, 0x64, 0x24, 0xc0, 0xf3, 0x0f, 0x7f, 0x5c, 0x24,
0xd0, 0xf3, 0x0f, 0x7f, 0x54, 0x24, 0xe0, 0xf3, 0x0f, 0x7f, 0x4c, 0x24, 0xf0, 0xf3, 0x0f, 0x7f, 0x04, 0x24, 0x48,
0x8d, 0x0c, 0x24, 0x48, 0x89, 0xe3, 0x48, 0x83, 0xec, 0x30, 0x48, 0x83, 0xe4, 0xf0, 0xff, 0x15, 0xa3, 0x00, 0x00,
0x00, 0x48, 0x89, 0xdc, 0xf3, 0x0f, 0x6f, 0x04, 0x24, 0xf3, 0x0f, 0x6f, 0x4c, 0x24, 0x10, 0xf3, 0x0f, 0x6f, 0x54,
0x24, 0x20, 0xf3, 0x0f, 0x6f, 0x5c, 0x24, 0x30, 0xf3, 0x0f, 0x6f, 0x64, 0x24, 0x40, 0xf3, 0x0f, 0x6f, 0x6c, 0x24,
0x50, 0xf3, 0x0f, 0x6f, 0x74, 0x24, 0x60, 0xf3, 0x0f, 0x6f, 0x7c, 0x24, 0x70, 0xf3, 0x44, 0x0f, 0x6f, 0x84, 0x24,
0x80, 0x00, 0x00, 0x00, 0xf3, 0x44, 0x0f, 0x6f, 0x8c, 0x24, 0x90, 0x00, 0x00, 0x00, 0xf3, 0x44, 0x0f, 0x6f, 0x94,
0x24, 0xa0, 0x00, 0x00, 0x00, 0xf3, 0x44, 0x0f, 0x6f, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00, 0xf3, 0x44, 0x0f, 0x6f,
0xa4, 0x24, 0xc0, 0x00, 0x00, 0x00, 0xf3, 0x44, 0x0f, 0x6f, 0xac, 0x24, 0xd0, 0x00, 0x00, 0x00, 0xf3, 0x44, 0x0f,
0x6f, 0xb4, 0x24, 0xe0, 0x00, 0x00, 0x00, 0xf3, 0x44, 0x0f, 0x6f, 0xbc, 0x24, 0xf0, 0x00, 0x00, 0x00, 0x48, 0x81,
0xc4, 0x00, 0x01, 0x00, 0x00, 0x9d, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x41, 0x5b, 0x41, 0x5a, 0x41,
0x59, 0x41, 0x58, 0x5f, 0x5e, 0x5a, 0x59, 0x5b, 0x58, 0x5d, 0x5c, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
#else
constexpr uint8_t asm_data[] = {0x54, 0x55, 0x50, 0x53, 0x51, 0x52, 0x56, 0x57, 0x9C, 0x54, 0xFF, 0x15, 0x00, 0x00,
0x00, 0x00, 0x83, 0xC4, 0x04, 0x9D, 0x5F, 0x5E, 0x5A, 0x59, 0x5B, 0x58, 0x5D, 0x5C, 0xFF, 0x25, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
constexpr auto asm_data = std::to_array<uint8_t>({0xff, 0x35, 0x91, 0x00, 0x00, 0x00, 0x54, 0x55, 0x50, 0x53, 0x51,
0x52, 0x56, 0x57, 0x9c, 0x81, 0xec, 0x80, 0x00, 0x00, 0x00, 0xf3, 0x0f, 0x7f, 0x7c, 0x24, 0x90, 0xf3, 0x0f, 0x7f,
0x74, 0x24, 0xa0, 0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0xb0, 0xf3, 0x0f, 0x7f, 0x64, 0x24, 0xc0, 0xf3, 0x0f, 0x7f, 0x5c,
0x24, 0xd0, 0xf3, 0x0f, 0x7f, 0x54, 0x24, 0xe0, 0xf3, 0x0f, 0x7f, 0x4c, 0x24, 0xf0, 0xf3, 0x0f, 0x7f, 0x04, 0x24,
0x54, 0xff, 0x15, 0x8d, 0x00, 0x00, 0x00, 0x83, 0xc4, 0x04, 0xf3, 0x0f, 0x6f, 0x04, 0x24, 0xf3, 0x0f, 0x6f, 0x4c,
0x24, 0x10, 0xf3, 0x0f, 0x6f, 0x54, 0x24, 0x20, 0xf3, 0x0f, 0x6f, 0x5c, 0x24, 0x30, 0xf3, 0x0f, 0x6f, 0x64, 0x24,
0x40, 0xf3, 0x0f, 0x6f, 0x6c, 0x24, 0x50, 0xf3, 0x0f, 0x6f, 0x74, 0x24, 0x60, 0xf3, 0x0f, 0x6f, 0x7c, 0x24, 0x70,
0x81, 0xc4, 0x80, 0x00, 0x00, 0x00, 0x9d, 0x5f, 0x5e, 0x5a, 0x59, 0x5b, 0x58, 0x5d, 0x5c, 0xc3, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00});
#endif

std::expected<MidHook, MidHook::Error> MidHook::create(void* target, MidHookFn destination) {
Expand Down Expand Up @@ -64,24 +85,24 @@ std::expected<void, MidHook::Error> MidHook::setup(
m_target = target;
m_destination = destination;

auto stub_allocation = allocator->allocate(sizeof(asm_data));
auto stub_allocation = allocator->allocate(asm_data.size());

if (!stub_allocation) {
return std::unexpected{Error::bad_allocation(stub_allocation.error())};
}

m_stub = std::move(*stub_allocation);

std::copy_n(asm_data, sizeof(asm_data), m_stub.data());
std::copy(asm_data.begin(), asm_data.end(), m_stub.data());

#ifdef _M_X64
store(m_stub.data() + sizeof(asm_data) - 16, m_destination);
#else
store(m_stub.data() + sizeof(asm_data) - 8, m_destination);

// 32-bit has some relocations we need to fix up as well.
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);
store(m_stub.data() + 0x02, m_stub.data() + m_stub.size() - 4);
store(m_stub.data() + 0x47, m_stub.data() + m_stub.size() - 8);
#endif

auto hook_result = InlineHook::create(allocator, m_target, m_stub.data());
Expand Down
28 changes: 24 additions & 4 deletions src/mid_hook.x86.asm
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
bits 32

; save context
push dword [trampoline]
push esp
push ebp
push eax
Expand All @@ -8,13 +11,31 @@ push edx
push esi
push edi
pushfd
sub esp, 128
movdqu [esp-112], xmm7
movdqu [esp-96], xmm6
movdqu [esp-80], xmm5
movdqu [esp-64], xmm4
movdqu [esp-48], xmm3
movdqu [esp-32], xmm2
movdqu [esp-16], xmm1
movdqu [esp], xmm0

; call destination
push esp
call [destination]
add esp, 4

; restore context
movdqu xmm0, [esp]
movdqu xmm1, [esp+16]
movdqu xmm2, [esp+32]
movdqu xmm3, [esp+48]
movdqu xmm4, [esp+64]
movdqu xmm5, [esp+80]
movdqu xmm6, [esp+96]
movdqu xmm7, [esp+112]
add esp, 128
popfd
pop edi
pop esi
Expand All @@ -24,10 +45,9 @@ pop ebx
pop eax
pop ebp
pop esp

jmp [trampoline]
ret

destination:
.dd 0
dd 0
trampoline:
.dd 0
dd 0
48 changes: 42 additions & 6 deletions src/mid_hook.x86_64.asm
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
; save context
bits 64

; save context
push qword [rel trampoline]
push rsp
push rbp
push rax
Expand All @@ -16,6 +19,23 @@ push r13
push r14
push r15
pushfq
sub rsp, 256
movdqu [rsp-240], xmm15
movdqu [rsp-224], xmm14
movdqu [rsp-208], xmm13
movdqu [rsp-192], xmm12
movdqu [rsp-176], xmm11
movdqu [rsp-160], xmm10
movdqu [rsp-144], xmm9
movdqu [rsp-128], xmm8
movdqu [rsp-112], xmm7
movdqu [rsp-96], xmm6
movdqu [rsp-80], xmm5
movdqu [rsp-64], xmm4
movdqu [rsp-48], xmm3
movdqu [rsp-32], xmm2
movdqu [rsp-16], xmm1
movdqu [rsp], xmm0

; set destination parameter
lea rcx, [rsp]
Expand All @@ -26,12 +46,29 @@ sub rsp, 48
and rsp, -16

; call destination
call [destination]
call [rel destination]

; restore stack
mov rsp, rbx

; restore context
movdqu xmm0, [rsp]
movdqu xmm1, [rsp+16]
movdqu xmm2, [rsp+32]
movdqu xmm3, [rsp+48]
movdqu xmm4, [rsp+64]
movdqu xmm5, [rsp+80]
movdqu xmm6, [rsp+96]
movdqu xmm7, [rsp+112]
movdqu xmm8, [rsp+128]
movdqu xmm9, [rsp+144]
movdqu xmm10, [rsp+160]
movdqu xmm11, [rsp+176]
movdqu xmm12, [rsp+192]
movdqu xmm13, [rsp+208]
movdqu xmm14, [rsp+224]
movdqu xmm15, [rsp+240]
add rsp, 256
popfq
pop r15
pop r14
Expand All @@ -49,10 +86,9 @@ pop rbx
pop rax
pop rbp
pop rsp

jmp [trampoline]
ret

destination:
.dq 0
dq 0
trampoline:
.dq 0
dq 0
30 changes: 29 additions & 1 deletion unittest/mid_hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,32 @@ TEST_CASE("Mid hook to change a register", "[mid_hook]") {
hook.reset();

REQUIRE(Target::add_42(2) == 44);
}
}

#ifdef _M_X64
TEST_CASE("Mid hook to change an XMM register", "[mid_hook]") {
struct Target {
__declspec(noinline) static float __fastcall add_42(float a) { return a + 0.42f; }
};

REQUIRE(Target::add_42(0.0f) == 0.42f);

static SafetyHookMid hook;

struct Hook {
static void add_42(SafetyHookContext& ctx) { ctx.xmm0.f32[0] = 1337.0f - 0.42f; }
};

auto hook_result = SafetyHookMid::create(Target::add_42, Hook::add_42);

REQUIRE(hook_result);

hook = std::move(*hook_result);

REQUIRE(Target::add_42(1.0f) == 1337.0f);

hook.reset();

REQUIRE(Target::add_42(2.0f) == 2.42f);
}
#endif