CommonLib
Loading...
Searching...
No Matches
mem_x86.inl
Go to the documentation of this file.
1#include "ut/preprocessor.h"
2
3namespace hedgedev::csl::mem
4{
5 enum class branch_type
6 {
10 };
11
18
38
39 inline bool is_nop(void* in_address)
40 {
41 return in_address && read<uint8_t>(in_address) == 0x90;
42 }
43
45 {
46 branch_info result{};
47
48 if (!in_address)
49 return result;
50
51 const auto b0 = read<uint8_t>(in_address);
52 const auto b1 = read<uint8_t>(reinterpret_cast<uint8_t*>(in_address) + 1);
53
54 if ((b0 & 0xF0) == 0x70 || b0 == 0x0F)
55 {
56 result.type = branch_type::conditional;
57
58 if (b0 == 0x0F)
59 {
60 result.distance = branch_distance::near_branch;
61 result.condition = branch_condition(b1 & ~0x80);
62 result.opcode_length = 2;
63 result.instr_length = 6;
64 }
65 else
66 {
67 result.distance = branch_distance::short_branch;
68 result.condition = branch_condition(b0 & ~0x70);
69 result.opcode_length = 1;
70 result.instr_length = 2;
71 }
72 }
73 else
74 {
75 if (b0 == 0xFF)
76 {
77 result.type = b1 == 0x15 ? branch_type::call : branch_type::jump;
78 result.distance = branch_distance::far_branch;
79#ifdef CMNLIB_X64
80 result.opcode_length = 6;
81 result.instr_length = 14;
82#else
83 result.opcode_length = 2;
84 result.instr_length = 6;
85#endif
86 }
87 else if (b0 == 0xEB)
88 {
89 result.type = branch_type::jump;
90 result.distance = branch_distance::short_branch;
91 result.opcode_length = 1;
92 result.instr_length = 2;
93 }
94 else
95 {
96 result.type = b0 == 0xE8 ? branch_type::call : branch_type::jump;
97 result.distance = branch_distance::near_branch;
98 result.opcode_length = 1;
99 result.instr_length = 5;
100 }
101 }
102
103 const auto imm_offset = uintptr_t(in_address) + result.opcode_length;
104
105 ptrdiff_t rva{};
106
107 switch (result.distance)
108 {
110 rva = *reinterpret_cast<int8_t*>(imm_offset);
111 break;
112
114 rva = *reinterpret_cast<int32_t*>(imm_offset);
115 break;
116
118 result.destination = reinterpret_cast<void*>(*reinterpret_cast<uintptr_t*>(imm_offset));
119 return result;
120 }
121
122 result.destination = reinterpret_cast<void*>(uintptr_t(in_address) + rva + result.instr_length);
123
124 return result;
125 }
126
127 template <typename T>
128 inline void* read_instr_address(void* in_address, ptrdiff_t in_offset, size_t in_stride)
129 {
130 if (!in_address)
131 return nullptr;
132
133 return reinterpret_cast<void*>((uintptr_t(in_address) + *reinterpret_cast<T*>(uintptr_t(in_address) + in_offset)) + in_stride);
134 }
135
136 inline void* read_call(void* in_address)
137 {
138 return read_jump(in_address);
139 }
140
141 inline void* read_jump(void* in_address)
142 {
143 return get_branch_info(in_address).destination;
144 }
145
146 inline bool write_call(void* in_address, void* in_destination)
147 {
148 return write_jump(in_address, in_destination, true);
149 }
150
151 inline bool write_jump(void* in_address, void* in_destination, bool in_isCall)
152 {
153 if (!in_address)
154 return false;
155
156 const auto rva = ptrdiff_t(in_destination) - ptrdiff_t(in_address);
157
158 if (rva - 2 <= 0x7F && !in_isCall)
159 {
160 ASSERT_RETURN_FALSE(write<uint8_t>(in_address, 0xEB));
161 ASSERT_RETURN_FALSE(write<int8_t>(reinterpret_cast<uint8_t*>(in_address) + 1, int8_t(rva - 2)));
162 }
163 else
164 {
165 if (rva - 5 <= 0x7FFFFFFF)
166 {
167 ASSERT_RETURN_FALSE(write<uint8_t>(in_address, in_isCall ? 0xE8 : 0xE9));
168 ASSERT_RETURN_FALSE(write<int32_t>(reinterpret_cast<uint8_t*>(in_address) + 1, int32_t(rva - 5)));
169 }
170 else
171 {
172 ASSERT_RETURN_FALSE(write<uint8_t>(in_address, 0xFF));
173 ASSERT_RETURN_FALSE(write<uint8_t>(reinterpret_cast<uint8_t*>(in_address) + 1, in_isCall ? 0x15 : 0x25));
174#ifdef CMNLIB_X64
175 ASSERT_RETURN_FALSE(write<uint32_t>(reinterpret_cast<uint8_t*>(in_address) + 2, 0));
176
177 const ptrdiff_t imm_offset = 6;
178#else
179 const ptrdiff_t imm_offset = 2;
180#endif
181 ASSERT_RETURN_FALSE(write<uintptr_t>(reinterpret_cast<uint8_t*>(in_address) + imm_offset, uintptr_t(in_destination)));
182 }
183 }
184
185 return true;
186 }
187
188 inline bool write_nop(void* in_address, size_t in_count)
189 {
190 return write<uint8_t>(in_address, 0x90, in_count);
191 }
192}
Definition mem.h:169
void * read_jump(void *in_address)
Definition mem_x86.inl:141
void * read_call(void *in_address)
Definition mem_x86.inl:136
void * read_instr_address(void *in_address, ptrdiff_t in_offset, size_t in_stride)
Definition mem_x86.inl:128
branch_info get_branch_info(void *in_address)
Definition mem_x86.inl:44
bool write_jump(void *in_address, void *in_destination, bool in_call=false)
Definition mem_x86.inl:151
branch_distance
Definition mem_x86.inl:13
@ near_branch
Definition mem_x86.inl:15
@ short_branch
Definition mem_x86.inl:14
@ far_branch
Definition mem_x86.inl:16
bool write_nop(void *in_address, size_t in_count=1)
Definition mem_x86.inl:188
bool is_nop(void *in_address)
Definition mem_x86.inl:39
bool write_call(void *in_address, void *in_destination)
Definition mem_x86.inl:146
branch_condition
Definition mem_x86.inl:20
@ sign
Definition mem_x86.inl:29
@ overflow
Definition mem_x86.inl:21
@ equal
Definition mem_x86.inl:25
@ above
Definition mem_x86.inl:28
@ not_below
Definition mem_x86.inl:24
@ below
Definition mem_x86.inl:23
@ greater
Definition mem_x86.inl:36
@ not_equal
Definition mem_x86.inl:26
@ parity
Definition mem_x86.inl:31
@ not_parity
Definition mem_x86.inl:32
@ not_greater
Definition mem_x86.inl:35
@ not_overflow
Definition mem_x86.inl:22
@ not_less
Definition mem_x86.inl:34
@ less
Definition mem_x86.inl:33
@ below_or_equal
Definition mem_x86.inl:27
@ not_sign
Definition mem_x86.inl:30
branch_type
Definition mem_x86.inl:6
@ call
Definition mem_x86.inl:9
@ conditional
Definition mem_x86.inl:7
@ jump
Definition mem_x86.inl:8
#define ASSERT_RETURN_FALSE(CONDITION)
Definition preprocessor.h:33