plugify 1.0.0.0
Loading...
Searching...
No Matches
mem_hook.hpp
1#pragma once
2
3#include "mem_protector.hpp"
4
5namespace plugify {
17 template<typename F> requires(std::is_pointer_v<F> && std::is_function_v<std::remove_pointer_t<F>>)
18 F HookMethod(void* vtp, F func, int offset) {
19 const uintptr_t vtable = *reinterpret_cast<uintptr_t*>(vtp);
20 const uintptr_t entry = vtable + (static_cast<size_t>(offset) * sizeof(void*));
21 const uintptr_t orig = *reinterpret_cast<uintptr_t*>(entry);
22 MemProtector memProtector(entry, sizeof(entry), ProtFlag::RWX);
23 *reinterpret_cast<uintptr_t*>(entry) = reinterpret_cast<uintptr_t>(func);
24 return reinterpret_cast<F>(orig);
25 }
26
38 template<typename F>
39 int GetVirtualTableIndex(F func, ProtFlag flag = ProtFlag::RWX) {
40 void* ptr = (void*&)func;
41
42 constexpr size_t size = 12;
43
44 MemProtector protector(ptr, size, flag);
45
46#if defined(__GNUC__) || defined(__clang__)
47 struct GCC_MemFunPtr {
48 union {
49 void* adrr; // always even
50 intptr_t vti_plus1; // vindex+1, always odd
51 };
52 intptr_t delta;
53 };
54
55 int vtindex;
56 auto mfp_detail = (GCC_MemFunPtr*)&ptr;
57 if (mfp_detail->vti_plus1 & 1) {
58 vtindex = (mfp_detail->vti_plus1 - 1) / sizeof(void*);
59 } else {
60 vtindex = -1;
61 }
62
63 return vtindex;
64#elif defined(_MSC_VER)
65 // https://www.unknowncheats.me/forum/c-and-c-/102577-vtable-index-pure-virtual-function.html
66
67 // Check whether it's a virtual function call on x86
68
69 // They look like this:a
70 // 0: 8b 01 mov eax,DWORD PTR [ecx]
71 // 2: ff 60 04 jmp DWORD PTR [eax+0x4]
72 // ==OR==
73 // 0: 8b 01 mov eax,DWORD PTR [ecx]
74 // 2: ff a0 18 03 00 00 jmp DWORD PTR [eax+0x318]]
75
76 // However, for vararg functions, they look like this:
77 // 0: 8b 44 24 04 mov eax,DWORD PTR [esp+0x4]
78 // 4: 8b 00 mov eax,DWORD PTR [eax]
79 // 6: ff 60 08 jmp DWORD PTR [eax+0x8]
80 // ==OR==
81 // 0: 8b 44 24 04 mov eax,DWORD PTR [esp+0x4]
82 // 4: 8b 00 mov eax,DWORD PTR [eax]
83 // 6: ff a0 18 03 00 00 jmp DWORD PTR [eax+0x318]
84 // With varargs, the this pointer is passed as if it was the first argument
85
86 // On x64
87 // 0: 48 8b 01 mov rax,QWORD PTR [rcx]
88 // 3: ff 60 04 jmp QWORD PTR [rax+0x4]
89 // ==OR==
90 // 0: 48 8b 01 mov rax,QWORD PTR [rcx]
91 // 3: ff a0 18 03 00 00 jmp QWORD PTR [rax+0x318]
92 auto finder = [&](uint8_t* addr) {
93 std::unique_ptr<MemProtector> protector;
94
95 if (*addr == 0xE9) {
96 // May or may not be!
97 // Check where it'd jump
98 addr += 5 /*size of the instruction*/ + *(uint32_t*)(addr + 1);
99
100 protector = std::make_unique<MemProtector>(addr, size, flag);
101 }
102
103 bool ok = false;
104#if INTPTR_MAX == INT64_MAX
105 if (addr[0] == 0x48 && addr[1] == 0x8B && addr[2] == 0x01) {
106 addr += 3;
107 ok = true;
108 } else
109#endif
110 if (addr[0] == 0x8B && addr[1] == 0x01) {
111 addr += 2;
112 ok = true;
113 } else if (addr[0] == 0x8B && addr[1] == 0x44 && addr[2] == 0x24 && addr[3] == 0x04 && addr[4] == 0x8B && addr[5] == 0x00) {
114 addr += 6;
115 ok = true;
116 }
117
118 if (!ok)
119 return -1;
120
121 constexpr int PtrSize = static_cast<int>(sizeof(void*));
122
123 if (*addr++ == 0xFF) {
124 if (*addr == 0x60)
125 return *++addr / PtrSize;
126 else if (*addr == 0xA0)
127 return int(*((uint32_t*)++addr)) / PtrSize;
128 else if (*addr == 0x20)
129 return 0;
130 else
131 return -1;
132 }
133
134 return -1;
135 };
136
137 return finder((uint8_t*)ptr);
138#else
139#error "Compiler not support"
140#endif
141 }
142} // namespace plugify