@memoryprocess/bindings 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.gyp +46 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +27 -0
- package/dist/memoryprocess.node +0 -0
- package/dist/native.d.ts +128 -0
- package/native/hde/LICENSE-minhook.txt +81 -0
- package/native/hde/hde64.c +538 -0
- package/native/hde/hde64.h +113 -0
- package/native/hde/pstdint.h +39 -0
- package/native/hde/table64.h +74 -0
- package/native/memory.cc +21 -0
- package/native/memory.h +31 -0
- package/native/memoryprocess.cc +43 -0
- package/native/module.cc +1720 -0
- package/native/module.h +55 -0
- package/native/pattern.cc +304 -0
- package/native/process.cc +113 -0
- package/native/process.h +36 -0
- package/package.json +49 -4
- package/README.md +0 -3
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Hacker Disassembler Engine 64 C
|
|
3
|
+
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#if defined(_M_X64) || defined(__x86_64__)
|
|
9
|
+
|
|
10
|
+
#include <string.h>
|
|
11
|
+
#include "hde64.h"
|
|
12
|
+
#include "table64.h"
|
|
13
|
+
|
|
14
|
+
/* An instruction is at most 15 bytes long, so the bytes past that may not be
|
|
15
|
+
* mapped: a decode that would run over the limit stops instead of reading. */
|
|
16
|
+
#define NEED(n) do { if (limit - p < (n)) goto error_length; } while (0)
|
|
17
|
+
|
|
18
|
+
unsigned int hde64_disasm(const void *code, hde64s *hs)
|
|
19
|
+
{
|
|
20
|
+
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0, mand = 0;
|
|
21
|
+
uint8_t map0f = 0; /* the opcode came from the 0F map */
|
|
22
|
+
uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
|
|
23
|
+
uint8_t op64 = 0, rex = 0, rex2 = 0, have_rex2 = 0, ext = 0;
|
|
24
|
+
uint8_t *limit = (uint8_t *)code + 15;
|
|
25
|
+
|
|
26
|
+
memset(hs, 0, sizeof(hde64s));
|
|
27
|
+
|
|
28
|
+
for (x = 15; x; x--)
|
|
29
|
+
switch (c = *p++) {
|
|
30
|
+
case 0xf3:
|
|
31
|
+
hs->p_rep = c;
|
|
32
|
+
pref |= PRE_F3;
|
|
33
|
+
mand = PRE_F3;
|
|
34
|
+
rex = 0;
|
|
35
|
+
break;
|
|
36
|
+
case 0xf2:
|
|
37
|
+
hs->p_rep = c;
|
|
38
|
+
pref |= PRE_F2;
|
|
39
|
+
mand = PRE_F2;
|
|
40
|
+
rex = 0;
|
|
41
|
+
break;
|
|
42
|
+
case 0xf0:
|
|
43
|
+
hs->p_lock = c;
|
|
44
|
+
pref |= PRE_LOCK;
|
|
45
|
+
rex = 0;
|
|
46
|
+
break;
|
|
47
|
+
case 0x26: case 0x2e: case 0x36:
|
|
48
|
+
case 0x3e: case 0x64: case 0x65:
|
|
49
|
+
hs->p_seg = c;
|
|
50
|
+
pref |= PRE_SEG;
|
|
51
|
+
rex = 0;
|
|
52
|
+
break;
|
|
53
|
+
case 0x66:
|
|
54
|
+
hs->p_66 = c;
|
|
55
|
+
pref |= PRE_66;
|
|
56
|
+
if (!mand)
|
|
57
|
+
mand = PRE_66;
|
|
58
|
+
rex = 0;
|
|
59
|
+
break;
|
|
60
|
+
case 0x67:
|
|
61
|
+
hs->p_67 = c;
|
|
62
|
+
pref |= PRE_67;
|
|
63
|
+
rex = 0;
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
if ((c & 0xf0) != 0x40)
|
|
67
|
+
goto pref_done;
|
|
68
|
+
/* REX counts only as the last prefix before the opcode: a
|
|
69
|
+
* legacy prefix after it, or a further REX, discards it. */
|
|
70
|
+
rex = c;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
goto error_length; /* 15 prefixes leave no room for an opcode */
|
|
74
|
+
|
|
75
|
+
pref_done:
|
|
76
|
+
|
|
77
|
+
hs->flags = (uint32_t)pref << 23;
|
|
78
|
+
|
|
79
|
+
if (!pref)
|
|
80
|
+
pref |= PRE_NONE;
|
|
81
|
+
/* pref says which prefix classes are present, which is what an
|
|
82
|
+
* operand-size or LOCK rule asks. A mandatory prefix is a choice
|
|
83
|
+
* between 66, F2 and F3 rather than a set, so the rules that select
|
|
84
|
+
* an instruction read mand instead. */
|
|
85
|
+
if (!mand)
|
|
86
|
+
mand = PRE_NONE;
|
|
87
|
+
|
|
88
|
+
if (rex) {
|
|
89
|
+
hs->flags |= F_PREFIX_REX;
|
|
90
|
+
hs->rex = rex;
|
|
91
|
+
hs->rex_w = (rex & 0xf) >> 3;
|
|
92
|
+
hs->rex_r = (rex & 7) >> 2;
|
|
93
|
+
hs->rex_x = (rex & 3) >> 1;
|
|
94
|
+
hs->rex_b = rex & 1;
|
|
95
|
+
if (hs->rex_w && (c & 0xf8) == 0xb8)
|
|
96
|
+
op64++;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* VEX, EVEX and XOP. C4, C5 and 62 are always escapes in long mode; 8F is
|
|
100
|
+
* one only from map 8 upwards, which leaves 8F /0 as POP. The header names
|
|
101
|
+
* the opcode map, the map decides the immediate, and every instruction
|
|
102
|
+
* reached this way has a ModR/M byte. */
|
|
103
|
+
if (c == 0xc4 || c == 0xc5 || c == 0x62 ||
|
|
104
|
+
(c == 0x8f && p < limit && (*p & 0x1f) >= 8)) {
|
|
105
|
+
uint8_t map;
|
|
106
|
+
|
|
107
|
+
hs->opcode = c;
|
|
108
|
+
if (c == 0xc5) {
|
|
109
|
+
NEED(3);
|
|
110
|
+
map = 1;
|
|
111
|
+
p++;
|
|
112
|
+
} else if (c == 0x62) {
|
|
113
|
+
NEED(5);
|
|
114
|
+
map = *p & 0x07; /* the bit above the map is APX's B4 */
|
|
115
|
+
p += 3;
|
|
116
|
+
} else {
|
|
117
|
+
NEED(4);
|
|
118
|
+
map = *p & 0x1f;
|
|
119
|
+
p += 2;
|
|
120
|
+
}
|
|
121
|
+
hs->opcode2 = opcode = *p++;
|
|
122
|
+
|
|
123
|
+
/* The escape carries the operand size and the register extensions
|
|
124
|
+
* itself, so a 66, F2, F3, LOCK or REX in front of it is invalid. A
|
|
125
|
+
* segment or 67 prefix still applies. */
|
|
126
|
+
if (rex || (pref & (PRE_66 | PRE_F2 | PRE_F3 | PRE_LOCK)))
|
|
127
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
128
|
+
pref &= ~PRE_66;
|
|
129
|
+
|
|
130
|
+
cflags = C_MODRM;
|
|
131
|
+
if (c == 0x8f) {
|
|
132
|
+
switch (map) {
|
|
133
|
+
case 8: /* every XOP8 opcode takes an imm8 */
|
|
134
|
+
cflags |= C_IMM8;
|
|
135
|
+
break;
|
|
136
|
+
case 9: /* no XOP9 opcode takes one */
|
|
137
|
+
break;
|
|
138
|
+
case 10: /* bextr and the lwp forms: imm32 */
|
|
139
|
+
cflags |= C_IMM_P66;
|
|
140
|
+
break;
|
|
141
|
+
default:
|
|
142
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
} else switch (map) {
|
|
146
|
+
case 1: /* 0F map */
|
|
147
|
+
if (opcode == 0x70 || (opcode >= 0x71 && opcode <= 0x73) ||
|
|
148
|
+
opcode == 0xc2 || (opcode >= 0xc4 && opcode <= 0xc6))
|
|
149
|
+
cflags |= C_IMM8;
|
|
150
|
+
else if (c != 0x62 && opcode == 0x77)
|
|
151
|
+
cflags = C_NONE; /* vzeroupper and vzeroall: no ModR/M */
|
|
152
|
+
else if (c != 0x62 && (opcode == 0x84 || opcode == 0x85))
|
|
153
|
+
cflags = C_REL32; /* jkzd and jknzd: rel32, no ModR/M */
|
|
154
|
+
break;
|
|
155
|
+
case 2: /* 0F 38 map: never an immediate */
|
|
156
|
+
break;
|
|
157
|
+
case 3: /* 0F 3A map: always an imm8 */
|
|
158
|
+
cflags |= C_IMM8;
|
|
159
|
+
break;
|
|
160
|
+
case 5: case 6: /* half-precision maps, EVEX only */
|
|
161
|
+
if (c != 0x62)
|
|
162
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
163
|
+
else if (map == 5 && (opcode == 0x08 || opcode == 0x0a ||
|
|
164
|
+
opcode == 0x26 || opcode == 0x27 ||
|
|
165
|
+
opcode == 0x56 || opcode == 0x57 ||
|
|
166
|
+
opcode == 0x66 || opcode == 0x67 ||
|
|
167
|
+
opcode == 0xc2))
|
|
168
|
+
cflags |= C_IMM8; /* the 0F 3A forms of that map */
|
|
169
|
+
break;
|
|
170
|
+
default:
|
|
171
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
ext = 1;
|
|
175
|
+
x = 0;
|
|
176
|
+
goto modrm;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* REX2: D5, a payload byte, then the opcode. The payload names the
|
|
180
|
+
* opcode map in its top bit, so a 0F opcode is reached without the 0F
|
|
181
|
+
* byte, and carries the register extensions, with W where REX keeps it.
|
|
182
|
+
* Only legacy instructions are promoted this way, so the tables give the
|
|
183
|
+
* right shape once the map is known. */
|
|
184
|
+
if (c == 0xd5) {
|
|
185
|
+
NEED(2);
|
|
186
|
+
rex2 = *p++;
|
|
187
|
+
have_rex2 = 1;
|
|
188
|
+
c = *p++;
|
|
189
|
+
hs->flags |= F_PREFIX_REX2;
|
|
190
|
+
if (rex) /* REX2 replaces a REX, it cannot follow one */
|
|
191
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
192
|
+
hs->rex_w = (rex2 & 8) >> 3;
|
|
193
|
+
hs->rex_r = (rex2 & 4) >> 2;
|
|
194
|
+
hs->rex_x = (rex2 & 2) >> 1;
|
|
195
|
+
hs->rex_b = rex2 & 1;
|
|
196
|
+
if (rex2 & 0x80) {
|
|
197
|
+
hs->opcode = 0xd5;
|
|
198
|
+
hs->opcode2 = c;
|
|
199
|
+
map0f = 1;
|
|
200
|
+
ht += DELTA_OPCODES;
|
|
201
|
+
goto opcode_ready;
|
|
202
|
+
}
|
|
203
|
+
/* Map 0 is the one-byte map, and REX2 has to be the last byte
|
|
204
|
+
* before the opcode: neither the 0F escape nor a further prefix
|
|
205
|
+
* can follow it. 8F is deliberately absent, and adding it would be
|
|
206
|
+
* wrong: it is POP here, not an XOP escape, and D5 00 8F C0 is a
|
|
207
|
+
* promoted pop. The other escapes are absent because their opcodes
|
|
208
|
+
* have no table entry, so they are rejected either way. */
|
|
209
|
+
if (c == 0x0f || (c & 0xf0) == 0x40 ||
|
|
210
|
+
c == 0x26 || c == 0x2e || c == 0x36 || c == 0x3e ||
|
|
211
|
+
c == 0x64 || c == 0x65 || c == 0x66 || c == 0x67 ||
|
|
212
|
+
c == 0xf0 || c == 0xf2 || c == 0xf3)
|
|
213
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
214
|
+
if (hs->rex_w && (c & 0xf8) == 0xb8)
|
|
215
|
+
op64++; /* B8+r, map 0's mov r64, imm64 */
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
hs->opcode = c;
|
|
219
|
+
if (!have_rex2 && c == 0x0f) {
|
|
220
|
+
NEED(1);
|
|
221
|
+
hs->opcode2 = c = *p++;
|
|
222
|
+
map0f = 1;
|
|
223
|
+
if (c == 0x38 || c == 0x3a) {
|
|
224
|
+
/* Three-byte maps: the opcode follows and always has a ModR/M
|
|
225
|
+
* byte. Every 0F 3A opcode takes an imm8, no 0F 38 one does, and
|
|
226
|
+
* none of them is lockable. */
|
|
227
|
+
NEED(2);
|
|
228
|
+
opcode = *p++;
|
|
229
|
+
cflags = (c == 0x3a) ? (C_MODRM | C_IMM8) : C_MODRM;
|
|
230
|
+
if (pref & PRE_LOCK)
|
|
231
|
+
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
232
|
+
ext = 1;
|
|
233
|
+
x = 0;
|
|
234
|
+
goto modrm;
|
|
235
|
+
}
|
|
236
|
+
ht += DELTA_OPCODES;
|
|
237
|
+
} else if (c >= 0xa0 && c <= 0xa3) {
|
|
238
|
+
/* moffs: the absolute address is as wide as the address size, so
|
|
239
|
+
* eight bytes unless 67 selects 32-bit addressing. */
|
|
240
|
+
if (!(pref & PRE_67))
|
|
241
|
+
op64++;
|
|
242
|
+
pref &= ~PRE_66;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
opcode_ready:
|
|
246
|
+
opcode = c;
|
|
247
|
+
cflags = ht[ht[opcode / 4] + (opcode % 4)];
|
|
248
|
+
|
|
249
|
+
if (cflags == C_ERROR) {
|
|
250
|
+
/* The table carries no entry for the opcode. Some of these are real
|
|
251
|
+
* instructions whose shape is known, and flagging one denies the caller a
|
|
252
|
+
* length it could have used; the rest keep F_ERROR, because the opcode
|
|
253
|
+
* is not one this engine can claim to know. */
|
|
254
|
+
cflags = 0;
|
|
255
|
+
if (map0f && (opcode == 0x0b ||
|
|
256
|
+
(opcode == 0x37 &&
|
|
257
|
+
mand == PRE_NONE))) {
|
|
258
|
+
; /* ud2 and getsec take no operand */
|
|
259
|
+
} else if (map0f && (opcode == 0xa6 || opcode == 0xa7 ||
|
|
260
|
+
opcode == 0xb9 || opcode == 0xff)) {
|
|
261
|
+
cflags = C_MODRM; /* PadLock, ud1 and ud0 */
|
|
262
|
+
} else if (!map0f && (opcode == 0x9e || opcode == 0x9f)) {
|
|
263
|
+
; /* sahf and lahf, back since 2006 */
|
|
264
|
+
} else {
|
|
265
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
266
|
+
if (map0f && (opcode & -3) == 0x24)
|
|
267
|
+
cflags = C_MODRM; /* the test registers: shape only */
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
x = 0;
|
|
272
|
+
if (cflags & C_GROUP) {
|
|
273
|
+
uint16_t t;
|
|
274
|
+
t = *(uint16_t *)(ht + (cflags & 0x7f));
|
|
275
|
+
cflags = (uint8_t)t;
|
|
276
|
+
x = (uint8_t)(t >> 8);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (map0f) {
|
|
280
|
+
ht = hde64_table + DELTA_PREFIXES;
|
|
281
|
+
/* movntsd and movntss are F2 0F 2B and F3 0F 2B. The row 0F 2B
|
|
282
|
+
* reads rejects both, and it is shared with a neighbour that has
|
|
283
|
+
* no such form, so the exception lives here rather than in the
|
|
284
|
+
* table. */
|
|
285
|
+
if ((ht[ht[opcode / 4] + (opcode % 4)] & mand) &&
|
|
286
|
+
!(opcode == 0x2b && (mand & (PRE_F2 | PRE_F3))))
|
|
287
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
288
|
+
/* vmread, vmwrite and popcnt take a ModR/M byte that the table cannot
|
|
289
|
+
* give them: their entries share a row with opcodes that take none. */
|
|
290
|
+
if (opcode == 0x78 || opcode == 0x79 || opcode == 0xb8)
|
|
291
|
+
cflags |= C_MODRM;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
modrm:
|
|
295
|
+
if (cflags & C_MODRM) {
|
|
296
|
+
hs->flags |= F_MODRM;
|
|
297
|
+
NEED(1);
|
|
298
|
+
hs->modrm = c = *p++;
|
|
299
|
+
hs->modrm_mod = m_mod = c >> 6;
|
|
300
|
+
hs->modrm_rm = m_rm = c & 7;
|
|
301
|
+
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
|
|
302
|
+
|
|
303
|
+
if (x && ((x << m_reg) & 0x80))
|
|
304
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
305
|
+
|
|
306
|
+
if (ext)
|
|
307
|
+
goto no_error_operand; /* no legacy operand rule applies */
|
|
308
|
+
|
|
309
|
+
if (!map0f && opcode >= 0xd9 && opcode <= 0xdf) {
|
|
310
|
+
uint8_t t = opcode - 0xd9;
|
|
311
|
+
if (m_mod == 3) {
|
|
312
|
+
ht = hde64_table + DELTA_FPU_MODRM + t*8;
|
|
313
|
+
t = ht[m_reg] << m_rm;
|
|
314
|
+
} else {
|
|
315
|
+
ht = hde64_table + DELTA_FPU_REG;
|
|
316
|
+
t = ht[t] << m_reg;
|
|
317
|
+
}
|
|
318
|
+
if (t & 0x80)
|
|
319
|
+
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (pref & PRE_LOCK) {
|
|
323
|
+
if (m_mod == 3) {
|
|
324
|
+
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
325
|
+
} else {
|
|
326
|
+
uint8_t *table_end, op = opcode;
|
|
327
|
+
if (map0f) {
|
|
328
|
+
ht = hde64_table + DELTA_OP2_LOCK_OK;
|
|
329
|
+
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
|
|
330
|
+
} else {
|
|
331
|
+
ht = hde64_table + DELTA_OP_LOCK_OK;
|
|
332
|
+
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
|
|
333
|
+
op &= -2;
|
|
334
|
+
}
|
|
335
|
+
for (; ht != table_end; ht++)
|
|
336
|
+
if (*ht++ == op) {
|
|
337
|
+
if (!((*ht << m_reg) & 0x80))
|
|
338
|
+
goto no_lock_error;
|
|
339
|
+
else
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
343
|
+
no_lock_error:
|
|
344
|
+
;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (map0f) {
|
|
349
|
+
switch (opcode) {
|
|
350
|
+
case 0x20: case 0x22:
|
|
351
|
+
m_mod = 3;
|
|
352
|
+
if (m_reg > 4 || m_reg == 1)
|
|
353
|
+
goto error_operand;
|
|
354
|
+
else
|
|
355
|
+
goto no_error_operand;
|
|
356
|
+
case 0x21: case 0x23:
|
|
357
|
+
m_mod = 3;
|
|
358
|
+
/* dr4 and dr5 alias dr6 and dr7 unless CR4.DE is set, so
|
|
359
|
+
* they decode rather than fault. */
|
|
360
|
+
goto no_error_operand;
|
|
361
|
+
}
|
|
362
|
+
} else {
|
|
363
|
+
switch (opcode) {
|
|
364
|
+
case 0x8c:
|
|
365
|
+
if (m_reg > 5)
|
|
366
|
+
goto error_operand;
|
|
367
|
+
else
|
|
368
|
+
goto no_error_operand;
|
|
369
|
+
case 0x8e:
|
|
370
|
+
if (m_reg == 1 || m_reg > 5)
|
|
371
|
+
goto error_operand;
|
|
372
|
+
else
|
|
373
|
+
goto no_error_operand;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (m_mod == 3) {
|
|
378
|
+
uint8_t *table_end;
|
|
379
|
+
if (map0f) {
|
|
380
|
+
ht = hde64_table + DELTA_OP2_ONLY_MEM;
|
|
381
|
+
table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
|
|
382
|
+
} else {
|
|
383
|
+
ht = hde64_table + DELTA_OP_ONLY_MEM;
|
|
384
|
+
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
|
|
385
|
+
}
|
|
386
|
+
for (; ht != table_end; ht += 2)
|
|
387
|
+
if (*ht++ == opcode) {
|
|
388
|
+
if ((*ht++ & mand) && !((*ht << m_reg) & 0x80))
|
|
389
|
+
goto error_operand;
|
|
390
|
+
else
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
goto no_error_operand;
|
|
394
|
+
} else if (map0f) {
|
|
395
|
+
switch (opcode) {
|
|
396
|
+
case 0x50: case 0xd7: case 0xf7:
|
|
397
|
+
if (mand & (PRE_NONE | PRE_66))
|
|
398
|
+
goto error_operand;
|
|
399
|
+
break;
|
|
400
|
+
case 0xd6:
|
|
401
|
+
if (mand & (PRE_F2 | PRE_F3))
|
|
402
|
+
goto error_operand;
|
|
403
|
+
break;
|
|
404
|
+
case 0xc5:
|
|
405
|
+
goto error_operand;
|
|
406
|
+
}
|
|
407
|
+
goto no_error_operand;
|
|
408
|
+
} else
|
|
409
|
+
goto no_error_operand;
|
|
410
|
+
|
|
411
|
+
error_operand:
|
|
412
|
+
hs->flags |= F_ERROR | F_ERROR_OPERAND;
|
|
413
|
+
no_error_operand:
|
|
414
|
+
|
|
415
|
+
/* Group 3: F6 /0 and /1 take an imm8, F7 /0 and /1 an imm32 or imm16.
|
|
416
|
+
* The rule belongs to the one-byte map; 0F F6 and 0F F7 are psadbw
|
|
417
|
+
* and maskmovq, which take neither. */
|
|
418
|
+
if (!ext && !map0f && m_reg <= 1) {
|
|
419
|
+
if (opcode == 0xf6)
|
|
420
|
+
cflags |= C_IMM8;
|
|
421
|
+
else if (opcode == 0xf7)
|
|
422
|
+
cflags |= C_IMM_P66;
|
|
423
|
+
}
|
|
424
|
+
/* C7 /7 is xbegin, whose immediate is a displacement. */
|
|
425
|
+
if (!ext && !map0f && opcode == 0xc7 && m_reg == 7)
|
|
426
|
+
hs->flags |= F_RELATIVE;
|
|
427
|
+
/* extrq and insertq take two imm8 operands where vmread takes none. */
|
|
428
|
+
if (!ext && map0f && opcode == 0x78 && (mand & (PRE_66 | PRE_F2)))
|
|
429
|
+
cflags |= C_IMM16;
|
|
430
|
+
|
|
431
|
+
switch (m_mod) {
|
|
432
|
+
case 0:
|
|
433
|
+
if (m_rm == 5)
|
|
434
|
+
disp_size = 4;
|
|
435
|
+
break;
|
|
436
|
+
case 1:
|
|
437
|
+
disp_size = 1;
|
|
438
|
+
break;
|
|
439
|
+
case 2:
|
|
440
|
+
disp_size = 4;
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (m_mod != 3 && m_rm == 4) {
|
|
445
|
+
hs->flags |= F_SIB;
|
|
446
|
+
NEED(1);
|
|
447
|
+
hs->sib = c = *p++;
|
|
448
|
+
hs->sib_scale = c >> 6;
|
|
449
|
+
hs->sib_index = (c & 0x3f) >> 3;
|
|
450
|
+
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
|
|
451
|
+
disp_size = 4;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (disp_size) {
|
|
455
|
+
NEED(disp_size);
|
|
456
|
+
if (disp_size == 1) {
|
|
457
|
+
hs->flags |= F_DISP8;
|
|
458
|
+
hs->disp.disp8 = *p;
|
|
459
|
+
} else {
|
|
460
|
+
hs->flags |= F_DISP32;
|
|
461
|
+
hs->disp.disp32 = *(uint32_t *)p;
|
|
462
|
+
}
|
|
463
|
+
p += disp_size;
|
|
464
|
+
}
|
|
465
|
+
} else if (pref & PRE_LOCK)
|
|
466
|
+
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
|
467
|
+
|
|
468
|
+
/* An operand-size dependent immediate is 32 bits wide, 16 under a 66
|
|
469
|
+
* prefix, and 32 again when a REX.W overrides that prefix. */
|
|
470
|
+
if (cflags & C_IMM_P66) {
|
|
471
|
+
if (cflags & C_REL32) {
|
|
472
|
+
if ((pref & PRE_66) && !hs->rex_w) {
|
|
473
|
+
NEED(2);
|
|
474
|
+
hs->flags |= F_IMM16 | F_RELATIVE;
|
|
475
|
+
hs->imm.imm16 = *(uint16_t *)p;
|
|
476
|
+
p += 2;
|
|
477
|
+
goto disasm_done;
|
|
478
|
+
}
|
|
479
|
+
goto rel32_ok;
|
|
480
|
+
}
|
|
481
|
+
if (op64) {
|
|
482
|
+
NEED(8);
|
|
483
|
+
hs->flags |= F_IMM64;
|
|
484
|
+
hs->imm.imm64 = *(uint64_t *)p;
|
|
485
|
+
p += 8;
|
|
486
|
+
} else if (!(pref & PRE_66) || hs->rex_w) {
|
|
487
|
+
NEED(4);
|
|
488
|
+
hs->flags |= F_IMM32;
|
|
489
|
+
hs->imm.imm32 = *(uint32_t *)p;
|
|
490
|
+
p += 4;
|
|
491
|
+
} else
|
|
492
|
+
goto imm16_ok;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
if (cflags & C_IMM16) {
|
|
497
|
+
imm16_ok:
|
|
498
|
+
NEED(2);
|
|
499
|
+
hs->flags |= F_IMM16;
|
|
500
|
+
hs->imm.imm16 = *(uint16_t *)p;
|
|
501
|
+
p += 2;
|
|
502
|
+
}
|
|
503
|
+
if (cflags & C_IMM8) {
|
|
504
|
+
NEED(1);
|
|
505
|
+
hs->flags |= F_IMM8;
|
|
506
|
+
if (hs->flags & F_IMM16)
|
|
507
|
+
hs->disp.disp8 = *p++; /* enter: the union holds the imm16 */
|
|
508
|
+
else
|
|
509
|
+
hs->imm.imm8 = *p++;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (cflags & C_REL32) {
|
|
513
|
+
rel32_ok:
|
|
514
|
+
NEED(4);
|
|
515
|
+
hs->flags |= F_IMM32 | F_RELATIVE;
|
|
516
|
+
hs->imm.imm32 = *(uint32_t *)p;
|
|
517
|
+
p += 4;
|
|
518
|
+
} else if (cflags & C_REL8) {
|
|
519
|
+
NEED(1);
|
|
520
|
+
hs->flags |= F_IMM8 | F_RELATIVE;
|
|
521
|
+
hs->imm.imm8 = *p++;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
disasm_done:
|
|
525
|
+
|
|
526
|
+
hs->len = (uint8_t)(p - (uint8_t *)code);
|
|
527
|
+
return (unsigned int)hs->len;
|
|
528
|
+
|
|
529
|
+
error_length:
|
|
530
|
+
|
|
531
|
+
hs->flags |= F_ERROR | F_ERROR_LENGTH;
|
|
532
|
+
hs->len = 15;
|
|
533
|
+
return 15;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
#undef NEED
|
|
537
|
+
|
|
538
|
+
#endif // defined(_M_X64) || defined(__x86_64__)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Hacker Disassembler Engine 64
|
|
3
|
+
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* hde64.h: C/C++ header file
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#ifndef _HDE64_H_
|
|
11
|
+
#define _HDE64_H_
|
|
12
|
+
|
|
13
|
+
/* stdint.h - C99 standard header
|
|
14
|
+
* http://en.wikipedia.org/wiki/stdint.h
|
|
15
|
+
*
|
|
16
|
+
* if your compiler doesn't contain "stdint.h" header (for
|
|
17
|
+
* example, Microsoft Visual C++), you can download file:
|
|
18
|
+
* http://www.azillionmonkeys.com/qed/pstdint.h
|
|
19
|
+
* and change next line to:
|
|
20
|
+
* #include "pstdint.h"
|
|
21
|
+
*/
|
|
22
|
+
#include "pstdint.h"
|
|
23
|
+
|
|
24
|
+
#define F_MODRM 0x00000001
|
|
25
|
+
#define F_SIB 0x00000002
|
|
26
|
+
#define F_IMM8 0x00000004
|
|
27
|
+
#define F_IMM16 0x00000008
|
|
28
|
+
#define F_IMM32 0x00000010
|
|
29
|
+
#define F_IMM64 0x00000020
|
|
30
|
+
#define F_DISP8 0x00000040
|
|
31
|
+
#define F_DISP16 0x00000080
|
|
32
|
+
#define F_DISP32 0x00000100
|
|
33
|
+
#define F_RELATIVE 0x00000200
|
|
34
|
+
#define F_ERROR 0x00001000
|
|
35
|
+
#define F_ERROR_OPCODE 0x00002000
|
|
36
|
+
#define F_ERROR_LENGTH 0x00004000
|
|
37
|
+
#define F_ERROR_LOCK 0x00008000
|
|
38
|
+
#define F_ERROR_OPERAND 0x00010000
|
|
39
|
+
#define F_PREFIX_REPNZ 0x01000000
|
|
40
|
+
#define F_PREFIX_REPX 0x02000000
|
|
41
|
+
#define F_PREFIX_REP 0x03000000
|
|
42
|
+
#define F_PREFIX_66 0x04000000
|
|
43
|
+
#define F_PREFIX_67 0x08000000
|
|
44
|
+
#define F_PREFIX_LOCK 0x10000000
|
|
45
|
+
#define F_PREFIX_SEG 0x20000000
|
|
46
|
+
#define F_PREFIX_REX 0x40000000
|
|
47
|
+
#define F_PREFIX_REX2 0x80000000
|
|
48
|
+
#define F_PREFIX_ANY 0xff000000
|
|
49
|
+
|
|
50
|
+
#define PREFIX_SEGMENT_CS 0x2e
|
|
51
|
+
#define PREFIX_SEGMENT_SS 0x36
|
|
52
|
+
#define PREFIX_SEGMENT_DS 0x3e
|
|
53
|
+
#define PREFIX_SEGMENT_ES 0x26
|
|
54
|
+
#define PREFIX_SEGMENT_FS 0x64
|
|
55
|
+
#define PREFIX_SEGMENT_GS 0x65
|
|
56
|
+
#define PREFIX_LOCK 0xf0
|
|
57
|
+
#define PREFIX_REPNZ 0xf2
|
|
58
|
+
#define PREFIX_REPX 0xf3
|
|
59
|
+
#define PREFIX_OPERAND_SIZE 0x66
|
|
60
|
+
#define PREFIX_ADDRESS_SIZE 0x67
|
|
61
|
+
|
|
62
|
+
#pragma pack(push,1)
|
|
63
|
+
|
|
64
|
+
typedef struct {
|
|
65
|
+
uint8_t len;
|
|
66
|
+
uint8_t p_rep;
|
|
67
|
+
uint8_t p_lock;
|
|
68
|
+
uint8_t p_seg;
|
|
69
|
+
uint8_t p_66;
|
|
70
|
+
uint8_t p_67;
|
|
71
|
+
uint8_t rex;
|
|
72
|
+
uint8_t rex_w;
|
|
73
|
+
uint8_t rex_r;
|
|
74
|
+
uint8_t rex_x;
|
|
75
|
+
uint8_t rex_b;
|
|
76
|
+
uint8_t opcode;
|
|
77
|
+
uint8_t opcode2;
|
|
78
|
+
uint8_t modrm;
|
|
79
|
+
uint8_t modrm_mod;
|
|
80
|
+
uint8_t modrm_reg;
|
|
81
|
+
uint8_t modrm_rm;
|
|
82
|
+
uint8_t sib;
|
|
83
|
+
uint8_t sib_scale;
|
|
84
|
+
uint8_t sib_index;
|
|
85
|
+
uint8_t sib_base;
|
|
86
|
+
union {
|
|
87
|
+
uint8_t imm8;
|
|
88
|
+
uint16_t imm16;
|
|
89
|
+
uint32_t imm32;
|
|
90
|
+
uint64_t imm64;
|
|
91
|
+
} imm;
|
|
92
|
+
union {
|
|
93
|
+
uint8_t disp8;
|
|
94
|
+
uint16_t disp16;
|
|
95
|
+
uint32_t disp32;
|
|
96
|
+
} disp;
|
|
97
|
+
uint32_t flags;
|
|
98
|
+
} hde64s;
|
|
99
|
+
|
|
100
|
+
#pragma pack(pop)
|
|
101
|
+
|
|
102
|
+
#ifdef __cplusplus
|
|
103
|
+
extern "C" {
|
|
104
|
+
#endif
|
|
105
|
+
|
|
106
|
+
/* __cdecl */
|
|
107
|
+
unsigned int hde64_disasm(const void *code, hde64s *hs);
|
|
108
|
+
|
|
109
|
+
#ifdef __cplusplus
|
|
110
|
+
}
|
|
111
|
+
#endif
|
|
112
|
+
|
|
113
|
+
#endif /* _HDE64_H_ */
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
|
3
|
+
* Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
|
6
|
+
* modification, are permitted provided that the following conditions
|
|
7
|
+
* are met:
|
|
8
|
+
*
|
|
9
|
+
* 1. Redistributions of source code must retain the above copyright
|
|
10
|
+
* notice, this list of conditions and the following disclaimer.
|
|
11
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
|
12
|
+
* notice, this list of conditions and the following disclaimer in the
|
|
13
|
+
* documentation and/or other materials provided with the distribution.
|
|
14
|
+
*
|
|
15
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
|
16
|
+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
17
|
+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
18
|
+
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
19
|
+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
20
|
+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
21
|
+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
22
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
23
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
24
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
#pragma once
|
|
28
|
+
|
|
29
|
+
#include <windows.h>
|
|
30
|
+
|
|
31
|
+
// Integer types for HDE.
|
|
32
|
+
typedef INT8 int8_t;
|
|
33
|
+
typedef INT16 int16_t;
|
|
34
|
+
typedef INT32 int32_t;
|
|
35
|
+
typedef INT64 int64_t;
|
|
36
|
+
typedef UINT8 uint8_t;
|
|
37
|
+
typedef UINT16 uint16_t;
|
|
38
|
+
typedef UINT32 uint32_t;
|
|
39
|
+
typedef UINT64 uint64_t;
|