@wzwjustdoit/dsh-plugin-git-bash 0.0.0-stage → 0.4.0

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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -2
  3. package/client.js +736 -0
  4. package/cordis.patch.yml +27 -0
  5. package/lib/agents.d.ts +5 -0
  6. package/lib/agents.d.ts.map +1 -0
  7. package/lib/agents.js +56 -0
  8. package/lib/agents.js.map +1 -0
  9. package/lib/discovery.d.ts +21 -0
  10. package/lib/discovery.d.ts.map +1 -0
  11. package/lib/discovery.js +122 -0
  12. package/lib/discovery.js.map +1 -0
  13. package/lib/index.d.ts +55 -0
  14. package/lib/index.d.ts.map +1 -0
  15. package/lib/index.js +369 -0
  16. package/lib/index.js.map +1 -0
  17. package/native/CMakeLists.txt +58 -0
  18. package/native/bin/win32-x64/msys-token-guard-hook.dll +0 -0
  19. package/native/bin/win32-x64/msys-token-guard.exe +0 -0
  20. package/native/msys-token-guard-hook.cpp +470 -0
  21. package/native/msys-token-guard.cpp +671 -0
  22. package/native/vendor/detours/LICENSE.md +23 -0
  23. package/native/vendor/detours/README.dsh.md +13 -0
  24. package/native/vendor/detours/creatwth.cpp +1577 -0
  25. package/native/vendor/detours/detours.cpp +2364 -0
  26. package/native/vendor/detours/detours.h +1059 -0
  27. package/native/vendor/detours/detver.h +27 -0
  28. package/native/vendor/detours/disasm.cpp +4236 -0
  29. package/native/vendor/detours/image.cpp +2251 -0
  30. package/native/vendor/detours/modules.cpp +929 -0
  31. package/native/vendor/detours/uimports.cpp +269 -0
  32. package/package.json +120 -4
  33. package/scripts/build-native.mjs +35 -0
  34. package/scripts/dsh.desktop.startup/README.md +27 -0
  35. package/scripts/dsh.desktop.startup/dsh.desktop.startup.gitbash.bat +28 -0
  36. package/scripts/dsh.desktop.startup/dsh.desktop.startup.gitbash.sh +46 -0
  37. package/scripts/dsh.desktop.startup/dsh.desktop.startup.gitbash.vbs +0 -0
  38. package/scripts/dsh.web.startup/README.md +33 -0
  39. package/scripts/dsh.web.startup/dsh.web.startup.gitbash.bat +28 -0
  40. package/scripts/dsh.web.startup/dsh.web.startup.gitbash.sh +48 -0
  41. package/scripts/dsh.web.startup/dsh.web.startup.gitbash.vbs +0 -0
@@ -0,0 +1,2364 @@
1
+ //////////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // Core Detours Functionality (detours.cpp of detours.lib)
4
+ //
5
+ // Microsoft Research Detours Package, Version 4.0.1
6
+ //
7
+ // Copyright (c) Microsoft Corporation. All rights reserved.
8
+ //
9
+
10
+ #pragma warning(disable:4068) // unknown pragma (suppress)
11
+
12
+ #if _MSC_VER >= 1900
13
+ #pragma warning(push)
14
+ #pragma warning(disable:4091) // empty typedef
15
+ #endif
16
+
17
+ #define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1
18
+ #include <windows.h>
19
+
20
+ #if (_MSC_VER < 1299)
21
+ #pragma warning(disable: 4710)
22
+ #endif
23
+
24
+ //#define DETOUR_DEBUG 1
25
+ #define DETOURS_INTERNAL
26
+
27
+ #include "detours.h"
28
+
29
+ #if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH
30
+ #error detours.h version mismatch
31
+ #endif
32
+
33
+ #if _MSC_VER >= 1900
34
+ #pragma warning(pop)
35
+ #endif
36
+
37
+ #define NOTHROW
38
+
39
+ //////////////////////////////////////////////////////////////////////////////
40
+ //
41
+ struct _DETOUR_ALIGN
42
+ {
43
+ BYTE obTarget : 3;
44
+ BYTE obTrampoline : 5;
45
+ };
46
+
47
+ C_ASSERT(sizeof(_DETOUR_ALIGN) == 1);
48
+
49
+ //////////////////////////////////////////////////////////////////////////////
50
+ //
51
+ // Region reserved for system DLLs, which cannot be used for trampolines.
52
+ //
53
+ static PVOID s_pSystemRegionLowerBound = (PVOID)(ULONG_PTR)0x70000000;
54
+ static PVOID s_pSystemRegionUpperBound = (PVOID)(ULONG_PTR)0x80000000;
55
+
56
+ //////////////////////////////////////////////////////////////////////////////
57
+ //
58
+ static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
59
+ {
60
+ MEMORY_BASIC_INFORMATION mbi;
61
+ VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
62
+ __try {
63
+ PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
64
+ if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
65
+ return false;
66
+ }
67
+
68
+ PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
69
+ pDosHeader->e_lfanew);
70
+ if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
71
+ return false;
72
+ }
73
+
74
+ if (pbAddress >= ((PBYTE)pDosHeader +
75
+ pNtHeader->OptionalHeader
76
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
77
+ pbAddress < ((PBYTE)pDosHeader +
78
+ pNtHeader->OptionalHeader
79
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
80
+ pNtHeader->OptionalHeader
81
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
82
+ return true;
83
+ }
84
+ }
85
+ #pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.")
86
+ __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
87
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
88
+ return false;
89
+ }
90
+ return false;
91
+ }
92
+
93
+ inline ULONG_PTR detour_2gb_below(ULONG_PTR address)
94
+ {
95
+ return (address > (ULONG_PTR)0x7ff80000) ? address - 0x7ff80000 : 0x80000;
96
+ }
97
+
98
+ inline ULONG_PTR detour_2gb_above(ULONG_PTR address)
99
+ {
100
+ #if defined(DETOURS_64BIT)
101
+ return (address < (ULONG_PTR)0xffffffff80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfffffffffff80000;
102
+ #else
103
+ return (address < (ULONG_PTR)0x80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfff80000;
104
+ #endif
105
+ }
106
+
107
+ ///////////////////////////////////////////////////////////////////////// X86.
108
+ //
109
+ #ifdef DETOURS_X86
110
+
111
+ struct _DETOUR_TRAMPOLINE
112
+ {
113
+ BYTE rbCode[30]; // target code + jmp to pbRemain
114
+ BYTE cbCode; // size of moved target code.
115
+ BYTE cbCodeBreak; // padding to make debugging easier.
116
+ BYTE rbRestore[22]; // original target code.
117
+ BYTE cbRestore; // size of original target code.
118
+ BYTE cbRestoreBreak; // padding to make debugging easier.
119
+ _DETOUR_ALIGN rAlign[8]; // instruction alignment array.
120
+ PBYTE pbRemain; // first instruction after moved code. [free list]
121
+ PBYTE pbDetour; // first instruction of detour function.
122
+ };
123
+
124
+ C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 72);
125
+
126
+ enum {
127
+ SIZE_OF_JMP = 5
128
+ };
129
+
130
+ inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
131
+ {
132
+ PBYTE pbJmpSrc = pbCode + 5;
133
+ *pbCode++ = 0xE9; // jmp +imm32
134
+ *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc);
135
+ return pbCode;
136
+ }
137
+
138
+ inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
139
+ {
140
+ *pbCode++ = 0xff; // jmp [+imm32]
141
+ *pbCode++ = 0x25;
142
+ *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal);
143
+ return pbCode;
144
+ }
145
+
146
+ inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
147
+ {
148
+ while (pbCode < pbLimit) {
149
+ *pbCode++ = 0xcc; // brk;
150
+ }
151
+ return pbCode;
152
+ }
153
+
154
+ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
155
+ {
156
+ if (pbCode == NULL) {
157
+ return NULL;
158
+ }
159
+ if (ppGlobals != NULL) {
160
+ *ppGlobals = NULL;
161
+ }
162
+
163
+ // First, skip over the import vector if there is one.
164
+ if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32]
165
+ // Looks like an import alias jump, then get the code it points to.
166
+ PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2];
167
+ if (detour_is_imported(pbCode, pbTarget)) {
168
+ PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget;
169
+ DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
170
+ pbCode = pbNew;
171
+ }
172
+ }
173
+
174
+ // Then, skip over a patch jump
175
+ if (pbCode[0] == 0xeb) { // jmp +imm8
176
+ PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1];
177
+ DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));
178
+ pbCode = pbNew;
179
+
180
+ // First, skip over the import vector if there is one.
181
+ if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32]
182
+ // Looks like an import alias jump, then get the code it points to.
183
+ PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2];
184
+ if (detour_is_imported(pbCode, pbTarget)) {
185
+ pbNew = *(UNALIGNED PBYTE *)pbTarget;
186
+ DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
187
+ pbCode = pbNew;
188
+ }
189
+ }
190
+ // Finally, skip over a long jump if it is the target of the patch jump.
191
+ else if (pbCode[0] == 0xe9) { // jmp +imm32
192
+ pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
193
+ DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew));
194
+ pbCode = pbNew;
195
+ }
196
+ }
197
+ return pbCode;
198
+ }
199
+
200
+ inline void detour_find_jmp_bounds(PBYTE pbCode,
201
+ PDETOUR_TRAMPOLINE *ppLower,
202
+ PDETOUR_TRAMPOLINE *ppUpper)
203
+ {
204
+ // We have to place trampolines within +/- 2GB of code.
205
+ ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
206
+ ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
207
+ DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi));
208
+
209
+ // And, within +/- 2GB of relative jmp targets.
210
+ if (pbCode[0] == 0xe9) { // jmp +imm32
211
+ PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
212
+
213
+ if (pbNew < pbCode) {
214
+ hi = detour_2gb_above((ULONG_PTR)pbNew);
215
+ }
216
+ else {
217
+ lo = detour_2gb_below((ULONG_PTR)pbNew);
218
+ }
219
+ DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi));
220
+ }
221
+
222
+ *ppLower = (PDETOUR_TRAMPOLINE)lo;
223
+ *ppUpper = (PDETOUR_TRAMPOLINE)hi;
224
+ }
225
+
226
+ inline BOOL detour_does_code_end_function(PBYTE pbCode)
227
+ {
228
+ if (pbCode[0] == 0xeb || // jmp +imm8
229
+ pbCode[0] == 0xe9 || // jmp +imm32
230
+ pbCode[0] == 0xe0 || // jmp eax
231
+ pbCode[0] == 0xc2 || // ret +imm8
232
+ pbCode[0] == 0xc3 || // ret
233
+ pbCode[0] == 0xcc) { // brk
234
+ return TRUE;
235
+ }
236
+ else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret
237
+ return TRUE;
238
+ }
239
+ else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
240
+ return TRUE;
241
+ }
242
+ else if ((pbCode[0] == 0x26 || // jmp es:
243
+ pbCode[0] == 0x2e || // jmp cs:
244
+ pbCode[0] == 0x36 || // jmp ss:
245
+ pbCode[0] == 0x3e || // jmp ds:
246
+ pbCode[0] == 0x64 || // jmp fs:
247
+ pbCode[0] == 0x65) && // jmp gs:
248
+ pbCode[1] == 0xff && // jmp [+imm32]
249
+ pbCode[2] == 0x25) {
250
+ return TRUE;
251
+ }
252
+ return FALSE;
253
+ }
254
+
255
+ inline ULONG detour_is_code_filler(PBYTE pbCode)
256
+ {
257
+ // 1-byte through 11-byte NOPs.
258
+ if (pbCode[0] == 0x90) {
259
+ return 1;
260
+ }
261
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x90) {
262
+ return 2;
263
+ }
264
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) {
265
+ return 3;
266
+ }
267
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 &&
268
+ pbCode[3] == 0x00) {
269
+ return 4;
270
+ }
271
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 &&
272
+ pbCode[3] == 0x00 && pbCode[4] == 0x00) {
273
+ return 5;
274
+ }
275
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
276
+ pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) {
277
+ return 6;
278
+ }
279
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 &&
280
+ pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
281
+ pbCode[6] == 0x00) {
282
+ return 7;
283
+ }
284
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 &&
285
+ pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
286
+ pbCode[6] == 0x00 && pbCode[7] == 0x00) {
287
+ return 8;
288
+ }
289
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
290
+ pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
291
+ pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) {
292
+ return 9;
293
+ }
294
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F &&
295
+ pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 &&
296
+ pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
297
+ pbCode[9] == 0x00) {
298
+ return 10;
299
+ }
300
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 &&
301
+ pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 &&
302
+ pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
303
+ pbCode[9] == 0x00 && pbCode[10] == 0x00) {
304
+ return 11;
305
+ }
306
+
307
+ // int 3.
308
+ if (pbCode[0] == 0xcc) {
309
+ return 1;
310
+ }
311
+ return 0;
312
+ }
313
+
314
+ #endif // DETOURS_X86
315
+
316
+ ///////////////////////////////////////////////////////////////////////// X64.
317
+ //
318
+ #ifdef DETOURS_X64
319
+
320
+ struct _DETOUR_TRAMPOLINE
321
+ {
322
+ // An X64 instuction can be 15 bytes long.
323
+ // In practice 11 seems to be the limit.
324
+ BYTE rbCode[30]; // target code + jmp to pbRemain.
325
+ BYTE cbCode; // size of moved target code.
326
+ BYTE cbCodeBreak; // padding to make debugging easier.
327
+ BYTE rbRestore[30]; // original target code.
328
+ BYTE cbRestore; // size of original target code.
329
+ BYTE cbRestoreBreak; // padding to make debugging easier.
330
+ _DETOUR_ALIGN rAlign[8]; // instruction alignment array.
331
+ PBYTE pbRemain; // first instruction after moved code. [free list]
332
+ PBYTE pbDetour; // first instruction of detour function.
333
+ BYTE rbCodeIn[8]; // jmp [pbDetour]
334
+ };
335
+
336
+ C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 96);
337
+
338
+ enum {
339
+ SIZE_OF_JMP = 5
340
+ };
341
+
342
+ inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
343
+ {
344
+ PBYTE pbJmpSrc = pbCode + 5;
345
+ *pbCode++ = 0xE9; // jmp +imm32
346
+ *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc);
347
+ return pbCode;
348
+ }
349
+
350
+ inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
351
+ {
352
+ PBYTE pbJmpSrc = pbCode + 6;
353
+ *pbCode++ = 0xff; // jmp [+imm32]
354
+ *pbCode++ = 0x25;
355
+ *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc);
356
+ return pbCode;
357
+ }
358
+
359
+ inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
360
+ {
361
+ while (pbCode < pbLimit) {
362
+ *pbCode++ = 0xcc; // brk;
363
+ }
364
+ return pbCode;
365
+ }
366
+
367
+ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
368
+ {
369
+ if (pbCode == NULL) {
370
+ return NULL;
371
+ }
372
+ if (ppGlobals != NULL) {
373
+ *ppGlobals = NULL;
374
+ }
375
+
376
+ // First, skip over the import vector if there is one.
377
+ if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
378
+ // Looks like an import alias jump, then get the code it points to.
379
+ PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2];
380
+ if (detour_is_imported(pbCode, pbTarget)) {
381
+ PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget;
382
+ DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
383
+ pbCode = pbNew;
384
+ }
385
+ }
386
+
387
+ // Then, skip over a patch jump
388
+ if (pbCode[0] == 0xeb) { // jmp +imm8
389
+ PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1];
390
+ DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));
391
+ pbCode = pbNew;
392
+
393
+ // First, skip over the import vector if there is one.
394
+ if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
395
+ // Looks like an import alias jump, then get the code it points to.
396
+ PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2];
397
+ if (detour_is_imported(pbCode, pbTarget)) {
398
+ pbNew = *(UNALIGNED PBYTE *)pbTarget;
399
+ DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
400
+ pbCode = pbNew;
401
+ }
402
+ }
403
+ // Finally, skip over a long jump if it is the target of the patch jump.
404
+ else if (pbCode[0] == 0xe9) { // jmp +imm32
405
+ pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
406
+ DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew));
407
+ pbCode = pbNew;
408
+ }
409
+ }
410
+ return pbCode;
411
+ }
412
+
413
+ inline void detour_find_jmp_bounds(PBYTE pbCode,
414
+ PDETOUR_TRAMPOLINE *ppLower,
415
+ PDETOUR_TRAMPOLINE *ppUpper)
416
+ {
417
+ // We have to place trampolines within +/- 2GB of code.
418
+ ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
419
+ ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
420
+ DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi));
421
+
422
+ // And, within +/- 2GB of relative jmp vectors.
423
+ if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
424
+ PBYTE pbNew = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2];
425
+
426
+ if (pbNew < pbCode) {
427
+ hi = detour_2gb_above((ULONG_PTR)pbNew);
428
+ }
429
+ else {
430
+ lo = detour_2gb_below((ULONG_PTR)pbNew);
431
+ }
432
+ DETOUR_TRACE(("[%p..%p..%p] [+imm32]\n", lo, pbCode, hi));
433
+ }
434
+ // And, within +/- 2GB of relative jmp targets.
435
+ else if (pbCode[0] == 0xe9) { // jmp +imm32
436
+ PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
437
+
438
+ if (pbNew < pbCode) {
439
+ hi = detour_2gb_above((ULONG_PTR)pbNew);
440
+ }
441
+ else {
442
+ lo = detour_2gb_below((ULONG_PTR)pbNew);
443
+ }
444
+ DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi));
445
+ }
446
+
447
+ *ppLower = (PDETOUR_TRAMPOLINE)lo;
448
+ *ppUpper = (PDETOUR_TRAMPOLINE)hi;
449
+ }
450
+
451
+ inline BOOL detour_does_code_end_function(PBYTE pbCode)
452
+ {
453
+ if (pbCode[0] == 0xeb || // jmp +imm8
454
+ pbCode[0] == 0xe9 || // jmp +imm32
455
+ pbCode[0] == 0xe0 || // jmp eax
456
+ pbCode[0] == 0xc2 || // ret +imm8
457
+ pbCode[0] == 0xc3 || // ret
458
+ pbCode[0] == 0xcc) { // brk
459
+ return TRUE;
460
+ }
461
+ else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret
462
+ return TRUE;
463
+ }
464
+ else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
465
+ return TRUE;
466
+ }
467
+ else if ((pbCode[0] == 0x26 || // jmp es:
468
+ pbCode[0] == 0x2e || // jmp cs:
469
+ pbCode[0] == 0x36 || // jmp ss:
470
+ pbCode[0] == 0x3e || // jmp ds:
471
+ pbCode[0] == 0x64 || // jmp fs:
472
+ pbCode[0] == 0x65) && // jmp gs:
473
+ pbCode[1] == 0xff && // jmp [+imm32]
474
+ pbCode[2] == 0x25) {
475
+ return TRUE;
476
+ }
477
+ return FALSE;
478
+ }
479
+
480
+ inline ULONG detour_is_code_filler(PBYTE pbCode)
481
+ {
482
+ // 1-byte through 11-byte NOPs.
483
+ if (pbCode[0] == 0x90) {
484
+ return 1;
485
+ }
486
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x90) {
487
+ return 2;
488
+ }
489
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) {
490
+ return 3;
491
+ }
492
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 &&
493
+ pbCode[3] == 0x00) {
494
+ return 4;
495
+ }
496
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 &&
497
+ pbCode[3] == 0x00 && pbCode[4] == 0x00) {
498
+ return 5;
499
+ }
500
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
501
+ pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) {
502
+ return 6;
503
+ }
504
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 &&
505
+ pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
506
+ pbCode[6] == 0x00) {
507
+ return 7;
508
+ }
509
+ if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 &&
510
+ pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
511
+ pbCode[6] == 0x00 && pbCode[7] == 0x00) {
512
+ return 8;
513
+ }
514
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
515
+ pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
516
+ pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) {
517
+ return 9;
518
+ }
519
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F &&
520
+ pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 &&
521
+ pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
522
+ pbCode[9] == 0x00) {
523
+ return 10;
524
+ }
525
+ if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 &&
526
+ pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 &&
527
+ pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
528
+ pbCode[9] == 0x00 && pbCode[10] == 0x00) {
529
+ return 11;
530
+ }
531
+
532
+ // int 3.
533
+ if (pbCode[0] == 0xcc) {
534
+ return 1;
535
+ }
536
+ return 0;
537
+ }
538
+
539
+ #endif // DETOURS_X64
540
+
541
+ //////////////////////////////////////////////////////////////////////// IA64.
542
+ //
543
+ #ifdef DETOURS_IA64
544
+
545
+ struct _DETOUR_TRAMPOLINE
546
+ {
547
+ // On the IA64, a trampoline is used for both incoming and outgoing calls.
548
+ //
549
+ // The trampoline contains the following bundles for the outgoing call:
550
+ // movl gp=target_gp;
551
+ // <relocated target bundle>
552
+ // brl target_code;
553
+ //
554
+ // The trampoline contains the following bundles for the incoming call:
555
+ // alloc r41=ar.pfs, b, 0, 8, 0
556
+ // mov r40=rp
557
+ //
558
+ // adds r50=0, r39
559
+ // adds r49=0, r38
560
+ // adds r48=0, r37 ;;
561
+ //
562
+ // adds r47=0, r36
563
+ // adds r46=0, r35
564
+ // adds r45=0, r34
565
+ //
566
+ // adds r44=0, r33
567
+ // adds r43=0, r32
568
+ // adds r42=0, gp ;;
569
+ //
570
+ // movl gp=ffffffff`ffffffff ;;
571
+ //
572
+ // brl.call.sptk.few rp=disas!TestCodes+20e0 (00000000`00404ea0) ;;
573
+ //
574
+ // adds gp=0, r42
575
+ // mov rp=r40, +0 ;;
576
+ // mov.i ar.pfs=r41
577
+ //
578
+ // br.ret.sptk.many rp ;;
579
+ //
580
+ // This way, we only have to relocate a single bundle.
581
+ //
582
+ // The complicated incoming trampoline is required because we have to
583
+ // create an additional stack frame so that we save and restore the gp.
584
+ // We must do this because gp is a caller-saved register, but not saved
585
+ // if the caller thinks the target is in the same DLL, which changes
586
+ // when we insert a detour.
587
+ //
588
+ DETOUR_IA64_BUNDLE bMovlTargetGp; // Bundle which sets target GP
589
+ BYTE rbCode[sizeof(DETOUR_IA64_BUNDLE)]; // moved bundle.
590
+ DETOUR_IA64_BUNDLE bBrlRemainEip; // Brl to pbRemain
591
+ // This must be adjacent to bBranchIslands.
592
+
593
+ // Each instruction in the moved bundle could be a IP-relative chk or branch or call.
594
+ // Any such instructions are changed to point to a brl in bBranchIslands.
595
+ // This must be adjacent to bBrlRemainEip -- see "pbPool".
596
+ DETOUR_IA64_BUNDLE bBranchIslands[DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE];
597
+
598
+ // Target of brl inserted in target function
599
+ DETOUR_IA64_BUNDLE bAllocFrame; // alloc frame
600
+ DETOUR_IA64_BUNDLE bSave37to39; // save r37, r38, r39.
601
+ DETOUR_IA64_BUNDLE bSave34to36; // save r34, r35, r36.
602
+ DETOUR_IA64_BUNDLE bSaveGPto33; // save gp, r32, r33.
603
+ DETOUR_IA64_BUNDLE bMovlDetourGp; // set detour GP.
604
+ DETOUR_IA64_BUNDLE bCallDetour; // call detour.
605
+ DETOUR_IA64_BUNDLE bPopFrameGp; // pop frame and restore gp.
606
+ DETOUR_IA64_BUNDLE bReturn; // return to caller.
607
+
608
+ PLABEL_DESCRIPTOR pldTrampoline;
609
+
610
+ BYTE rbRestore[sizeof(DETOUR_IA64_BUNDLE)]; // original target bundle.
611
+ BYTE cbRestore; // size of original target code.
612
+ BYTE cbCode; // size of moved target code.
613
+ _DETOUR_ALIGN rAlign[14]; // instruction alignment array.
614
+ PBYTE pbRemain; // first instruction after moved code. [free list]
615
+ PBYTE pbDetour; // first instruction of detour function.
616
+ PPLABEL_DESCRIPTOR ppldDetour; // [pbDetour,gpDetour]
617
+ PPLABEL_DESCRIPTOR ppldTarget; // [pbTarget,gpDetour]
618
+ };
619
+
620
+ C_ASSERT(sizeof(DETOUR_IA64_BUNDLE) == 16);
621
+ C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 256 + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * 16);
622
+
623
+ enum {
624
+ SIZE_OF_JMP = sizeof(DETOUR_IA64_BUNDLE)
625
+ };
626
+
627
+ inline PBYTE detour_skip_jmp(PBYTE pPointer, PVOID *ppGlobals)
628
+ {
629
+ PBYTE pGlobals = NULL;
630
+ PBYTE pbCode = NULL;
631
+
632
+ if (pPointer != NULL) {
633
+ PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)pPointer;
634
+ pbCode = (PBYTE)ppld->EntryPoint;
635
+ pGlobals = (PBYTE)ppld->GlobalPointer;
636
+ }
637
+ if (ppGlobals != NULL) {
638
+ *ppGlobals = pGlobals;
639
+ }
640
+ if (pbCode == NULL) {
641
+ return NULL;
642
+ }
643
+
644
+ DETOUR_IA64_BUNDLE *pb = (DETOUR_IA64_BUNDLE *)pbCode;
645
+
646
+ // IA64 Local Import Jumps look like:
647
+ // addl r2=ffffffff`ffe021c0, gp ;;
648
+ // ld8 r2=[r2]
649
+ // nop.i 0 ;;
650
+ //
651
+ // ld8 r3=[r2], 8 ;;
652
+ // ld8 gp=[r2]
653
+ // mov b6=r3, +0
654
+ //
655
+ // nop.m 0
656
+ // nop.i 0
657
+ // br.cond.sptk.few b6
658
+ //
659
+
660
+ // 002024000200100b
661
+ if ((pb[0].wide[0] & 0xfffffc000603ffff) == 0x002024000200100b &&
662
+ pb[0].wide[1] == 0x0004000000203008 &&
663
+ pb[1].wide[0] == 0x001014180420180a &&
664
+ pb[1].wide[1] == 0x07000830c0203008 &&
665
+ pb[2].wide[0] == 0x0000000100000010 &&
666
+ pb[2].wide[1] == 0x0080006000000200) {
667
+
668
+ ULONG64 offset =
669
+ ((pb[0].wide[0] & 0x0000000001fc0000) >> 18) | // imm7b
670
+ ((pb[0].wide[0] & 0x000001ff00000000) >> 25) | // imm9d
671
+ ((pb[0].wide[0] & 0x00000000f8000000) >> 11); // imm5c
672
+ if (pb[0].wide[0] & 0x0000020000000000) { // sign
673
+ offset |= 0xffffffffffe00000;
674
+ }
675
+ PBYTE pbTarget = pGlobals + offset;
676
+ DETOUR_TRACE(("%p: potential import jump, target=%p\n", pb, pbTarget));
677
+
678
+ if (detour_is_imported(pbCode, pbTarget) && *(PBYTE*)pbTarget != NULL) {
679
+ DETOUR_TRACE(("%p: is import jump, label=%p\n", pb, *(PBYTE *)pbTarget));
680
+
681
+ PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)*(PBYTE *)pbTarget;
682
+ pbCode = (PBYTE)ppld->EntryPoint;
683
+ pGlobals = (PBYTE)ppld->GlobalPointer;
684
+ if (ppGlobals != NULL) {
685
+ *ppGlobals = pGlobals;
686
+ }
687
+ }
688
+ }
689
+ return pbCode;
690
+ }
691
+
692
+
693
+ inline void detour_find_jmp_bounds(PBYTE pbCode,
694
+ PDETOUR_TRAMPOLINE *ppLower,
695
+ PDETOUR_TRAMPOLINE *ppUpper)
696
+ {
697
+ (void)pbCode;
698
+ *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x0000000000080000;
699
+ *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfffffffffff80000;
700
+ }
701
+
702
+ inline BOOL detour_does_code_end_function(PBYTE pbCode)
703
+ {
704
+ // Routine not needed on IA64.
705
+ (void)pbCode;
706
+ return FALSE;
707
+ }
708
+
709
+ inline ULONG detour_is_code_filler(PBYTE pbCode)
710
+ {
711
+ // Routine not needed on IA64.
712
+ (void)pbCode;
713
+ return 0;
714
+ }
715
+
716
+ #endif // DETOURS_IA64
717
+
718
+ #ifdef DETOURS_ARM
719
+
720
+ struct _DETOUR_TRAMPOLINE
721
+ {
722
+ // A Thumb-2 instruction can be 2 or 4 bytes long.
723
+ BYTE rbCode[62]; // target code + jmp to pbRemain
724
+ BYTE cbCode; // size of moved target code.
725
+ BYTE cbCodeBreak; // padding to make debugging easier.
726
+ BYTE rbRestore[22]; // original target code.
727
+ BYTE cbRestore; // size of original target code.
728
+ BYTE cbRestoreBreak; // padding to make debugging easier.
729
+ _DETOUR_ALIGN rAlign[8]; // instruction alignment array.
730
+ PBYTE pbRemain; // first instruction after moved code. [free list]
731
+ PBYTE pbDetour; // first instruction of detour function.
732
+ };
733
+
734
+ C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 104);
735
+
736
+ enum {
737
+ SIZE_OF_JMP = 8
738
+ };
739
+
740
+ inline PBYTE align4(PBYTE pValue)
741
+ {
742
+ return (PBYTE)(((ULONG)pValue) & ~(ULONG)3u);
743
+ }
744
+
745
+ inline ULONG fetch_thumb_opcode(PBYTE pbCode)
746
+ {
747
+ ULONG Opcode = *(UINT16 *)&pbCode[0];
748
+ if (Opcode >= 0xe800) {
749
+ Opcode = (Opcode << 16) | *(UINT16 *)&pbCode[2];
750
+ }
751
+ return Opcode;
752
+ }
753
+
754
+ inline void write_thumb_opcode(PBYTE &pbCode, ULONG Opcode)
755
+ {
756
+ if (Opcode >= 0x10000) {
757
+ *((UINT16*&)pbCode)++ = Opcode >> 16;
758
+ }
759
+ *((UINT16*&)pbCode)++ = (UINT16)Opcode;
760
+ }
761
+
762
+ PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
763
+ {
764
+ PBYTE pbLiteral;
765
+ if (ppPool != NULL) {
766
+ *ppPool = *ppPool - 4;
767
+ pbLiteral = *ppPool;
768
+ }
769
+ else {
770
+ pbLiteral = align4(pbCode + 6);
771
+ }
772
+
773
+ *((PBYTE*&)pbLiteral) = DETOURS_PBYTE_TO_PFUNC(pbJmpVal);
774
+ LONG delta = pbLiteral - align4(pbCode + 4);
775
+
776
+ write_thumb_opcode(pbCode, 0xf8dff000 | delta); // LDR PC,[PC+n]
777
+
778
+ if (ppPool == NULL) {
779
+ if (((ULONG)pbCode & 2) != 0) {
780
+ write_thumb_opcode(pbCode, 0xdefe); // BREAK
781
+ }
782
+ pbCode += 4;
783
+ }
784
+ return pbCode;
785
+ }
786
+
787
+ inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
788
+ {
789
+ while (pbCode < pbLimit) {
790
+ write_thumb_opcode(pbCode, 0xdefe);
791
+ }
792
+ return pbCode;
793
+ }
794
+
795
+ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
796
+ {
797
+ if (pbCode == NULL) {
798
+ return NULL;
799
+ }
800
+ if (ppGlobals != NULL) {
801
+ *ppGlobals = NULL;
802
+ }
803
+
804
+ // Skip over the import jump if there is one.
805
+ pbCode = (PBYTE)DETOURS_PFUNC_TO_PBYTE(pbCode);
806
+ ULONG Opcode = fetch_thumb_opcode(pbCode);
807
+
808
+ if ((Opcode & 0xfbf08f00) == 0xf2400c00) { // movw r12,#xxxx
809
+ ULONG Opcode2 = fetch_thumb_opcode(pbCode+4);
810
+
811
+ if ((Opcode2 & 0xfbf08f00) == 0xf2c00c00) { // movt r12,#xxxx
812
+ ULONG Opcode3 = fetch_thumb_opcode(pbCode+8);
813
+ if (Opcode3 == 0xf8dcf000) { // ldr pc,[r12]
814
+ PBYTE pbTarget = (PBYTE)(((Opcode2 << 12) & 0xf7000000) |
815
+ ((Opcode2 << 1) & 0x08000000) |
816
+ ((Opcode2 << 16) & 0x00ff0000) |
817
+ ((Opcode >> 4) & 0x0000f700) |
818
+ ((Opcode >> 15) & 0x00000800) |
819
+ ((Opcode >> 0) & 0x000000ff));
820
+ if (detour_is_imported(pbCode, pbTarget)) {
821
+ PBYTE pbNew = *(PBYTE *)pbTarget;
822
+ pbNew = DETOURS_PFUNC_TO_PBYTE(pbNew);
823
+ DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
824
+ return pbNew;
825
+ }
826
+ }
827
+ }
828
+ }
829
+ return pbCode;
830
+ }
831
+
832
+ inline void detour_find_jmp_bounds(PBYTE pbCode,
833
+ PDETOUR_TRAMPOLINE *ppLower,
834
+ PDETOUR_TRAMPOLINE *ppUpper)
835
+ {
836
+ // We have to place trampolines within +/- 2GB of code.
837
+ ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
838
+ ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
839
+ DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi));
840
+
841
+ *ppLower = (PDETOUR_TRAMPOLINE)lo;
842
+ *ppUpper = (PDETOUR_TRAMPOLINE)hi;
843
+ }
844
+
845
+
846
+ inline BOOL detour_does_code_end_function(PBYTE pbCode)
847
+ {
848
+ ULONG Opcode = fetch_thumb_opcode(pbCode);
849
+ if ((Opcode & 0xffffff87) == 0x4700 || // bx <reg>
850
+ (Opcode & 0xf800d000) == 0xf0009000) { // b <imm20>
851
+ return TRUE;
852
+ }
853
+ if ((Opcode & 0xffff8000) == 0xe8bd8000) { // pop {...,pc}
854
+ __debugbreak();
855
+ return TRUE;
856
+ }
857
+ if ((Opcode & 0xffffff00) == 0x0000bd00) { // pop {...,pc}
858
+ __debugbreak();
859
+ return TRUE;
860
+ }
861
+ return FALSE;
862
+ }
863
+
864
+ inline ULONG detour_is_code_filler(PBYTE pbCode)
865
+ {
866
+ if (pbCode[0] == 0x00 && pbCode[1] == 0xbf) { // nop.
867
+ return 2;
868
+ }
869
+ if (pbCode[0] == 0x00 && pbCode[1] == 0x00) { // zero-filled padding.
870
+ return 2;
871
+ }
872
+ return 0;
873
+ }
874
+
875
+ #endif // DETOURS_ARM
876
+
877
+ #ifdef DETOURS_ARM64
878
+
879
+ struct _DETOUR_TRAMPOLINE
880
+ {
881
+ // An ARM64 instruction is 4 bytes long.
882
+ BYTE rbCode[64]; // target code + jmp to pbRemain
883
+ BYTE cbCode; // size of moved target code.
884
+ BYTE cbCodeBreak[3]; // padding to make debugging easier.
885
+ BYTE rbRestore[24]; // original target code.
886
+ BYTE cbRestore; // size of original target code.
887
+ BYTE cbRestoreBreak[3]; // padding to make debugging easier.
888
+ _DETOUR_ALIGN rAlign[8]; // instruction alignment array.
889
+ PBYTE pbRemain; // first instruction after moved code. [free list]
890
+ PBYTE pbDetour; // first instruction of detour function.
891
+ };
892
+
893
+ C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 120);
894
+
895
+ enum {
896
+ SIZE_OF_JMP = 8
897
+ };
898
+
899
+ inline ULONG fetch_opcode(PBYTE pbCode)
900
+ {
901
+ return *(ULONG *)pbCode;
902
+ }
903
+
904
+ inline void write_opcode(PBYTE &pbCode, ULONG Opcode)
905
+ {
906
+ *(ULONG *)pbCode = Opcode;
907
+ pbCode += 4;
908
+ }
909
+
910
+ PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
911
+ {
912
+ PBYTE pbLiteral;
913
+ if (ppPool != NULL) {
914
+ *ppPool = *ppPool - 8;
915
+ pbLiteral = *ppPool;
916
+ }
917
+ else {
918
+ pbLiteral = pbCode + 2*4;
919
+ }
920
+
921
+ *((PBYTE*&)pbLiteral) = pbJmpVal;
922
+ LONG delta = (LONG)(pbLiteral - pbCode);
923
+
924
+ write_opcode(pbCode, 0x58000011 | ((delta / 4) << 5)); // LDR X17,[PC+n]
925
+ write_opcode(pbCode, 0xd61f0000 | (17 << 5)); // BR X17
926
+
927
+ if (ppPool == NULL) {
928
+ pbCode += 8;
929
+ }
930
+ return pbCode;
931
+ }
932
+
933
+ inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
934
+ {
935
+ while (pbCode < pbLimit) {
936
+ write_opcode(pbCode, 0xd4100000 | (0xf000 << 5));
937
+ }
938
+ return pbCode;
939
+ }
940
+
941
+ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
942
+ {
943
+ if (pbCode == NULL) {
944
+ return NULL;
945
+ }
946
+ if (ppGlobals != NULL) {
947
+ *ppGlobals = NULL;
948
+ }
949
+
950
+ // Skip over the import jump if there is one.
951
+ pbCode = (PBYTE)pbCode;
952
+ ULONG Opcode = fetch_opcode(pbCode);
953
+ if ((Opcode & 0x9f00001f) == 0x90000010) { // adrp x16, IAT
954
+ ULONG Opcode2 = fetch_opcode(pbCode+4);
955
+
956
+ if ((Opcode2 & 0xffe003ff) == 0xf9400210) { // ldr x16, [x16, IAT]
957
+ ULONG Opcode3 = fetch_opcode(pbCode+8);
958
+
959
+ if (Opcode3 == 0xd61f0200) { // br x16
960
+
961
+ ULONG PageOffset = ((Opcode & 0x60000000) >> 29) | ((Opcode & 0x00ffffe0) >> 3);
962
+ PageOffset = (LONG)(Opcode << 11) >> 11;
963
+
964
+ PBYTE pbTarget = (PBYTE)(((ULONG64)pbCode & 0xfffffffffffff000ULL) + PageOffset +
965
+ ((Opcode2 >> 10) & 0xfff));
966
+ if (detour_is_imported(pbCode, pbTarget)) {
967
+ PBYTE pbNew = *(PBYTE *)pbTarget;
968
+ DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
969
+ return pbNew;
970
+ }
971
+ }
972
+ }
973
+ }
974
+ return pbCode;
975
+ }
976
+
977
+ inline BOOL detour_does_code_end_function(PBYTE pbCode)
978
+ {
979
+ ULONG Opcode = fetch_opcode(pbCode);
980
+ if ((Opcode & 0xfffffc1f) == 0xd65f0000 || // br <reg>
981
+ (Opcode & 0xfc000000) == 0x14000000) { // b <imm26>
982
+ return TRUE;
983
+ }
984
+ return FALSE;
985
+ }
986
+
987
+ inline ULONG detour_is_code_filler(PBYTE pbCode)
988
+ {
989
+ if (*(ULONG *)pbCode == 0xd503201f) { // nop.
990
+ return 4;
991
+ }
992
+ if (*(ULONG *)pbCode == 0x00000000) { // zero-filled padding.
993
+ return 4;
994
+ }
995
+ return 0;
996
+ }
997
+
998
+ #endif // DETOURS_ARM64
999
+
1000
+ //////////////////////////////////////////////// Trampoline Memory Management.
1001
+ //
1002
+ struct DETOUR_REGION
1003
+ {
1004
+ ULONG dwSignature;
1005
+ DETOUR_REGION * pNext; // Next region in list of regions.
1006
+ DETOUR_TRAMPOLINE * pFree; // List of free trampolines in this region.
1007
+ };
1008
+ typedef DETOUR_REGION * PDETOUR_REGION;
1009
+
1010
+ const ULONG DETOUR_REGION_SIGNATURE = 'Rrtd';
1011
+ const ULONG DETOUR_REGION_SIZE = 0x10000;
1012
+ const ULONG DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE
1013
+ / sizeof(DETOUR_TRAMPOLINE)) - 1;
1014
+ static PDETOUR_REGION s_pRegions = NULL; // List of all regions.
1015
+ static PDETOUR_REGION s_pRegion = NULL; // Default region.
1016
+
1017
+ static DWORD detour_writable_trampoline_regions()
1018
+ {
1019
+ // Mark all of the regions as writable.
1020
+ for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {
1021
+ DWORD dwOld;
1022
+ if (!VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READWRITE, &dwOld)) {
1023
+ return GetLastError();
1024
+ }
1025
+ }
1026
+ return NO_ERROR;
1027
+ }
1028
+
1029
+ static void detour_runnable_trampoline_regions()
1030
+ {
1031
+ HANDLE hProcess = GetCurrentProcess();
1032
+
1033
+ // Mark all of the regions as executable.
1034
+ for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {
1035
+ DWORD dwOld;
1036
+ VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READ, &dwOld);
1037
+ FlushInstructionCache(hProcess, pRegion, DETOUR_REGION_SIZE);
1038
+ }
1039
+ }
1040
+
1041
+ static PBYTE detour_alloc_round_down_to_region(PBYTE pbTry)
1042
+ {
1043
+ // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications.
1044
+ ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1);
1045
+ if (extra != 0) {
1046
+ pbTry -= extra;
1047
+ }
1048
+ return pbTry;
1049
+ }
1050
+
1051
+ static PBYTE detour_alloc_round_up_to_region(PBYTE pbTry)
1052
+ {
1053
+ // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications.
1054
+ ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1);
1055
+ if (extra != 0) {
1056
+ ULONG_PTR adjust = DETOUR_REGION_SIZE - extra;
1057
+ pbTry += adjust;
1058
+ }
1059
+ return pbTry;
1060
+ }
1061
+
1062
+ // Starting at pbLo, try to allocate a memory region, continue until pbHi.
1063
+
1064
+ static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi)
1065
+ {
1066
+ PBYTE pbTry = detour_alloc_round_up_to_region(pbLo);
1067
+
1068
+ DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry));
1069
+
1070
+ for (; pbTry < pbHi;) {
1071
+ MEMORY_BASIC_INFORMATION mbi;
1072
+
1073
+ if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) {
1074
+ // Skip region reserved for system DLLs, but preserve address space entropy.
1075
+ pbTry += 0x08000000;
1076
+ continue;
1077
+ }
1078
+
1079
+ ZeroMemory(&mbi, sizeof(mbi));
1080
+ if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {
1081
+ break;
1082
+ }
1083
+
1084
+ DETOUR_TRACE((" Try %p => %p..%p %6x\n",
1085
+ pbTry,
1086
+ mbi.BaseAddress,
1087
+ (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
1088
+ mbi.State));
1089
+
1090
+ if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {
1091
+
1092
+ PVOID pv = VirtualAlloc(pbTry,
1093
+ DETOUR_REGION_SIZE,
1094
+ MEM_COMMIT|MEM_RESERVE,
1095
+ PAGE_EXECUTE_READWRITE);
1096
+ if (pv != NULL) {
1097
+ return pv;
1098
+ }
1099
+ pbTry += DETOUR_REGION_SIZE;
1100
+ }
1101
+ else {
1102
+ pbTry = detour_alloc_round_up_to_region((PBYTE)mbi.BaseAddress + mbi.RegionSize);
1103
+ }
1104
+ }
1105
+ return NULL;
1106
+ }
1107
+
1108
+ // Starting at pbHi, try to allocate a memory region, continue until pbLo.
1109
+
1110
+ static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi)
1111
+ {
1112
+ PBYTE pbTry = detour_alloc_round_down_to_region(pbHi - DETOUR_REGION_SIZE);
1113
+
1114
+ DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry));
1115
+
1116
+ for (; pbTry > pbLo;) {
1117
+ MEMORY_BASIC_INFORMATION mbi;
1118
+
1119
+ DETOUR_TRACE((" Try %p\n", pbTry));
1120
+ if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) {
1121
+ // Skip region reserved for system DLLs, but preserve address space entropy.
1122
+ pbTry -= 0x08000000;
1123
+ continue;
1124
+ }
1125
+
1126
+ ZeroMemory(&mbi, sizeof(mbi));
1127
+ if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {
1128
+ break;
1129
+ }
1130
+
1131
+ DETOUR_TRACE((" Try %p => %p..%p %6x\n",
1132
+ pbTry,
1133
+ mbi.BaseAddress,
1134
+ (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
1135
+ mbi.State));
1136
+
1137
+ if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {
1138
+
1139
+ PVOID pv = VirtualAlloc(pbTry,
1140
+ DETOUR_REGION_SIZE,
1141
+ MEM_COMMIT|MEM_RESERVE,
1142
+ PAGE_EXECUTE_READWRITE);
1143
+ if (pv != NULL) {
1144
+ return pv;
1145
+ }
1146
+ pbTry -= DETOUR_REGION_SIZE;
1147
+ }
1148
+ else {
1149
+ pbTry = detour_alloc_round_down_to_region((PBYTE)mbi.AllocationBase
1150
+ - DETOUR_REGION_SIZE);
1151
+ }
1152
+ }
1153
+ return NULL;
1154
+ }
1155
+
1156
+ static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget)
1157
+ {
1158
+ // We have to place trampolines within +/- 2GB of target.
1159
+
1160
+ PDETOUR_TRAMPOLINE pLo;
1161
+ PDETOUR_TRAMPOLINE pHi;
1162
+
1163
+ detour_find_jmp_bounds(pbTarget, &pLo, &pHi);
1164
+
1165
+ PDETOUR_TRAMPOLINE pTrampoline = NULL;
1166
+
1167
+ // Insure that there is a default region.
1168
+ if (s_pRegion == NULL && s_pRegions != NULL) {
1169
+ s_pRegion = s_pRegions;
1170
+ }
1171
+
1172
+ // First check the default region for an valid free block.
1173
+ if (s_pRegion != NULL && s_pRegion->pFree != NULL &&
1174
+ s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {
1175
+
1176
+ found_region:
1177
+ pTrampoline = s_pRegion->pFree;
1178
+ // do a last sanity check on region.
1179
+ if (pTrampoline < pLo || pTrampoline > pHi) {
1180
+ return NULL;
1181
+ }
1182
+ s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain;
1183
+ memset(pTrampoline, 0xcc, sizeof(*pTrampoline));
1184
+ return pTrampoline;
1185
+ }
1186
+
1187
+ // Then check the existing regions for a valid free block.
1188
+ for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) {
1189
+ if (s_pRegion != NULL && s_pRegion->pFree != NULL &&
1190
+ s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {
1191
+ goto found_region;
1192
+ }
1193
+ }
1194
+
1195
+ // We need to allocate a new region.
1196
+
1197
+ // Round pbTarget down to 64KB block.
1198
+ pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff);
1199
+
1200
+ PVOID pbTry = NULL;
1201
+
1202
+ // NB: We must always also start the search at an offset from pbTarget
1203
+ // in order to maintain ASLR entropy.
1204
+
1205
+ #if defined(DETOURS_64BIT)
1206
+ // Try looking 1GB below or lower.
1207
+ if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
1208
+ pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget - 0x40000000);
1209
+ }
1210
+ // Try looking 1GB above or higher.
1211
+ if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
1212
+ pbTry = detour_alloc_region_from_lo(pbTarget + 0x40000000, (PBYTE)pHi);
1213
+ }
1214
+ // Try looking 1GB below or higher.
1215
+ if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
1216
+ pbTry = detour_alloc_region_from_lo(pbTarget - 0x40000000, pbTarget);
1217
+ }
1218
+ // Try looking 1GB above or lower.
1219
+ if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
1220
+ pbTry = detour_alloc_region_from_hi(pbTarget, pbTarget + 0x40000000);
1221
+ }
1222
+ #endif
1223
+
1224
+ // Try anything below.
1225
+ if (pbTry == NULL) {
1226
+ pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget);
1227
+ }
1228
+ // try anything above.
1229
+ if (pbTry == NULL) {
1230
+ pbTry = detour_alloc_region_from_lo(pbTarget, (PBYTE)pHi);
1231
+ }
1232
+
1233
+ if (pbTry != NULL) {
1234
+ s_pRegion = (DETOUR_REGION*)pbTry;
1235
+ s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE;
1236
+ s_pRegion->pFree = NULL;
1237
+ s_pRegion->pNext = s_pRegions;
1238
+ s_pRegions = s_pRegion;
1239
+ DETOUR_TRACE((" Allocated region %p..%p\n\n",
1240
+ s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1));
1241
+
1242
+ // Put everything but the first trampoline on the free list.
1243
+ PBYTE pFree = NULL;
1244
+ pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1;
1245
+ for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) {
1246
+ pTrampoline[i].pbRemain = pFree;
1247
+ pFree = (PBYTE)&pTrampoline[i];
1248
+ }
1249
+ s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree;
1250
+ goto found_region;
1251
+ }
1252
+
1253
+ DETOUR_TRACE(("Couldn't find available memory region!\n"));
1254
+ return NULL;
1255
+ }
1256
+
1257
+ static void detour_free_trampoline(PDETOUR_TRAMPOLINE pTrampoline)
1258
+ {
1259
+ PDETOUR_REGION pRegion = (PDETOUR_REGION)
1260
+ ((ULONG_PTR)pTrampoline & ~(ULONG_PTR)0xffff);
1261
+
1262
+ memset(pTrampoline, 0, sizeof(*pTrampoline));
1263
+ pTrampoline->pbRemain = (PBYTE)pRegion->pFree;
1264
+ pRegion->pFree = pTrampoline;
1265
+ }
1266
+
1267
+ static BOOL detour_is_region_empty(PDETOUR_REGION pRegion)
1268
+ {
1269
+ // Stop if the region isn't a region (this would be bad).
1270
+ if (pRegion->dwSignature != DETOUR_REGION_SIGNATURE) {
1271
+ return FALSE;
1272
+ }
1273
+
1274
+ PBYTE pbRegionBeg = (PBYTE)pRegion;
1275
+ PBYTE pbRegionLim = pbRegionBeg + DETOUR_REGION_SIZE;
1276
+
1277
+ // Stop if any of the trampolines aren't free.
1278
+ PDETOUR_TRAMPOLINE pTrampoline = ((PDETOUR_TRAMPOLINE)pRegion) + 1;
1279
+ for (int i = 0; i < DETOUR_TRAMPOLINES_PER_REGION; i++) {
1280
+ if (pTrampoline[i].pbRemain != NULL &&
1281
+ (pTrampoline[i].pbRemain < pbRegionBeg ||
1282
+ pTrampoline[i].pbRemain >= pbRegionLim)) {
1283
+ return FALSE;
1284
+ }
1285
+ }
1286
+
1287
+ // OK, the region is empty.
1288
+ return TRUE;
1289
+ }
1290
+
1291
+ static void detour_free_unused_trampoline_regions()
1292
+ {
1293
+ PDETOUR_REGION *ppRegionBase = &s_pRegions;
1294
+ PDETOUR_REGION pRegion = s_pRegions;
1295
+
1296
+ while (pRegion != NULL) {
1297
+ if (detour_is_region_empty(pRegion)) {
1298
+ *ppRegionBase = pRegion->pNext;
1299
+
1300
+ VirtualFree(pRegion, 0, MEM_RELEASE);
1301
+ s_pRegion = NULL;
1302
+ }
1303
+ else {
1304
+ ppRegionBase = &pRegion->pNext;
1305
+ }
1306
+ pRegion = *ppRegionBase;
1307
+ }
1308
+ }
1309
+
1310
+ ///////////////////////////////////////////////////////// Transaction Structs.
1311
+ //
1312
+ struct DetourThread
1313
+ {
1314
+ DetourThread * pNext;
1315
+ HANDLE hThread;
1316
+ };
1317
+
1318
+ struct DetourOperation
1319
+ {
1320
+ DetourOperation * pNext;
1321
+ BOOL fIsRemove;
1322
+ PBYTE * ppbPointer;
1323
+ PBYTE pbTarget;
1324
+ PDETOUR_TRAMPOLINE pTrampoline;
1325
+ ULONG dwPerm;
1326
+ };
1327
+
1328
+ static BOOL s_fIgnoreTooSmall = FALSE;
1329
+ static BOOL s_fRetainRegions = FALSE;
1330
+
1331
+ static LONG s_nPendingThreadId = 0; // Thread owning pending transaction.
1332
+ static LONG s_nPendingError = NO_ERROR;
1333
+ static PVOID * s_ppPendingError = NULL;
1334
+ static DetourThread * s_pPendingThreads = NULL;
1335
+ static DetourOperation * s_pPendingOperations = NULL;
1336
+
1337
+ //////////////////////////////////////////////////////////////////////////////
1338
+ //
1339
+ PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer,
1340
+ _Out_opt_ PVOID *ppGlobals)
1341
+ {
1342
+ return detour_skip_jmp((PBYTE)pPointer, ppGlobals);
1343
+ }
1344
+
1345
+ //////////////////////////////////////////////////////////// Transaction APIs.
1346
+ //
1347
+ BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore)
1348
+ {
1349
+ BOOL fPrevious = s_fIgnoreTooSmall;
1350
+ s_fIgnoreTooSmall = fIgnore;
1351
+ return fPrevious;
1352
+ }
1353
+
1354
+ BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain)
1355
+ {
1356
+ BOOL fPrevious = s_fRetainRegions;
1357
+ s_fRetainRegions = fRetain;
1358
+ return fPrevious;
1359
+ }
1360
+
1361
+ PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound)
1362
+ {
1363
+ PVOID pPrevious = s_pSystemRegionLowerBound;
1364
+ s_pSystemRegionLowerBound = pSystemRegionLowerBound;
1365
+ return pPrevious;
1366
+ }
1367
+
1368
+ PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound)
1369
+ {
1370
+ PVOID pPrevious = s_pSystemRegionUpperBound;
1371
+ s_pSystemRegionUpperBound = pSystemRegionUpperBound;
1372
+ return pPrevious;
1373
+ }
1374
+
1375
+ LONG WINAPI DetourTransactionBegin()
1376
+ {
1377
+ // Only one transaction is allowed at a time.
1378
+ _Benign_race_begin_
1379
+ if (s_nPendingThreadId != 0) {
1380
+ return ERROR_INVALID_OPERATION;
1381
+ }
1382
+ _Benign_race_end_
1383
+
1384
+ // Make sure only one thread can start a transaction.
1385
+ if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) {
1386
+ return ERROR_INVALID_OPERATION;
1387
+ }
1388
+
1389
+ s_pPendingOperations = NULL;
1390
+ s_pPendingThreads = NULL;
1391
+ s_ppPendingError = NULL;
1392
+
1393
+ // Make sure the trampoline pages are writable.
1394
+ s_nPendingError = detour_writable_trampoline_regions();
1395
+
1396
+ return s_nPendingError;
1397
+ }
1398
+
1399
+ LONG WINAPI DetourTransactionAbort()
1400
+ {
1401
+ if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
1402
+ return ERROR_INVALID_OPERATION;
1403
+ }
1404
+
1405
+ // Restore all of the page permissions.
1406
+ for (DetourOperation *o = s_pPendingOperations; o != NULL;) {
1407
+ // We don't care if this fails, because the code is still accessible.
1408
+ DWORD dwOld;
1409
+ VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore,
1410
+ o->dwPerm, &dwOld);
1411
+
1412
+ if (!o->fIsRemove) {
1413
+ if (o->pTrampoline) {
1414
+ detour_free_trampoline(o->pTrampoline);
1415
+ o->pTrampoline = NULL;
1416
+ }
1417
+ }
1418
+
1419
+ DetourOperation *n = o->pNext;
1420
+ delete o;
1421
+ o = n;
1422
+ }
1423
+ s_pPendingOperations = NULL;
1424
+
1425
+ // Make sure the trampoline pages are no longer writable.
1426
+ detour_runnable_trampoline_regions();
1427
+
1428
+ // Resume any suspended threads.
1429
+ for (DetourThread *t = s_pPendingThreads; t != NULL;) {
1430
+ // There is nothing we can do if this fails.
1431
+ ResumeThread(t->hThread);
1432
+
1433
+ DetourThread *n = t->pNext;
1434
+ delete t;
1435
+ t = n;
1436
+ }
1437
+ s_pPendingThreads = NULL;
1438
+ s_nPendingThreadId = 0;
1439
+
1440
+ return NO_ERROR;
1441
+ }
1442
+
1443
+ LONG WINAPI DetourTransactionCommit()
1444
+ {
1445
+ return DetourTransactionCommitEx(NULL);
1446
+ }
1447
+
1448
+ static BYTE detour_align_from_trampoline(PDETOUR_TRAMPOLINE pTrampoline, BYTE obTrampoline)
1449
+ {
1450
+ for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) {
1451
+ if (pTrampoline->rAlign[n].obTrampoline == obTrampoline) {
1452
+ return pTrampoline->rAlign[n].obTarget;
1453
+ }
1454
+ }
1455
+ return 0;
1456
+ }
1457
+
1458
+ static LONG detour_align_from_target(PDETOUR_TRAMPOLINE pTrampoline, LONG obTarget)
1459
+ {
1460
+ for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) {
1461
+ if (pTrampoline->rAlign[n].obTarget == obTarget) {
1462
+ return pTrampoline->rAlign[n].obTrampoline;
1463
+ }
1464
+ }
1465
+ return 0;
1466
+ }
1467
+
1468
+ LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer)
1469
+ {
1470
+ if (pppFailedPointer != NULL) {
1471
+ // Used to get the last error.
1472
+ *pppFailedPointer = s_ppPendingError;
1473
+ }
1474
+ if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
1475
+ return ERROR_INVALID_OPERATION;
1476
+ }
1477
+
1478
+ // If any of the pending operations failed, then we abort the whole transaction.
1479
+ if (s_nPendingError != NO_ERROR) {
1480
+ DETOUR_BREAK();
1481
+ DetourTransactionAbort();
1482
+ return s_nPendingError;
1483
+ }
1484
+
1485
+ // Common variables.
1486
+ DetourOperation *o;
1487
+ DetourThread *t;
1488
+ BOOL freed = FALSE;
1489
+
1490
+ // Insert or remove each of the detours.
1491
+ for (o = s_pPendingOperations; o != NULL; o = o->pNext) {
1492
+ if (o->fIsRemove) {
1493
+ CopyMemory(o->pbTarget,
1494
+ o->pTrampoline->rbRestore,
1495
+ o->pTrampoline->cbRestore);
1496
+ #ifdef DETOURS_IA64
1497
+ *o->ppbPointer = (PBYTE)o->pTrampoline->ppldTarget;
1498
+ #endif // DETOURS_IA64
1499
+
1500
+ #ifdef DETOURS_X86
1501
+ *o->ppbPointer = o->pbTarget;
1502
+ #endif // DETOURS_X86
1503
+
1504
+ #ifdef DETOURS_X64
1505
+ *o->ppbPointer = o->pbTarget;
1506
+ #endif // DETOURS_X64
1507
+
1508
+ #ifdef DETOURS_ARM
1509
+ *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pbTarget);
1510
+ #endif // DETOURS_ARM
1511
+
1512
+ #ifdef DETOURS_ARM64
1513
+ *o->ppbPointer = o->pbTarget;
1514
+ #endif // DETOURS_ARM
1515
+ }
1516
+ else {
1517
+ DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%d\n",
1518
+ o->pTrampoline,
1519
+ o->pTrampoline->pbRemain,
1520
+ o->pTrampoline->pbDetour,
1521
+ o->pTrampoline->cbRestore));
1522
+
1523
+ DETOUR_TRACE(("detours: pbTarget=%p: "
1524
+ "%02x %02x %02x %02x "
1525
+ "%02x %02x %02x %02x "
1526
+ "%02x %02x %02x %02x [before]\n",
1527
+ o->pbTarget,
1528
+ o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],
1529
+ o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],
1530
+ o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));
1531
+
1532
+ #ifdef DETOURS_IA64
1533
+ ((DETOUR_IA64_BUNDLE*)o->pbTarget)
1534
+ ->SetBrl((UINT64)&o->pTrampoline->bAllocFrame);
1535
+ *o->ppbPointer = (PBYTE)&o->pTrampoline->pldTrampoline;
1536
+ #endif // DETOURS_IA64
1537
+
1538
+ #ifdef DETOURS_X64
1539
+ detour_gen_jmp_indirect(o->pTrampoline->rbCodeIn, &o->pTrampoline->pbDetour);
1540
+ PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->rbCodeIn);
1541
+ pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
1542
+ *o->ppbPointer = o->pTrampoline->rbCode;
1543
+ UNREFERENCED_PARAMETER(pbCode);
1544
+ #endif // DETOURS_X64
1545
+
1546
+ #ifdef DETOURS_X86
1547
+ PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->pbDetour);
1548
+ pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
1549
+ *o->ppbPointer = o->pTrampoline->rbCode;
1550
+ UNREFERENCED_PARAMETER(pbCode);
1551
+ #endif // DETOURS_X86
1552
+
1553
+ #ifdef DETOURS_ARM
1554
+ PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour);
1555
+ pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
1556
+ *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pTrampoline->rbCode);
1557
+ UNREFERENCED_PARAMETER(pbCode);
1558
+ #endif // DETOURS_ARM
1559
+
1560
+ #ifdef DETOURS_ARM64
1561
+ PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour);
1562
+ pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
1563
+ *o->ppbPointer = o->pTrampoline->rbCode;
1564
+ UNREFERENCED_PARAMETER(pbCode);
1565
+ #endif // DETOURS_ARM64
1566
+
1567
+ DETOUR_TRACE(("detours: pbTarget=%p: "
1568
+ "%02x %02x %02x %02x "
1569
+ "%02x %02x %02x %02x "
1570
+ "%02x %02x %02x %02x [after]\n",
1571
+ o->pbTarget,
1572
+ o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],
1573
+ o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],
1574
+ o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));
1575
+
1576
+ DETOUR_TRACE(("detours: pbTramp =%p: "
1577
+ "%02x %02x %02x %02x "
1578
+ "%02x %02x %02x %02x "
1579
+ "%02x %02x %02x %02x\n",
1580
+ o->pTrampoline,
1581
+ o->pTrampoline->rbCode[0], o->pTrampoline->rbCode[1],
1582
+ o->pTrampoline->rbCode[2], o->pTrampoline->rbCode[3],
1583
+ o->pTrampoline->rbCode[4], o->pTrampoline->rbCode[5],
1584
+ o->pTrampoline->rbCode[6], o->pTrampoline->rbCode[7],
1585
+ o->pTrampoline->rbCode[8], o->pTrampoline->rbCode[9],
1586
+ o->pTrampoline->rbCode[10], o->pTrampoline->rbCode[11]));
1587
+
1588
+ #ifdef DETOURS_IA64
1589
+ DETOUR_TRACE(("\n"));
1590
+ DETOUR_TRACE(("detours: &pldTrampoline =%p\n",
1591
+ &o->pTrampoline->pldTrampoline));
1592
+ DETOUR_TRACE(("detours: &bMovlTargetGp =%p [%p]\n",
1593
+ &o->pTrampoline->bMovlTargetGp,
1594
+ o->pTrampoline->bMovlTargetGp.GetMovlGp()));
1595
+ DETOUR_TRACE(("detours: &rbCode =%p [%p]\n",
1596
+ &o->pTrampoline->rbCode,
1597
+ ((DETOUR_IA64_BUNDLE&)o->pTrampoline->rbCode).GetBrlTarget()));
1598
+ DETOUR_TRACE(("detours: &bBrlRemainEip =%p [%p]\n",
1599
+ &o->pTrampoline->bBrlRemainEip,
1600
+ o->pTrampoline->bBrlRemainEip.GetBrlTarget()));
1601
+ DETOUR_TRACE(("detours: &bMovlDetourGp =%p [%p]\n",
1602
+ &o->pTrampoline->bMovlDetourGp,
1603
+ o->pTrampoline->bMovlDetourGp.GetMovlGp()));
1604
+ DETOUR_TRACE(("detours: &bBrlDetourEip =%p [%p]\n",
1605
+ &o->pTrampoline->bCallDetour,
1606
+ o->pTrampoline->bCallDetour.GetBrlTarget()));
1607
+ DETOUR_TRACE(("detours: pldDetour =%p [%p]\n",
1608
+ o->pTrampoline->ppldDetour->EntryPoint,
1609
+ o->pTrampoline->ppldDetour->GlobalPointer));
1610
+ DETOUR_TRACE(("detours: pldTarget =%p [%p]\n",
1611
+ o->pTrampoline->ppldTarget->EntryPoint,
1612
+ o->pTrampoline->ppldTarget->GlobalPointer));
1613
+ DETOUR_TRACE(("detours: pbRemain =%p\n",
1614
+ o->pTrampoline->pbRemain));
1615
+ DETOUR_TRACE(("detours: pbDetour =%p\n",
1616
+ o->pTrampoline->pbDetour));
1617
+ DETOUR_TRACE(("\n"));
1618
+ #endif // DETOURS_IA64
1619
+ }
1620
+ }
1621
+
1622
+ // Update any suspended threads.
1623
+ for (t = s_pPendingThreads; t != NULL; t = t->pNext) {
1624
+ CONTEXT cxt;
1625
+ cxt.ContextFlags = CONTEXT_CONTROL;
1626
+
1627
+ #undef DETOURS_EIP
1628
+
1629
+ #ifdef DETOURS_X86
1630
+ #define DETOURS_EIP Eip
1631
+ #endif // DETOURS_X86
1632
+
1633
+ #ifdef DETOURS_X64
1634
+ #define DETOURS_EIP Rip
1635
+ #endif // DETOURS_X64
1636
+
1637
+ #ifdef DETOURS_IA64
1638
+ #define DETOURS_EIP StIIP
1639
+ #endif // DETOURS_IA64
1640
+
1641
+ #ifdef DETOURS_ARM
1642
+ #define DETOURS_EIP Pc
1643
+ #endif // DETOURS_ARM
1644
+
1645
+ #ifdef DETOURS_ARM64
1646
+ #define DETOURS_EIP Pc
1647
+ #endif // DETOURS_ARM64
1648
+
1649
+ typedef ULONG_PTR DETOURS_EIP_TYPE;
1650
+
1651
+ if (GetThreadContext(t->hThread, &cxt)) {
1652
+ for (o = s_pPendingOperations; o != NULL; o = o->pNext) {
1653
+ if (o->fIsRemove) {
1654
+ if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline &&
1655
+ cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pTrampoline
1656
+ + sizeof(o->pTrampoline))
1657
+ ) {
1658
+
1659
+ cxt.DETOURS_EIP = (DETOURS_EIP_TYPE)
1660
+ ((ULONG_PTR)o->pbTarget
1661
+ + detour_align_from_trampoline(o->pTrampoline,
1662
+ (BYTE)(cxt.DETOURS_EIP
1663
+ - (DETOURS_EIP_TYPE)(ULONG_PTR)
1664
+ o->pTrampoline)));
1665
+
1666
+ SetThreadContext(t->hThread, &cxt);
1667
+ }
1668
+ }
1669
+ else {
1670
+ if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget &&
1671
+ cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pbTarget
1672
+ + o->pTrampoline->cbRestore)
1673
+ ) {
1674
+
1675
+ cxt.DETOURS_EIP = (DETOURS_EIP_TYPE)
1676
+ ((ULONG_PTR)o->pTrampoline
1677
+ + detour_align_from_target(o->pTrampoline,
1678
+ (BYTE)(cxt.DETOURS_EIP
1679
+ - (DETOURS_EIP_TYPE)(ULONG_PTR)
1680
+ o->pbTarget)));
1681
+
1682
+ SetThreadContext(t->hThread, &cxt);
1683
+ }
1684
+ }
1685
+ }
1686
+ }
1687
+ #undef DETOURS_EIP
1688
+ }
1689
+
1690
+ // Restore all of the page permissions and flush the icache.
1691
+ HANDLE hProcess = GetCurrentProcess();
1692
+ for (o = s_pPendingOperations; o != NULL;) {
1693
+ // We don't care if this fails, because the code is still accessible.
1694
+ DWORD dwOld;
1695
+ VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore, o->dwPerm, &dwOld);
1696
+ FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbRestore);
1697
+
1698
+ if (o->fIsRemove && o->pTrampoline) {
1699
+ detour_free_trampoline(o->pTrampoline);
1700
+ o->pTrampoline = NULL;
1701
+ freed = true;
1702
+ }
1703
+
1704
+ DetourOperation *n = o->pNext;
1705
+ delete o;
1706
+ o = n;
1707
+ }
1708
+ s_pPendingOperations = NULL;
1709
+
1710
+ // Free any trampoline regions that are now unused.
1711
+ if (freed && !s_fRetainRegions) {
1712
+ detour_free_unused_trampoline_regions();
1713
+ }
1714
+
1715
+ // Make sure the trampoline pages are no longer writable.
1716
+ detour_runnable_trampoline_regions();
1717
+
1718
+ // Resume any suspended threads.
1719
+ for (t = s_pPendingThreads; t != NULL;) {
1720
+ // There is nothing we can do if this fails.
1721
+ ResumeThread(t->hThread);
1722
+
1723
+ DetourThread *n = t->pNext;
1724
+ delete t;
1725
+ t = n;
1726
+ }
1727
+ s_pPendingThreads = NULL;
1728
+ s_nPendingThreadId = 0;
1729
+
1730
+ if (pppFailedPointer != NULL) {
1731
+ *pppFailedPointer = s_ppPendingError;
1732
+ }
1733
+
1734
+ return s_nPendingError;
1735
+ }
1736
+
1737
+ LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread)
1738
+ {
1739
+ LONG error;
1740
+
1741
+ // If any of the pending operations failed, then we don't need to do this.
1742
+ if (s_nPendingError != NO_ERROR) {
1743
+ return s_nPendingError;
1744
+ }
1745
+
1746
+ // Silently (and safely) drop any attempt to suspend our own thread.
1747
+ if (hThread == GetCurrentThread()) {
1748
+ return NO_ERROR;
1749
+ }
1750
+
1751
+ DetourThread *t = new NOTHROW DetourThread;
1752
+ if (t == NULL) {
1753
+ error = ERROR_NOT_ENOUGH_MEMORY;
1754
+ fail:
1755
+ if (t != NULL) {
1756
+ delete t;
1757
+ t = NULL;
1758
+ }
1759
+ s_nPendingError = error;
1760
+ s_ppPendingError = NULL;
1761
+ DETOUR_BREAK();
1762
+ return error;
1763
+ }
1764
+
1765
+ if (SuspendThread(hThread) == (DWORD)-1) {
1766
+ error = GetLastError();
1767
+ DETOUR_BREAK();
1768
+ goto fail;
1769
+ }
1770
+
1771
+ t->hThread = hThread;
1772
+ t->pNext = s_pPendingThreads;
1773
+ s_pPendingThreads = t;
1774
+
1775
+ return NO_ERROR;
1776
+ }
1777
+
1778
+ ///////////////////////////////////////////////////////////// Transacted APIs.
1779
+ //
1780
+ LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer,
1781
+ _In_ PVOID pDetour)
1782
+ {
1783
+ return DetourAttachEx(ppPointer, pDetour, NULL, NULL, NULL);
1784
+ }
1785
+
1786
+ LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
1787
+ _In_ PVOID pDetour,
1788
+ _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline,
1789
+ _Out_opt_ PVOID *ppRealTarget,
1790
+ _Out_opt_ PVOID *ppRealDetour)
1791
+ {
1792
+ LONG error = NO_ERROR;
1793
+
1794
+ if (ppRealTrampoline != NULL) {
1795
+ *ppRealTrampoline = NULL;
1796
+ }
1797
+ if (ppRealTarget != NULL) {
1798
+ *ppRealTarget = NULL;
1799
+ }
1800
+ if (ppRealDetour != NULL) {
1801
+ *ppRealDetour = NULL;
1802
+ }
1803
+ if (pDetour == NULL) {
1804
+ DETOUR_TRACE(("empty detour\n"));
1805
+ return ERROR_INVALID_PARAMETER;
1806
+ }
1807
+
1808
+ if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
1809
+ DETOUR_TRACE(("transaction conflict with thread id=%d\n", s_nPendingThreadId));
1810
+ return ERROR_INVALID_OPERATION;
1811
+ }
1812
+
1813
+ // If any of the pending operations failed, then we don't need to do this.
1814
+ if (s_nPendingError != NO_ERROR) {
1815
+ DETOUR_TRACE(("pending transaction error=%d\n", s_nPendingError));
1816
+ return s_nPendingError;
1817
+ }
1818
+
1819
+ if (ppPointer == NULL) {
1820
+ DETOUR_TRACE(("ppPointer is null\n"));
1821
+ return ERROR_INVALID_HANDLE;
1822
+ }
1823
+ if (*ppPointer == NULL) {
1824
+ error = ERROR_INVALID_HANDLE;
1825
+ s_nPendingError = error;
1826
+ s_ppPendingError = ppPointer;
1827
+ DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", ppPointer));
1828
+ DETOUR_BREAK();
1829
+ return error;
1830
+ }
1831
+
1832
+ PBYTE pbTarget = (PBYTE)*ppPointer;
1833
+ PDETOUR_TRAMPOLINE pTrampoline = NULL;
1834
+ DetourOperation *o = NULL;
1835
+
1836
+ #ifdef DETOURS_IA64
1837
+ PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour;
1838
+ PPLABEL_DESCRIPTOR ppldTarget = (PPLABEL_DESCRIPTOR)pbTarget;
1839
+ PVOID pDetourGlobals = NULL;
1840
+ PVOID pTargetGlobals = NULL;
1841
+
1842
+ pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals);
1843
+ pbTarget = (PBYTE)DetourCodeFromPointer(ppldTarget, &pTargetGlobals);
1844
+ DETOUR_TRACE((" ppldDetour=%p, code=%p [gp=%p]\n",
1845
+ ppldDetour, pDetour, pDetourGlobals));
1846
+ DETOUR_TRACE((" ppldTarget=%p, code=%p [gp=%p]\n",
1847
+ ppldTarget, pbTarget, pTargetGlobals));
1848
+ #else // DETOURS_IA64
1849
+ pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL);
1850
+ pDetour = DetourCodeFromPointer(pDetour, NULL);
1851
+ #endif // !DETOURS_IA64
1852
+
1853
+ // Don't follow a jump if its destination is the target function.
1854
+ // This happens when the detour does nothing other than call the target.
1855
+ if (pDetour == (PVOID)pbTarget) {
1856
+ if (s_fIgnoreTooSmall) {
1857
+ goto stop;
1858
+ }
1859
+ else {
1860
+ DETOUR_BREAK();
1861
+ goto fail;
1862
+ }
1863
+ }
1864
+
1865
+ if (ppRealTarget != NULL) {
1866
+ *ppRealTarget = pbTarget;
1867
+ }
1868
+ if (ppRealDetour != NULL) {
1869
+ *ppRealDetour = pDetour;
1870
+ }
1871
+
1872
+ o = new NOTHROW DetourOperation;
1873
+ if (o == NULL) {
1874
+ error = ERROR_NOT_ENOUGH_MEMORY;
1875
+ fail:
1876
+ s_nPendingError = error;
1877
+ DETOUR_BREAK();
1878
+ stop:
1879
+ if (pTrampoline != NULL) {
1880
+ detour_free_trampoline(pTrampoline);
1881
+ pTrampoline = NULL;
1882
+ if (ppRealTrampoline != NULL) {
1883
+ *ppRealTrampoline = NULL;
1884
+ }
1885
+ }
1886
+ if (o != NULL) {
1887
+ delete o;
1888
+ o = NULL;
1889
+ }
1890
+ s_ppPendingError = ppPointer;
1891
+ return error;
1892
+ }
1893
+
1894
+ pTrampoline = detour_alloc_trampoline(pbTarget);
1895
+ if (pTrampoline == NULL) {
1896
+ error = ERROR_NOT_ENOUGH_MEMORY;
1897
+ DETOUR_BREAK();
1898
+ goto fail;
1899
+ }
1900
+
1901
+ if (ppRealTrampoline != NULL) {
1902
+ *ppRealTrampoline = pTrampoline;
1903
+ }
1904
+
1905
+ DETOUR_TRACE(("detours: pbTramp=%p, pDetour=%p\n", pTrampoline, pDetour));
1906
+
1907
+ memset(pTrampoline->rAlign, 0, sizeof(pTrampoline->rAlign));
1908
+
1909
+ // Determine the number of movable target instructions.
1910
+ PBYTE pbSrc = pbTarget;
1911
+ PBYTE pbTrampoline = pTrampoline->rbCode;
1912
+ #ifdef DETOURS_IA64
1913
+ PBYTE pbPool = (PBYTE)(&pTrampoline->bBranchIslands + 1);
1914
+ #else
1915
+ PBYTE pbPool = pbTrampoline + sizeof(pTrampoline->rbCode);
1916
+ #endif
1917
+ ULONG cbTarget = 0;
1918
+ ULONG cbJump = SIZE_OF_JMP;
1919
+ ULONG nAlign = 0;
1920
+
1921
+ #ifdef DETOURS_ARM
1922
+ // On ARM, we need an extra instruction when the function isn't 32-bit aligned.
1923
+ // Check if the existing code is another detour (or at least a similar
1924
+ // "ldr pc, [PC+0]" jump.
1925
+ if ((ULONG)pbTarget & 2) {
1926
+ cbJump += 2;
1927
+
1928
+ ULONG op = fetch_thumb_opcode(pbSrc);
1929
+ if (op == 0xbf00) {
1930
+ op = fetch_thumb_opcode(pbSrc + 2);
1931
+ if (op == 0xf8dff000) { // LDR PC,[PC]
1932
+ *((PUSHORT&)pbTrampoline)++ = *((PUSHORT&)pbSrc)++;
1933
+ *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
1934
+ *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
1935
+ cbTarget = (LONG)(pbSrc - pbTarget);
1936
+ // We will fall through the "while" because cbTarget is now >= cbJump.
1937
+ }
1938
+ }
1939
+ }
1940
+ else {
1941
+ ULONG op = fetch_thumb_opcode(pbSrc);
1942
+ if (op == 0xf8dff000) { // LDR PC,[PC]
1943
+ *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
1944
+ *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
1945
+ cbTarget = (LONG)(pbSrc - pbTarget);
1946
+ // We will fall through the "while" because cbTarget is now >= cbJump.
1947
+ }
1948
+ }
1949
+ #endif
1950
+
1951
+ while (cbTarget < cbJump) {
1952
+ PBYTE pbOp = pbSrc;
1953
+ LONG lExtra = 0;
1954
+
1955
+ DETOUR_TRACE((" DetourCopyInstruction(%p,%p)\n",
1956
+ pbTrampoline, pbSrc));
1957
+ pbSrc = (PBYTE)
1958
+ DetourCopyInstruction(pbTrampoline, (PVOID*)&pbPool, pbSrc, NULL, &lExtra);
1959
+ DETOUR_TRACE((" DetourCopyInstruction() = %p (%d bytes)\n",
1960
+ pbSrc, (int)(pbSrc - pbOp)));
1961
+ pbTrampoline += (pbSrc - pbOp) + lExtra;
1962
+ cbTarget = (LONG)(pbSrc - pbTarget);
1963
+ pTrampoline->rAlign[nAlign].obTarget = cbTarget;
1964
+ pTrampoline->rAlign[nAlign].obTrampoline = pbTrampoline - pTrampoline->rbCode;
1965
+ nAlign++;
1966
+
1967
+ if (nAlign >= ARRAYSIZE(pTrampoline->rAlign)) {
1968
+ break;
1969
+ }
1970
+
1971
+ if (detour_does_code_end_function(pbOp)) {
1972
+ break;
1973
+ }
1974
+ }
1975
+
1976
+ // Consume, but don't duplicate padding if it is needed and available.
1977
+ while (cbTarget < cbJump) {
1978
+ LONG cFiller = detour_is_code_filler(pbSrc);
1979
+ if (cFiller == 0) {
1980
+ break;
1981
+ }
1982
+
1983
+ pbSrc += cFiller;
1984
+ cbTarget = (LONG)(pbSrc - pbTarget);
1985
+ }
1986
+
1987
+ #if DETOUR_DEBUG
1988
+ {
1989
+ DETOUR_TRACE((" detours: rAlign ["));
1990
+ LONG n = 0;
1991
+ for (n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) {
1992
+ if (pTrampoline->rAlign[n].obTarget == 0 &&
1993
+ pTrampoline->rAlign[n].obTrampoline == 0) {
1994
+ break;
1995
+ }
1996
+ DETOUR_TRACE((" %d/%d",
1997
+ pTrampoline->rAlign[n].obTarget,
1998
+ pTrampoline->rAlign[n].obTrampoline
1999
+ ));
2000
+
2001
+ }
2002
+ DETOUR_TRACE((" ]\n"));
2003
+ }
2004
+ #endif
2005
+
2006
+ if (cbTarget < cbJump || nAlign > ARRAYSIZE(pTrampoline->rAlign)) {
2007
+ // Too few instructions.
2008
+
2009
+ error = ERROR_INVALID_BLOCK;
2010
+ if (s_fIgnoreTooSmall) {
2011
+ goto stop;
2012
+ }
2013
+ else {
2014
+ DETOUR_BREAK();
2015
+ goto fail;
2016
+ }
2017
+ }
2018
+
2019
+ if (pbTrampoline > pbPool) {
2020
+ __debugbreak();
2021
+ }
2022
+
2023
+ pTrampoline->cbCode = (BYTE)(pbTrampoline - pTrampoline->rbCode);
2024
+ pTrampoline->cbRestore = (BYTE)cbTarget;
2025
+ CopyMemory(pTrampoline->rbRestore, pbTarget, cbTarget);
2026
+
2027
+ #if !defined(DETOURS_IA64)
2028
+ if (cbTarget > sizeof(pTrampoline->rbCode) - cbJump) {
2029
+ // Too many instructions.
2030
+ error = ERROR_INVALID_HANDLE;
2031
+ DETOUR_BREAK();
2032
+ goto fail;
2033
+ }
2034
+ #endif // !DETOURS_IA64
2035
+
2036
+ pTrampoline->pbRemain = pbTarget + cbTarget;
2037
+ pTrampoline->pbDetour = (PBYTE)pDetour;
2038
+
2039
+ #ifdef DETOURS_IA64
2040
+ pTrampoline->ppldDetour = ppldDetour;
2041
+ pTrampoline->ppldTarget = ppldTarget;
2042
+ pTrampoline->pldTrampoline.EntryPoint = (UINT64)&pTrampoline->bMovlTargetGp;
2043
+ pTrampoline->pldTrampoline.GlobalPointer = (UINT64)pDetourGlobals;
2044
+
2045
+ ((DETOUR_IA64_BUNDLE *)pTrampoline->rbCode)->SetStop();
2046
+
2047
+ pTrampoline->bMovlTargetGp.SetMovlGp((UINT64)pTargetGlobals);
2048
+ pTrampoline->bBrlRemainEip.SetBrl((UINT64)pTrampoline->pbRemain);
2049
+
2050
+ // Alloc frame: alloc r41=ar.pfs,11,0,8,0; mov r40=rp
2051
+ pTrampoline->bAllocFrame.wide[0] = 0x00000580164d480c;
2052
+ pTrampoline->bAllocFrame.wide[1] = 0x00c4000500000200;
2053
+ // save r36, r37, r38.
2054
+ pTrampoline->bSave37to39.wide[0] = 0x031021004e019001;
2055
+ pTrampoline->bSave37to39.wide[1] = 0x8401280600420098;
2056
+ // save r34,r35,r36: adds r47=0,r36; adds r46=0,r35; adds r45=0,r34
2057
+ pTrampoline->bSave34to36.wide[0] = 0x02e0210048017800;
2058
+ pTrampoline->bSave34to36.wide[1] = 0x84011005a042008c;
2059
+ // save gp,r32,r33" adds r44=0,r33; adds r43=0,r32; adds r42=0,gp ;;
2060
+ pTrampoline->bSaveGPto33.wide[0] = 0x02b0210042016001;
2061
+ pTrampoline->bSaveGPto33.wide[1] = 0x8400080540420080;
2062
+ // set detour GP.
2063
+ pTrampoline->bMovlDetourGp.SetMovlGp((UINT64)pDetourGlobals);
2064
+ // call detour: brl.call.sptk.few rp=detour ;;
2065
+ pTrampoline->bCallDetour.wide[0] = 0x0000000100000005;
2066
+ pTrampoline->bCallDetour.wide[1] = 0xd000001000000000;
2067
+ pTrampoline->bCallDetour.SetBrlTarget((UINT64)pDetour);
2068
+ // pop frame & gp: adds gp=0,r42; mov rp=r40,+0;; mov.i ar.pfs=r41
2069
+ pTrampoline->bPopFrameGp.wide[0] = 0x4000210054000802;
2070
+ pTrampoline->bPopFrameGp.wide[1] = 0x00aa029000038005;
2071
+ // return to caller: br.ret.sptk.many rp ;;
2072
+ pTrampoline->bReturn.wide[0] = 0x0000000100000019;
2073
+ pTrampoline->bReturn.wide[1] = 0x0084000880000200;
2074
+
2075
+ DETOUR_TRACE(("detours: &bMovlTargetGp=%p\n", &pTrampoline->bMovlTargetGp));
2076
+ DETOUR_TRACE(("detours: &bMovlDetourGp=%p\n", &pTrampoline->bMovlDetourGp));
2077
+ #endif // DETOURS_IA64
2078
+
2079
+ pbTrampoline = pTrampoline->rbCode + pTrampoline->cbCode;
2080
+ #ifdef DETOURS_X64
2081
+ pbTrampoline = detour_gen_jmp_indirect(pbTrampoline, &pTrampoline->pbRemain);
2082
+ pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
2083
+ #endif // DETOURS_X64
2084
+
2085
+ #ifdef DETOURS_X86
2086
+ pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, pTrampoline->pbRemain);
2087
+ pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
2088
+ #endif // DETOURS_X86
2089
+
2090
+ #ifdef DETOURS_ARM
2091
+ pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain);
2092
+ pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
2093
+ #endif // DETOURS_ARM
2094
+
2095
+ #ifdef DETOURS_ARM64
2096
+ pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain);
2097
+ pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
2098
+ #endif // DETOURS_ARM64
2099
+
2100
+ (void)pbTrampoline;
2101
+
2102
+ DWORD dwOld = 0;
2103
+ if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) {
2104
+ error = GetLastError();
2105
+ DETOUR_BREAK();
2106
+ goto fail;
2107
+ }
2108
+
2109
+ DETOUR_TRACE(("detours: pbTarget=%p: "
2110
+ "%02x %02x %02x %02x "
2111
+ "%02x %02x %02x %02x "
2112
+ "%02x %02x %02x %02x\n",
2113
+ pbTarget,
2114
+ pbTarget[0], pbTarget[1], pbTarget[2], pbTarget[3],
2115
+ pbTarget[4], pbTarget[5], pbTarget[6], pbTarget[7],
2116
+ pbTarget[8], pbTarget[9], pbTarget[10], pbTarget[11]));
2117
+ DETOUR_TRACE(("detours: pbTramp =%p: "
2118
+ "%02x %02x %02x %02x "
2119
+ "%02x %02x %02x %02x "
2120
+ "%02x %02x %02x %02x\n",
2121
+ pTrampoline,
2122
+ pTrampoline->rbCode[0], pTrampoline->rbCode[1],
2123
+ pTrampoline->rbCode[2], pTrampoline->rbCode[3],
2124
+ pTrampoline->rbCode[4], pTrampoline->rbCode[5],
2125
+ pTrampoline->rbCode[6], pTrampoline->rbCode[7],
2126
+ pTrampoline->rbCode[8], pTrampoline->rbCode[9],
2127
+ pTrampoline->rbCode[10], pTrampoline->rbCode[11]));
2128
+
2129
+ o->fIsRemove = FALSE;
2130
+ o->ppbPointer = (PBYTE*)ppPointer;
2131
+ o->pTrampoline = pTrampoline;
2132
+ o->pbTarget = pbTarget;
2133
+ o->dwPerm = dwOld;
2134
+ o->pNext = s_pPendingOperations;
2135
+ s_pPendingOperations = o;
2136
+
2137
+ return NO_ERROR;
2138
+ }
2139
+
2140
+ LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer,
2141
+ _In_ PVOID pDetour)
2142
+ {
2143
+ LONG error = NO_ERROR;
2144
+
2145
+ if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
2146
+ return ERROR_INVALID_OPERATION;
2147
+ }
2148
+
2149
+ // If any of the pending operations failed, then we don't need to do this.
2150
+ if (s_nPendingError != NO_ERROR) {
2151
+ return s_nPendingError;
2152
+ }
2153
+
2154
+ if (pDetour == NULL) {
2155
+ return ERROR_INVALID_PARAMETER;
2156
+ }
2157
+ if (ppPointer == NULL) {
2158
+ return ERROR_INVALID_HANDLE;
2159
+ }
2160
+ if (*ppPointer == NULL) {
2161
+ error = ERROR_INVALID_HANDLE;
2162
+ s_nPendingError = error;
2163
+ s_ppPendingError = ppPointer;
2164
+ DETOUR_BREAK();
2165
+ return error;
2166
+ }
2167
+
2168
+ DetourOperation *o = new NOTHROW DetourOperation;
2169
+ if (o == NULL) {
2170
+ error = ERROR_NOT_ENOUGH_MEMORY;
2171
+ fail:
2172
+ s_nPendingError = error;
2173
+ DETOUR_BREAK();
2174
+ stop:
2175
+ if (o != NULL) {
2176
+ delete o;
2177
+ o = NULL;
2178
+ }
2179
+ s_ppPendingError = ppPointer;
2180
+ return error;
2181
+ }
2182
+
2183
+
2184
+ #ifdef DETOURS_IA64
2185
+ PPLABEL_DESCRIPTOR ppldTrampo = (PPLABEL_DESCRIPTOR)*ppPointer;
2186
+ PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour;
2187
+ PVOID pDetourGlobals = NULL;
2188
+ PVOID pTrampoGlobals = NULL;
2189
+
2190
+ pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals);
2191
+ PDETOUR_TRAMPOLINE pTrampoline = (PDETOUR_TRAMPOLINE)
2192
+ DetourCodeFromPointer(ppldTrampo, &pTrampoGlobals);
2193
+ DETOUR_TRACE((" ppldDetour=%p, code=%p [gp=%p]\n",
2194
+ ppldDetour, pDetour, pDetourGlobals));
2195
+ DETOUR_TRACE((" ppldTrampo=%p, code=%p [gp=%p]\n",
2196
+ ppldTrampo, pTrampoline, pTrampoGlobals));
2197
+
2198
+
2199
+ DETOUR_TRACE(("\n"));
2200
+ DETOUR_TRACE(("detours: &pldTrampoline =%p\n",
2201
+ &pTrampoline->pldTrampoline));
2202
+ DETOUR_TRACE(("detours: &bMovlTargetGp =%p [%p]\n",
2203
+ &pTrampoline->bMovlTargetGp,
2204
+ pTrampoline->bMovlTargetGp.GetMovlGp()));
2205
+ DETOUR_TRACE(("detours: &rbCode =%p [%p]\n",
2206
+ &pTrampoline->rbCode,
2207
+ ((DETOUR_IA64_BUNDLE&)pTrampoline->rbCode).GetBrlTarget()));
2208
+ DETOUR_TRACE(("detours: &bBrlRemainEip =%p [%p]\n",
2209
+ &pTrampoline->bBrlRemainEip,
2210
+ pTrampoline->bBrlRemainEip.GetBrlTarget()));
2211
+ DETOUR_TRACE(("detours: &bMovlDetourGp =%p [%p]\n",
2212
+ &pTrampoline->bMovlDetourGp,
2213
+ pTrampoline->bMovlDetourGp.GetMovlGp()));
2214
+ DETOUR_TRACE(("detours: &bBrlDetourEip =%p [%p]\n",
2215
+ &pTrampoline->bCallDetour,
2216
+ pTrampoline->bCallDetour.GetBrlTarget()));
2217
+ DETOUR_TRACE(("detours: pldDetour =%p [%p]\n",
2218
+ pTrampoline->ppldDetour->EntryPoint,
2219
+ pTrampoline->ppldDetour->GlobalPointer));
2220
+ DETOUR_TRACE(("detours: pldTarget =%p [%p]\n",
2221
+ pTrampoline->ppldTarget->EntryPoint,
2222
+ pTrampoline->ppldTarget->GlobalPointer));
2223
+ DETOUR_TRACE(("detours: pbRemain =%p\n",
2224
+ pTrampoline->pbRemain));
2225
+ DETOUR_TRACE(("detours: pbDetour =%p\n",
2226
+ pTrampoline->pbDetour));
2227
+ DETOUR_TRACE(("\n"));
2228
+ #else // !DETOURS_IA64
2229
+ PDETOUR_TRAMPOLINE pTrampoline =
2230
+ (PDETOUR_TRAMPOLINE)DetourCodeFromPointer(*ppPointer, NULL);
2231
+ pDetour = DetourCodeFromPointer(pDetour, NULL);
2232
+ #endif // !DETOURS_IA64
2233
+
2234
+ ////////////////////////////////////// Verify that Trampoline is in place.
2235
+ //
2236
+ LONG cbTarget = pTrampoline->cbRestore;
2237
+ PBYTE pbTarget = pTrampoline->pbRemain - cbTarget;
2238
+ if (cbTarget == 0 || cbTarget > sizeof(pTrampoline->rbCode)) {
2239
+ error = ERROR_INVALID_BLOCK;
2240
+ if (s_fIgnoreTooSmall) {
2241
+ goto stop;
2242
+ }
2243
+ else {
2244
+ DETOUR_BREAK();
2245
+ goto fail;
2246
+ }
2247
+ }
2248
+
2249
+ if (pTrampoline->pbDetour != pDetour) {
2250
+ error = ERROR_INVALID_BLOCK;
2251
+ if (s_fIgnoreTooSmall) {
2252
+ goto stop;
2253
+ }
2254
+ else {
2255
+ DETOUR_BREAK();
2256
+ goto fail;
2257
+ }
2258
+ }
2259
+
2260
+ DWORD dwOld = 0;
2261
+ if (!VirtualProtect(pbTarget, cbTarget,
2262
+ PAGE_EXECUTE_READWRITE, &dwOld)) {
2263
+ error = GetLastError();
2264
+ DETOUR_BREAK();
2265
+ goto fail;
2266
+ }
2267
+
2268
+ o->fIsRemove = TRUE;
2269
+ o->ppbPointer = (PBYTE*)ppPointer;
2270
+ o->pTrampoline = pTrampoline;
2271
+ o->pbTarget = pbTarget;
2272
+ o->dwPerm = dwOld;
2273
+ o->pNext = s_pPendingOperations;
2274
+ s_pPendingOperations = o;
2275
+
2276
+ return NO_ERROR;
2277
+ }
2278
+
2279
+ //////////////////////////////////////////////////////////////////////////////
2280
+ //
2281
+ // Helpers for manipulating page protection.
2282
+ //
2283
+
2284
+ // For reference:
2285
+ // PAGE_NOACCESS 0x01
2286
+ // PAGE_READONLY 0x02
2287
+ // PAGE_READWRITE 0x04
2288
+ // PAGE_WRITECOPY 0x08
2289
+ // PAGE_EXECUTE 0x10
2290
+ // PAGE_EXECUTE_READ 0x20
2291
+ // PAGE_EXECUTE_READWRITE 0x40
2292
+ // PAGE_EXECUTE_WRITECOPY 0x80
2293
+ // PAGE_GUARD ...
2294
+ // PAGE_NOCACHE ...
2295
+ // PAGE_WRITECOMBINE ...
2296
+
2297
+ #define DETOUR_PAGE_EXECUTE_ALL (PAGE_EXECUTE | \
2298
+ PAGE_EXECUTE_READ | \
2299
+ PAGE_EXECUTE_READWRITE | \
2300
+ PAGE_EXECUTE_WRITECOPY)
2301
+
2302
+ #define DETOUR_PAGE_NO_EXECUTE_ALL (PAGE_NOACCESS | \
2303
+ PAGE_READONLY | \
2304
+ PAGE_READWRITE | \
2305
+ PAGE_WRITECOPY)
2306
+
2307
+ #define DETOUR_PAGE_ATTRIBUTES (~(DETOUR_PAGE_EXECUTE_ALL | DETOUR_PAGE_NO_EXECUTE_ALL))
2308
+
2309
+ C_ASSERT((DETOUR_PAGE_NO_EXECUTE_ALL << 4) == DETOUR_PAGE_EXECUTE_ALL);
2310
+
2311
+ static DWORD DetourPageProtectAdjustExecute(_In_ DWORD dwOldProtect,
2312
+ _In_ DWORD dwNewProtect)
2313
+ // Copy EXECUTE from dwOldProtect to dwNewProtect.
2314
+ {
2315
+ bool const fOldExecute = ((dwOldProtect & DETOUR_PAGE_EXECUTE_ALL) != 0);
2316
+ bool const fNewExecute = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) != 0);
2317
+
2318
+ if (fOldExecute && !fNewExecute) {
2319
+ dwNewProtect = ((dwNewProtect & DETOUR_PAGE_NO_EXECUTE_ALL) << 4)
2320
+ | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES);
2321
+ }
2322
+ else if (!fOldExecute && fNewExecute) {
2323
+ dwNewProtect = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) >> 4)
2324
+ | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES);
2325
+ }
2326
+ return dwNewProtect;
2327
+ }
2328
+
2329
+ _Success_(return != FALSE)
2330
+ BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess,
2331
+ _In_ PVOID pAddress,
2332
+ _In_ SIZE_T nSize,
2333
+ _In_ DWORD dwNewProtect,
2334
+ _Out_ PDWORD pdwOldProtect)
2335
+ // Some systems do not allow executability of a page to change. This function applies
2336
+ // dwNewProtect to [pAddress, nSize), but preserving the previous executability.
2337
+ // This function is meant to be a drop-in replacement for some uses of VirtualProtectEx.
2338
+ // When "restoring" page protection, there is no need to use this function.
2339
+ {
2340
+ MEMORY_BASIC_INFORMATION mbi;
2341
+
2342
+ // Query to get existing execute access.
2343
+
2344
+ ZeroMemory(&mbi, sizeof(mbi));
2345
+
2346
+ if (VirtualQueryEx(hProcess, pAddress, &mbi, sizeof(mbi)) == 0) {
2347
+ return FALSE;
2348
+ }
2349
+ return VirtualProtectEx(hProcess, pAddress, nSize,
2350
+ DetourPageProtectAdjustExecute(mbi.Protect, dwNewProtect),
2351
+ pdwOldProtect);
2352
+ }
2353
+
2354
+ _Success_(return != FALSE)
2355
+ BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress,
2356
+ _In_ SIZE_T nSize,
2357
+ _In_ DWORD dwNewProtect,
2358
+ _Out_ PDWORD pdwOldProtect)
2359
+ {
2360
+ return DetourVirtualProtectSameExecuteEx(GetCurrentProcess(),
2361
+ pAddress, nSize, dwNewProtect, pdwOldProtect);
2362
+ }
2363
+
2364
+ // End of File