1 //===-- interception_win_test.cpp -----------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10 // Tests for interception_win.h.
12 //===----------------------------------------------------------------------===//
13 #include "interception/interception.h"
15 #include "gtest/gtest.h"
17 // Too slow for debug build
18 // Disabling for ARM64 since testcases are x86/x64 assembly.
21 # if !SANITIZER_WINDOWS_ARM64
25 # define WIN32_LEAN_AND_MEAN
28 namespace __interception
{
31 enum FunctionPrefixKind
{
33 FunctionPrefixPadding
,
34 FunctionPrefixHotPatch
,
38 typedef bool (*TestOverrideFunction
)(uptr
, uptr
, uptr
*);
39 typedef int (*IdentityFunction
)(int);
41 #if SANITIZER_WINDOWS64
43 const u8 kIdentityCodeWithPrologue
[] = {
45 0x48, 0x89, 0xE5, // mov rbp,rsp
46 0x8B, 0xC1, // mov eax,ecx
51 const u8 kIdentityCodeWithPushPop
[] = {
53 0x48, 0x89, 0xE5, // mov rbp,rsp
57 0x8B, 0xC1, // mov rax,rcx
63 const u8 kIdentityTwiceOffset
= 16;
64 const u8 kIdentityTwice
[] = {
66 0x48, 0x89, 0xE5, // mov rbp,rsp
67 0x8B, 0xC1, // mov eax,ecx
70 0x90, 0x90, 0x90, 0x90,
71 0x90, 0x90, 0x90, 0x90,
73 0x48, 0x89, 0xE5, // mov rbp,rsp
74 0x8B, 0xC1, // mov eax,ecx
79 const u8 kIdentityCodeWithMov
[] = {
80 0x89, 0xC8, // mov eax, ecx
84 const u8 kIdentityCodeWithJump
[] = {
85 0xE9, 0x04, 0x00, 0x00,
87 0xCC, 0xCC, 0xCC, 0xCC,
88 0x89, 0xC8, // mov eax, ecx
92 const u8 kIdentityCodeWithJumpBackwards
[] = {
93 0x89, 0xC8, // mov eax, ecx
95 0xE9, 0xF8, 0xFF, 0xFF,
97 0xCC, 0xCC, 0xCC, 0xCC,
99 const u8 kIdentityCodeWithJumpBackwardsOffset
= 3;
103 const u8 kIdentityCodeWithPrologue
[] = {
105 0x8B, 0xEC, // mov ebp,esp
106 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
111 const u8 kIdentityCodeWithPushPop
[] = {
113 0x8B, 0xEC, // mov ebp,esp
117 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
123 const u8 kIdentityTwiceOffset
= 8;
124 const u8 kIdentityTwice
[] = {
126 0x8B, 0xEC, // mov ebp,esp
127 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
131 0x8B, 0xEC, // mov ebp,esp
132 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
137 const u8 kIdentityCodeWithMov
[] = {
138 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4]
142 const u8 kIdentityCodeWithJump
[] = {
143 0xE9, 0x04, 0x00, 0x00,
145 0xCC, 0xCC, 0xCC, 0xCC,
146 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4]
150 const u8 kIdentityCodeWithJumpBackwards
[] = {
151 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4]
153 0xE9, 0xF6, 0xFF, 0xFF,
155 0xCC, 0xCC, 0xCC, 0xCC,
157 const u8 kIdentityCodeWithJumpBackwardsOffset
= 5;
161 const u8 kPatchableCode1
[] = {
162 0xB8, 0x4B, 0x00, 0x00, 0x00, // mov eax,4B
163 0x33, 0xC9, // xor ecx,ecx
167 const u8 kPatchableCode2
[] = {
169 0x8B, 0xEC, // mov ebp,esp
170 0x33, 0xC0, // xor eax,eax
175 const u8 kPatchableCode3
[] = {
177 0x8B, 0xEC, // mov ebp,esp
178 0x6A, 0x00, // push 0
179 0xE8, 0x3D, 0xFF, 0xFF, 0xFF, // call <func>
182 const u8 kPatchableCode4
[] = {
183 0xE9, 0xCC, 0xCC, 0xCC, 0xCC, // jmp <label>
184 0x90, 0x90, 0x90, 0x90,
187 const u8 kPatchableCode5
[] = {
189 0x8b, 0xec, // mov ebp,esp
190 0x8d, 0xa4, 0x24, 0x30, 0xfd, 0xff, 0xff, // lea esp,[esp-2D0h]
194 #if SANITIZER_WINDOWS64
195 u8 kLoadGlobalCode
[] = {
196 0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov eax [rip + global]
201 const u8 kUnpatchableCode1
[] = {
205 const u8 kUnpatchableCode2
[] = {
206 0x33, 0xC9, // xor ecx,ecx
210 const u8 kUnpatchableCode3
[] = {
211 0x75, 0xCC, // jne <label>
212 0x33, 0xC9, // xor ecx,ecx
216 const u8 kUnpatchableCode4
[] = {
217 0x74, 0xCC, // jne <label>
218 0x33, 0xC9, // xor ecx,ecx
222 const u8 kUnpatchableCode5
[] = {
223 0xEB, 0x02, // jmp <label>
224 0x33, 0xC9, // xor ecx,ecx
228 const u8 kUnpatchableCode6
[] = {
229 0xE8, 0xCC, 0xCC, 0xCC, 0xCC, // call <func>
230 0x90, 0x90, 0x90, 0x90,
233 # if SANITIZER_WINDOWS64
234 const u8 kUnpatchableCode7
[] = {
235 0x33, 0xc0, // xor eax,eax
236 0x48, 0x85, 0xd2, // test rdx,rdx
237 0x74, 0x10, // je +16 (unpatchable)
240 const u8 kUnpatchableCode8
[] = {
241 0x48, 0x8b, 0xc1, // mov rax,rcx
242 0x0f, 0xb7, 0x10, // movzx edx,word ptr [rax]
243 0x48, 0x83, 0xc0, 0x02, // add rax,2
244 0x66, 0x85, 0xd2, // test dx,dx
245 0x75, 0xf4, // jne -12 (unpatchable)
248 const u8 kUnpatchableCode9
[] = {
249 0x4c, 0x8b, 0xc1, // mov r8,rcx
250 0x8a, 0x01, // mov al,byte ptr [rcx]
251 0x48, 0xff, 0xc1, // inc rcx
252 0x84, 0xc0, // test al,al
253 0x75, 0xf7, // jne -9 (unpatchable)
256 const u8 kPatchableCode6
[] = {
257 0x48, 0x89, 0x54, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], rdx
258 0x33, 0xC9, // xor ecx,ecx
262 const u8 kPatchableCode7
[] = {
263 0x4c, 0x89, 0x4c, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], r9
264 0x33, 0xC9, // xor ecx,ecx
268 const u8 kPatchableCode8
[] = {
269 0x4c, 0x89, 0x44, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], r8
270 0x33, 0xC9, // xor ecx,ecx
274 const u8 kPatchableCode9
[] = {
275 0x8a, 0x01, // al,byte ptr [rcx]
276 0x45, 0x33, 0xc0, // xor r8d,r8d
277 0x84, 0xc0, // test al,al
280 const u8 kPatchableCode10
[] = {
281 0x45, 0x33, 0xc0, // xor r8d,r8d
282 0x41, 0x8b, 0xc0, // mov eax,r8d
283 0x48, 0x85, 0xd2, // test rdx,rdx
286 const u8 kPatchableCode11
[] = {
287 0x48, 0x83, 0xec, 0x38, // sub rsp,38h
288 0x83, 0x64, 0x24, 0x28, 0x00, // and dword ptr [rsp+28h],0
292 # if !SANITIZER_WINDOWS64
293 const u8 kPatchableCode12
[] = {
298 0x8b, 0x6c, 0x24, 0x18, // mov ebp,dword ptr[esp+18h]
301 const u8 kPatchableCode13
[] = {
306 0x8b, 0x5c, 0x24, 0x14, // mov ebx,dword ptr[esp+14h]
310 const u8 kPatchableCode14
[] = {
312 0x89, 0xe5, // mov ebp,esp
318 const u8 kUnsupportedCode1
[] = {
325 // A buffer holding the dynamically generated code under test.
327 const size_t ActiveCodeLength
= 4096;
329 int InterceptorFunction(int x
);
331 /// Allocate code memory more than 2GB away from Base.
332 u8
*AllocateCode2GBAway(u8
*Base
) {
333 // Find a 64K aligned location after Base plus 2GB.
334 size_t TwoGB
= 0x80000000;
335 size_t AllocGranularity
= 0x10000;
336 Base
= (u8
*)((((uptr
)Base
+ TwoGB
+ AllocGranularity
)) & ~(AllocGranularity
- 1));
338 // Check if that location is free, and if not, loop over regions until we find
340 MEMORY_BASIC_INFORMATION mbi
= {};
341 while (sizeof(mbi
) == VirtualQuery(Base
, &mbi
, sizeof(mbi
))) {
342 if (mbi
.State
& MEM_FREE
) break;
343 Base
+= mbi
.RegionSize
;
346 // Allocate one RWX page at the free location.
347 return (u8
*)::VirtualAlloc(Base
, ActiveCodeLength
, MEM_COMMIT
| MEM_RESERVE
,
348 PAGE_EXECUTE_READWRITE
);
352 static void LoadActiveCode(
355 FunctionPrefixKind prefix_kind
= FunctionPrefixNone
) {
356 if (ActiveCode
== nullptr) {
357 ActiveCode
= AllocateCode2GBAway((u8
*)&InterceptorFunction
);
358 ASSERT_NE(ActiveCode
, nullptr) << "failed to allocate RWX memory 2GB away";
363 // Add padding to avoid memory violation when scanning the prefix.
364 for (int i
= 0; i
< 16; ++i
)
365 ActiveCode
[position
++] = 0xC3; // Instruction 'ret'.
367 // Add function padding.
369 if (prefix_kind
== FunctionPrefixPadding
)
371 else if (prefix_kind
== FunctionPrefixDetour
||
372 prefix_kind
== FunctionPrefixHotPatch
)
373 padding
= FIRST_32_SECOND_64(5, 6);
374 // Insert |padding| instructions 'nop'.
375 for (size_t i
= 0; i
< padding
; ++i
)
376 ActiveCode
[position
++] = 0x90;
378 // Keep track of the entry point.
379 *entry_point
= (uptr
)&ActiveCode
[position
];
381 // Add the detour instruction (i.e. mov edi, edi)
382 if (prefix_kind
== FunctionPrefixDetour
) {
383 #if SANITIZER_WINDOWS64
384 // Note that "mov edi,edi" is NOP in 32-bit only, in 64-bit it clears
385 // higher bits of RDI.
386 // Use 66,90H as NOP for Windows64.
387 ActiveCode
[position
++] = 0x66;
388 ActiveCode
[position
++] = 0x90;
391 ActiveCode
[position
++] = 0x8B;
392 ActiveCode
[position
++] = 0xFF;
397 // Copy the function body.
398 for (size_t i
= 0; i
< sizeof(T
); ++i
)
399 ActiveCode
[position
++] = code
[i
];
402 int InterceptorFunctionCalled
;
403 IdentityFunction InterceptedRealFunction
;
405 int InterceptorFunction(int x
) {
406 ++InterceptorFunctionCalled
;
407 return InterceptedRealFunction(x
);
412 // Tests for interception_win.h
413 TEST(Interception
, InternalGetProcAddress
) {
414 HMODULE ntdll_handle
= ::GetModuleHandle("ntdll");
415 ASSERT_NE(nullptr, ntdll_handle
);
416 uptr DbgPrint_expected
= (uptr
)::GetProcAddress(ntdll_handle
, "DbgPrint");
417 uptr isdigit_expected
= (uptr
)::GetProcAddress(ntdll_handle
, "isdigit");
418 uptr DbgPrint_adddress
= InternalGetProcAddress(ntdll_handle
, "DbgPrint");
419 uptr isdigit_address
= InternalGetProcAddress(ntdll_handle
, "isdigit");
421 EXPECT_EQ(DbgPrint_expected
, DbgPrint_adddress
);
422 EXPECT_EQ(isdigit_expected
, isdigit_address
);
423 EXPECT_NE(DbgPrint_adddress
, isdigit_address
);
427 static void TestIdentityFunctionPatching(
428 const T
&code
, TestOverrideFunction override
,
429 FunctionPrefixKind prefix_kind
= FunctionPrefixNone
,
430 int function_start_offset
= 0) {
431 uptr identity_address
;
432 LoadActiveCode(code
, &identity_address
, prefix_kind
);
433 identity_address
+= function_start_offset
;
434 IdentityFunction identity
= (IdentityFunction
)identity_address
;
436 // Validate behavior before dynamic patching.
437 InterceptorFunctionCalled
= 0;
438 EXPECT_EQ(0, identity(0));
439 EXPECT_EQ(42, identity(42));
440 EXPECT_EQ(0, InterceptorFunctionCalled
);
442 // Patch the function.
443 uptr real_identity_address
= 0;
444 bool success
= override(identity_address
,
445 (uptr
)&InterceptorFunction
,
446 &real_identity_address
);
447 EXPECT_TRUE(success
);
448 EXPECT_NE(0U, real_identity_address
);
449 IdentityFunction real_identity
= (IdentityFunction
)real_identity_address
;
450 InterceptedRealFunction
= real_identity
;
452 // Don't run tests if hooking failed or the real function is not valid.
453 if (!success
|| !real_identity_address
)
456 // Calling the redirected function.
457 InterceptorFunctionCalled
= 0;
458 EXPECT_EQ(0, identity(0));
459 EXPECT_EQ(42, identity(42));
460 EXPECT_EQ(2, InterceptorFunctionCalled
);
462 // Calling the real function.
463 InterceptorFunctionCalled
= 0;
464 EXPECT_EQ(0, real_identity(0));
465 EXPECT_EQ(42, real_identity(42));
466 EXPECT_EQ(0, InterceptorFunctionCalled
);
468 TestOnlyReleaseTrampolineRegions();
471 # if !SANITIZER_WINDOWS64
472 TEST(Interception
, OverrideFunctionWithDetour
) {
473 TestOverrideFunction override
= OverrideFunctionWithDetour
;
474 FunctionPrefixKind prefix
= FunctionPrefixDetour
;
475 TestIdentityFunctionPatching(kIdentityCodeWithPrologue
, override
, prefix
);
476 TestIdentityFunctionPatching(kIdentityCodeWithPushPop
, override
, prefix
);
477 TestIdentityFunctionPatching(kIdentityCodeWithMov
, override
, prefix
);
478 TestIdentityFunctionPatching(kIdentityCodeWithJump
, override
, prefix
);
480 #endif // !SANITIZER_WINDOWS64
482 TEST(Interception
, OverrideFunctionWithRedirectJump
) {
483 TestOverrideFunction override
= OverrideFunctionWithRedirectJump
;
484 TestIdentityFunctionPatching(kIdentityCodeWithJump
, override
);
485 TestIdentityFunctionPatching(kIdentityCodeWithJumpBackwards
, override
,
487 kIdentityCodeWithJumpBackwardsOffset
);
490 TEST(Interception
, OverrideFunctionWithHotPatch
) {
491 TestOverrideFunction override
= OverrideFunctionWithHotPatch
;
492 FunctionPrefixKind prefix
= FunctionPrefixHotPatch
;
493 TestIdentityFunctionPatching(kIdentityCodeWithMov
, override
, prefix
);
496 TEST(Interception
, OverrideFunctionWithTrampoline
) {
497 TestOverrideFunction override
= OverrideFunctionWithTrampoline
;
498 FunctionPrefixKind prefix
= FunctionPrefixNone
;
499 TestIdentityFunctionPatching(kIdentityCodeWithPrologue
, override
, prefix
);
500 TestIdentityFunctionPatching(kIdentityCodeWithPushPop
, override
, prefix
);
502 prefix
= FunctionPrefixPadding
;
503 TestIdentityFunctionPatching(kIdentityCodeWithPrologue
, override
, prefix
);
504 TestIdentityFunctionPatching(kIdentityCodeWithPushPop
, override
, prefix
);
507 TEST(Interception
, OverrideFunction
) {
508 TestOverrideFunction override
= OverrideFunction
;
509 FunctionPrefixKind prefix
= FunctionPrefixNone
;
510 TestIdentityFunctionPatching(kIdentityCodeWithPrologue
, override
, prefix
);
511 TestIdentityFunctionPatching(kIdentityCodeWithPushPop
, override
, prefix
);
512 TestIdentityFunctionPatching(kIdentityCodeWithJump
, override
, prefix
);
514 prefix
= FunctionPrefixPadding
;
515 TestIdentityFunctionPatching(kIdentityCodeWithPrologue
, override
, prefix
);
516 TestIdentityFunctionPatching(kIdentityCodeWithPushPop
, override
, prefix
);
517 TestIdentityFunctionPatching(kIdentityCodeWithMov
, override
, prefix
);
518 TestIdentityFunctionPatching(kIdentityCodeWithJump
, override
, prefix
);
520 prefix
= FunctionPrefixHotPatch
;
521 TestIdentityFunctionPatching(kIdentityCodeWithPrologue
, override
, prefix
);
522 TestIdentityFunctionPatching(kIdentityCodeWithPushPop
, override
, prefix
);
523 TestIdentityFunctionPatching(kIdentityCodeWithMov
, override
, prefix
);
524 TestIdentityFunctionPatching(kIdentityCodeWithJump
, override
, prefix
);
526 prefix
= FunctionPrefixDetour
;
527 TestIdentityFunctionPatching(kIdentityCodeWithPrologue
, override
, prefix
);
528 TestIdentityFunctionPatching(kIdentityCodeWithPushPop
, override
, prefix
);
529 TestIdentityFunctionPatching(kIdentityCodeWithMov
, override
, prefix
);
530 TestIdentityFunctionPatching(kIdentityCodeWithJump
, override
, prefix
);
534 static void TestIdentityFunctionMultiplePatching(
536 TestOverrideFunction override
,
537 FunctionPrefixKind prefix_kind
= FunctionPrefixNone
) {
538 uptr identity_address
;
539 LoadActiveCode(code
, &identity_address
, prefix_kind
);
541 // Patch the function.
542 uptr real_identity_address
= 0;
543 bool success
= override(identity_address
,
544 (uptr
)&InterceptorFunction
,
545 &real_identity_address
);
546 EXPECT_TRUE(success
);
547 EXPECT_NE(0U, real_identity_address
);
549 // Re-patching the function should not work.
550 success
= override(identity_address
,
551 (uptr
)&InterceptorFunction
,
552 &real_identity_address
);
553 EXPECT_FALSE(success
);
555 TestOnlyReleaseTrampolineRegions();
558 TEST(Interception
, OverrideFunctionMultiplePatchingIsFailing
) {
559 #if !SANITIZER_WINDOWS64
560 TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue
,
561 OverrideFunctionWithDetour
,
562 FunctionPrefixDetour
);
565 TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov
,
566 OverrideFunctionWithHotPatch
,
567 FunctionPrefixHotPatch
);
569 TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop
,
570 OverrideFunctionWithTrampoline
,
571 FunctionPrefixPadding
);
574 TEST(Interception
, OverrideFunctionTwice
) {
575 uptr identity_address1
;
576 LoadActiveCode(kIdentityTwice
, &identity_address1
);
577 uptr identity_address2
= identity_address1
+ kIdentityTwiceOffset
;
578 IdentityFunction identity1
= (IdentityFunction
)identity_address1
;
579 IdentityFunction identity2
= (IdentityFunction
)identity_address2
;
581 // Patch the two functions.
582 uptr real_identity_address
= 0;
583 EXPECT_TRUE(OverrideFunction(identity_address1
,
584 (uptr
)&InterceptorFunction
,
585 &real_identity_address
));
586 EXPECT_TRUE(OverrideFunction(identity_address2
,
587 (uptr
)&InterceptorFunction
,
588 &real_identity_address
));
589 IdentityFunction real_identity
= (IdentityFunction
)real_identity_address
;
590 InterceptedRealFunction
= real_identity
;
592 // Calling the redirected function.
593 InterceptorFunctionCalled
= 0;
594 EXPECT_EQ(42, identity1(42));
595 EXPECT_EQ(42, identity2(42));
596 EXPECT_EQ(2, InterceptorFunctionCalled
);
598 TestOnlyReleaseTrampolineRegions();
602 static bool TestFunctionPatching(
604 TestOverrideFunction override
,
605 FunctionPrefixKind prefix_kind
= FunctionPrefixNone
) {
607 LoadActiveCode(code
, &address
, prefix_kind
);
608 uptr unused_real_address
= 0;
609 bool result
= override(
610 address
, (uptr
)&InterceptorFunction
, &unused_real_address
);
612 TestOnlyReleaseTrampolineRegions();
616 TEST(Interception
, PatchableFunction
) {
617 TestOverrideFunction override
= OverrideFunction
;
618 // Test without function padding.
619 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1
, override
));
620 EXPECT_TRUE(TestFunctionPatching(kPatchableCode2
, override
));
621 #if SANITIZER_WINDOWS64
622 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3
, override
));
624 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3
, override
));
626 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4
, override
));
627 EXPECT_TRUE(TestFunctionPatching(kPatchableCode5
, override
));
628 #if SANITIZER_WINDOWS64
629 EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode
, override
));
632 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1
, override
));
633 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2
, override
));
634 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3
, override
));
635 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4
, override
));
636 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5
, override
));
637 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6
, override
));
640 #if !SANITIZER_WINDOWS64
641 TEST(Interception
, PatchableFunctionWithDetour
) {
642 TestOverrideFunction override
= OverrideFunctionWithDetour
;
643 // Without the prefix, no function can be detoured.
644 EXPECT_FALSE(TestFunctionPatching(kPatchableCode1
, override
));
645 EXPECT_FALSE(TestFunctionPatching(kPatchableCode2
, override
));
646 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3
, override
));
647 EXPECT_FALSE(TestFunctionPatching(kPatchableCode4
, override
));
648 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1
, override
));
649 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2
, override
));
650 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3
, override
));
651 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4
, override
));
652 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5
, override
));
653 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6
, override
));
655 // With the prefix, all functions can be detoured.
656 FunctionPrefixKind prefix
= FunctionPrefixDetour
;
657 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1
, override
, prefix
));
658 EXPECT_TRUE(TestFunctionPatching(kPatchableCode2
, override
, prefix
));
659 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3
, override
, prefix
));
660 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4
, override
, prefix
));
661 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode1
, override
, prefix
));
662 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2
, override
, prefix
));
663 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode3
, override
, prefix
));
664 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode4
, override
, prefix
));
665 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode5
, override
, prefix
));
666 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode6
, override
, prefix
));
668 #endif // !SANITIZER_WINDOWS64
670 TEST(Interception
, PatchableFunctionWithRedirectJump
) {
671 TestOverrideFunction override
= OverrideFunctionWithRedirectJump
;
672 EXPECT_FALSE(TestFunctionPatching(kPatchableCode1
, override
));
673 EXPECT_FALSE(TestFunctionPatching(kPatchableCode2
, override
));
674 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3
, override
));
675 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4
, override
));
676 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1
, override
));
677 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2
, override
));
678 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3
, override
));
679 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4
, override
));
680 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5
, override
));
681 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6
, override
));
684 TEST(Interception
, PatchableFunctionWithHotPatch
) {
685 TestOverrideFunction override
= OverrideFunctionWithHotPatch
;
686 FunctionPrefixKind prefix
= FunctionPrefixHotPatch
;
688 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1
, override
, prefix
));
689 EXPECT_FALSE(TestFunctionPatching(kPatchableCode2
, override
, prefix
));
690 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3
, override
, prefix
));
691 EXPECT_FALSE(TestFunctionPatching(kPatchableCode4
, override
, prefix
));
692 #if SANITIZER_WINDOWS64
693 EXPECT_TRUE(TestFunctionPatching(kPatchableCode6
, override
, prefix
));
694 EXPECT_TRUE(TestFunctionPatching(kPatchableCode7
, override
, prefix
));
695 EXPECT_TRUE(TestFunctionPatching(kPatchableCode8
, override
, prefix
));
697 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1
, override
, prefix
));
698 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2
, override
, prefix
));
699 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3
, override
, prefix
));
700 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4
, override
, prefix
));
701 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5
, override
, prefix
));
702 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6
, override
, prefix
));
705 TEST(Interception
, PatchableFunctionWithTrampoline
) {
706 TestOverrideFunction override
= OverrideFunctionWithTrampoline
;
707 FunctionPrefixKind prefix
= FunctionPrefixPadding
;
709 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1
, override
, prefix
));
710 EXPECT_TRUE(TestFunctionPatching(kPatchableCode2
, override
, prefix
));
711 #if SANITIZER_WINDOWS64
712 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3
, override
, prefix
));
713 EXPECT_TRUE(TestFunctionPatching(kPatchableCode9
, override
, prefix
));
714 EXPECT_TRUE(TestFunctionPatching(kPatchableCode10
, override
, prefix
));
715 EXPECT_TRUE(TestFunctionPatching(kPatchableCode11
, override
, prefix
));
716 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode7
, override
, prefix
));
717 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode8
, override
, prefix
));
718 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode9
, override
, prefix
));
720 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3
, override
, prefix
));
721 EXPECT_TRUE(TestFunctionPatching(kPatchableCode12
, override
, prefix
));
722 EXPECT_TRUE(TestFunctionPatching(kPatchableCode13
, override
, prefix
));
724 EXPECT_FALSE(TestFunctionPatching(kPatchableCode4
, override
, prefix
));
725 EXPECT_TRUE(TestFunctionPatching(kPatchableCode14
, override
, prefix
));
727 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1
, override
, prefix
));
728 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2
, override
, prefix
));
729 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3
, override
, prefix
));
730 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4
, override
, prefix
));
731 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5
, override
, prefix
));
732 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6
, override
, prefix
));
735 TEST(Interception
, UnsupportedInstructionWithTrampoline
) {
736 TestOverrideFunction override
= OverrideFunctionWithTrampoline
;
737 FunctionPrefixKind prefix
= FunctionPrefixPadding
;
739 static bool reportCalled
;
740 reportCalled
= false;
743 static void Report(const char *format
, ...) {
745 FAIL() << "Report called more times than expected";
748 "interception_win: unhandled instruction at %p: %02x %02x %02x %02x "
749 "%02x %02x %02x %02x\n",
752 va_start(args
, format
);
753 u8
*ptr
= va_arg(args
, u8
*);
754 for (int i
= 0; i
< 8; i
++) EXPECT_EQ(kUnsupportedCode1
[i
], ptr
[i
]);
756 for (int i
= 0; i
< 8; i
++) {
757 bytes
[i
] = va_arg(args
, int);
758 EXPECT_EQ(kUnsupportedCode1
[i
], bytes
[i
]);
764 SetErrorReportCallback(Local::Report
);
765 EXPECT_FALSE(TestFunctionPatching(kUnsupportedCode1
, override
, prefix
));
766 SetErrorReportCallback(nullptr);
769 ADD_FAILURE() << "Report not called";
772 TEST(Interception
, PatchableFunctionPadding
) {
773 TestOverrideFunction override
= OverrideFunction
;
774 FunctionPrefixKind prefix
= FunctionPrefixPadding
;
776 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1
, override
, prefix
));
777 EXPECT_TRUE(TestFunctionPatching(kPatchableCode2
, override
, prefix
));
778 #if SANITIZER_WINDOWS64
779 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3
, override
, prefix
));
781 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3
, override
, prefix
));
783 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4
, override
, prefix
));
785 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1
, override
, prefix
));
786 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2
, override
, prefix
));
787 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3
, override
, prefix
));
788 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4
, override
, prefix
));
789 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5
, override
, prefix
));
790 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6
, override
, prefix
));
793 TEST(Interception
, EmptyExportTable
) {
794 // We try to get a pointer to a function from an executable that doesn't
795 // export any symbol (empty export table).
796 uptr FunPtr
= InternalGetProcAddress((void *)GetModuleHandleA(0), "example");
797 EXPECT_EQ(0U, FunPtr
);
800 const struct InstructionSizeData
{
801 size_t size
; // hold instruction size or 0 for failure,
802 // e.g. on control instructions
804 size_t rel_offset
; // filled just for instructions with two operands
805 // and displacement length of four bytes.
810 { 0, {0x70, 0x71}, 0, "70 XX : jo XX (short conditional jump)"},
811 { 0, {0x71, 0x71}, 0, "71 XX : jno XX (short conditional jump)"},
812 { 0, {0x72, 0x71}, 0, "72 XX : jb XX (short conditional jump)"},
813 { 0, {0x73, 0x71}, 0, "73 XX : jae XX (short conditional jump)"},
814 { 0, {0x74, 0x71}, 0, "74 XX : je XX (short conditional jump)"},
815 { 0, {0x75, 0x71}, 0, "75 XX : jne XX (short conditional jump)"},
816 { 0, {0x76, 0x71}, 0, "76 XX : jbe XX (short conditional jump)"},
817 { 0, {0x77, 0x71}, 0, "77 XX : ja XX (short conditional jump)"},
818 { 0, {0x78, 0x71}, 0, "78 XX : js XX (short conditional jump)"},
819 { 0, {0x79, 0x71}, 0, "79 XX : jns XX (short conditional jump)"},
820 { 0, {0x7A, 0x71}, 0, "7A XX : jp XX (short conditional jump)"},
821 { 0, {0x7B, 0x71}, 0, "7B XX : jnp XX (short conditional jump)"},
822 { 0, {0x7C, 0x71}, 0, "7C XX : jl XX (short conditional jump)"},
823 { 0, {0x7D, 0x71}, 0, "7D XX : jge XX (short conditional jump)"},
824 { 0, {0x7E, 0x71}, 0, "7E XX : jle XX (short conditional jump)"},
825 { 0, {0x7F, 0x71}, 0, "7F XX : jg XX (short conditional jump)"},
826 { 0, {0xE8, 0x71, 0x72, 0x73, 0x74}, 0, "E8 XX XX XX XX : call <func>"},
827 { 0, {0xE9, 0x71, 0x72, 0x73, 0x74}, 0, "E9 XX XX XX XX : jmp <label>"},
828 { 0, {0xEB, 0x71}, 0, "EB XX : jmp XX (short jump)"},
829 { 0, {0xFF, 0x25, 0x72, 0x73, 0x74, 0x75}, 0, "FF 25 XX YY ZZ WW : jmp dword ptr ds:[WWZZYYXX]"},
830 { 1, {0x50}, 0, "50 : push eax / rax"},
831 { 1, {0x51}, 0, "51 : push ecx / rcx"},
832 { 1, {0x52}, 0, "52 : push edx / rdx"},
833 { 1, {0x53}, 0, "53 : push ebx / rbx"},
834 { 1, {0x54}, 0, "54 : push esp / rsp"},
835 { 1, {0x55}, 0, "55 : push ebp / rbp"},
836 { 1, {0x56}, 0, "56 : push esi / rsi"},
837 { 1, {0x57}, 0, "57 : push edi / rdi"},
838 { 1, {0x5D}, 0, "5D : pop ebp / rbp"},
839 { 1, {0x90}, 0, "90 : nop"},
840 { 1, {0xC3}, 0, "C3 : ret (for small/empty function interception"},
841 { 1, {0xCC}, 0, "CC : int 3 i.e. registering weak functions)"},
842 { 2, {0x33, 0xC0}, 0, "33 C0 : xor eax, eax"},
843 { 2, {0x33, 0xC9}, 0, "33 C9 : xor ecx, ecx"},
844 { 2, {0x33, 0xD2}, 0, "33 D2 : xor edx, edx"},
845 { 2, {0x6A, 0x71}, 0, "6A XX : push XX"},
846 { 2, {0x84, 0xC9}, 0, "84 C9 : test cl,cl"},
847 { 2, {0x84, 0xD2}, 0, "84 D2 : test dl,dl"},
848 { 2, {0x84, 0xDB}, 0, "84 DB : test bl,bl"},
849 { 2, {0x89, 0xc8}, 0, "89 C8 : mov eax, ecx"},
850 { 2, {0x89, 0xE5}, 0, "89 E5 : mov ebp, esp"},
851 { 2, {0x8A, 0x01}, 0, "8A 01 : mov al, byte ptr [ecx]"},
852 { 2, {0x8B, 0xC1}, 0, "8B C1 : mov eax, ecx"},
853 { 2, {0x8B, 0xEC}, 0, "8B EC : mov ebp, esp"},
854 { 2, {0x8B, 0xFF}, 0, "8B FF : mov edi, edi"},
855 { 3, {0xc2, 0x71, 0x72}, 0, "C2 XX XX : ret XX (needed for registering weak functions)"},
856 { 5, {0x68, 0x71, 0x72, 0x73, 0x74}, 0, "68 XX XX XX XX : push imm32"},
857 { 5, {0xb8, 0x71, 0x72, 0x73, 0x74}, 0, "b8 XX XX XX XX : mov eax, XX XX XX XX"},
858 { 5, {0xB9, 0x71, 0x72, 0x73, 0x74}, 0, "b9 XX XX XX XX : mov ecx, XX XX XX XX"},
859 #if SANITIZER_WINDOWS_x64
861 { 2, {0x40, 0x50}, 0, "40 50 : push rax"},
862 { 2, {0x40, 0x51}, 0, "40 51 : push rcx"},
863 { 2, {0x40, 0x52}, 0, "40 52 : push rdx"},
864 { 2, {0x40, 0x53}, 0, "40 53 : push rbx"},
865 { 2, {0x40, 0x54}, 0, "40 54 : push rsp"},
866 { 2, {0x40, 0x55}, 0, "40 55 : push rbp"},
867 { 2, {0x40, 0x56}, 0, "40 56 : push rsi"},
868 { 2, {0x40, 0x57}, 0, "40 57 : push rdi"},
869 { 2, {0x41, 0x54}, 0, "41 54 : push r12"},
870 { 2, {0x41, 0x55}, 0, "41 55 : push r13"},
871 { 2, {0x41, 0x56}, 0, "41 56 : push r14"},
872 { 2, {0x41, 0x57}, 0, "41 57 : push r15"},
873 { 2, {0x66, 0x90}, 0, "66 90 : Two-byte NOP"},
874 { 2, {0x84, 0xc0}, 0, "84 c0 : test al, al"},
875 { 2, {0x8a, 0x01}, 0, "8a 01 : mov al, byte ptr [rcx]"},
876 { 3, {0x0f, 0xb6, 0xc2}, 0, "0f b6 c2 : movzx eax, dl"},
877 { 3, {0x0f, 0xb6, 0xd2}, 0, "0f b6 d2 : movzx edx, dl"},
878 { 3, {0x0f, 0xb7, 0x10}, 0, "0f b7 10 : movzx edx, WORD PTR [rax]"},
879 { 3, {0x41, 0x8b, 0xc0}, 0, "41 8b c0 : mov eax, r8d"},
880 { 3, {0x41, 0x8b, 0xc1}, 0, "41 8b c1 : mov eax, r9d"},
881 { 3, {0x41, 0x8b, 0xc2}, 0, "41 8b c2 : mov eax, r10d"},
882 { 3, {0x41, 0x8b, 0xc3}, 0, "41 8b c3 : mov eax, r11d"},
883 { 3, {0x41, 0x8b, 0xc4}, 0, "41 8b c4 : mov eax, r12d"},
884 { 3, {0x45, 0x33, 0xc0}, 0, "45 33 c0 : xor r8d, r8d"},
885 { 3, {0x45, 0x33, 0xc9}, 0, "45 33 c9 : xor r9d, r9d"},
886 { 3, {0x45, 0x33, 0xdb}, 0, "45 33 db : xor r11d, r11d"},
887 { 3, {0x48, 0x2b, 0xca}, 0, "48 2b ca : sub rcx, rdx"},
888 { 3, {0x48, 0x2b, 0xd1}, 0, "48 2b d1 : sub rdx, rcx"},
889 { 3, {0x48, 0x3b, 0xca}, 0, "48 3b ca : cmp rcx, rdx"},
890 { 3, {0x48, 0x85, 0xc0}, 0, "48 85 c0 : test rax, rax"},
891 { 3, {0x48, 0x85, 0xc9}, 0, "48 85 c9 : test rcx, rcx"},
892 { 3, {0x48, 0x85, 0xd2}, 0, "48 85 d2 : test rdx, rdx"},
893 { 3, {0x48, 0x85, 0xdb}, 0, "48 85 db : test rbx, rbx"},
894 { 3, {0x48, 0x85, 0xe4}, 0, "48 85 e4 : test rsp, rsp"},
895 { 3, {0x48, 0x85, 0xed}, 0, "48 85 ed : test rbp, rbp"},
896 { 3, {0x48, 0x89, 0xe5}, 0, "48 89 e5 : mov rbp, rsp"},
897 { 3, {0x48, 0x8b, 0xc1}, 0, "48 8b c1 : mov rax, rcx"},
898 { 3, {0x48, 0x8b, 0xc4}, 0, "48 8b c4 : mov rax, rsp"},
899 { 3, {0x48, 0x8b, 0xd1}, 0, "48 8b d1 : mov rdx, rcx"},
900 { 3, {0x48, 0xf7, 0xd9}, 0, "48 f7 d9 : neg rcx"},
901 { 3, {0x48, 0xff, 0xc0}, 0, "48 ff c0 : inc rax"},
902 { 3, {0x48, 0xff, 0xc1}, 0, "48 ff c1 : inc rcx"},
903 { 3, {0x48, 0xff, 0xc2}, 0, "48 ff c2 : inc rdx"},
904 { 3, {0x48, 0xff, 0xc3}, 0, "48 ff c3 : inc rbx"},
905 { 3, {0x48, 0xff, 0xc6}, 0, "48 ff c6 : inc rsi"},
906 { 3, {0x48, 0xff, 0xc7}, 0, "48 ff c7 : inc rdi"},
907 { 3, {0x49, 0xff, 0xc0}, 0, "49 ff c0 : inc r8"},
908 { 3, {0x49, 0xff, 0xc1}, 0, "49 ff c1 : inc r9"},
909 { 3, {0x49, 0xff, 0xc2}, 0, "49 ff c2 : inc r10"},
910 { 3, {0x49, 0xff, 0xc3}, 0, "49 ff c3 : inc r11"},
911 { 3, {0x49, 0xff, 0xc4}, 0, "49 ff c4 : inc r12"},
912 { 3, {0x49, 0xff, 0xc5}, 0, "49 ff c5 : inc r13"},
913 { 3, {0x49, 0xff, 0xc6}, 0, "49 ff c6 : inc r14"},
914 { 3, {0x49, 0xff, 0xc7}, 0, "49 ff c7 : inc r15"},
915 { 3, {0x4c, 0x8b, 0xc1}, 0, "4c 8b c1 : mov r8, rcx"},
916 { 3, {0x4c, 0x8b, 0xc9}, 0, "4c 8b c9 : mov r9, rcx"},
917 { 3, {0x4c, 0x8b, 0xd1}, 0, "4c 8b d1 : mov r10, rcx"},
918 { 3, {0x4c, 0x8b, 0xd2}, 0, "4c 8b d2 : mov r10, rdx"},
919 { 3, {0x4c, 0x8b, 0xd9}, 0, "4c 8b d9 : mov r11, rcx"},
920 { 3, {0x4c, 0x8b, 0xdc}, 0, "4c 8b dc : mov r11, rsp"},
921 { 3, {0x4d, 0x0b, 0xc0}, 0, "4d 0b c0 : or r8, r8"},
922 { 3, {0x4d, 0x85, 0xc0}, 0, "4d 85 c0 : test r8, r8"},
923 { 3, {0x4d, 0x85, 0xc9}, 0, "4d 85 c9 : test r9, r9"},
924 { 3, {0x4d, 0x85, 0xd2}, 0, "4d 85 d2 : test r10, r10"},
925 { 3, {0x4d, 0x85, 0xdb}, 0, "4d 85 db : test r11, r11"},
926 { 3, {0x4d, 0x85, 0xe4}, 0, "4d 85 e4 : test r12, r12"},
927 { 3, {0x4d, 0x85, 0xed}, 0, "4d 85 ed : test r13, r13"},
928 { 3, {0x4d, 0x85, 0xf6}, 0, "4d 85 f6 : test r14, r14"},
929 { 3, {0x4d, 0x85, 0xff}, 0, "4d 85 ff : test r15, r15"},
930 { 4, {0x44, 0x0f, 0xb6, 0x1a}, 0, "44 0f b6 1a : movzx r11d, BYTE PTR [rdx]"},
931 { 4, {0x44, 0x8d, 0x42, 0x73}, 0, "44 8d 42 XX : lea r8d , [rdx + XX]"},
932 { 4, {0x48, 0x83, 0xec, 0x73}, 0, "48 83 ec XX : sub rsp, XX"},
933 { 4, {0x48, 0x89, 0x58, 0x73}, 0, "48 89 58 XX : mov QWORD PTR[rax + XX], rbx"},
934 { 4, {0x49, 0x83, 0xf8, 0x73}, 0, "49 83 f8 XX : cmp r8, XX"},
935 { 4, {0x80, 0x78, 0x72, 0x73}, 0, "80 78 YY XX : cmp BYTE PTR [rax+YY], XX"},
936 { 4, {0x80, 0x79, 0x72, 0x73}, 0, "80 79 YY XX : cmp BYTE ptr [rcx+YY], XX"},
937 { 4, {0x80, 0x7A, 0x72, 0x73}, 0, "80 7A YY XX : cmp BYTE PTR [rdx+YY], XX"},
938 { 4, {0x80, 0x7B, 0x72, 0x73}, 0, "80 7B YY XX : cmp BYTE PTR [rbx+YY], XX"},
939 { 4, {0x80, 0x7D, 0x72, 0x73}, 0, "80 7D YY XX : cmp BYTE PTR [rbp+YY], XX"},
940 { 4, {0x80, 0x7E, 0x72, 0x73}, 0, "80 7E YY XX : cmp BYTE PTR [rsi+YY], XX"},
941 { 4, {0x89, 0x54, 0x24, 0x73}, 0, "89 54 24 XX : mov DWORD PTR[rsp + XX], edx"},
942 { 5, {0x44, 0x89, 0x44, 0x24, 0x74}, 0, "44 89 44 24 XX : mov DWORD PTR [rsp + XX], r8d"},
943 { 5, {0x44, 0x89, 0x4c, 0x24, 0x74}, 0, "44 89 4c 24 XX : mov DWORD PTR [rsp + XX], r9d"},
944 { 5, {0x48, 0x89, 0x4C, 0x24, 0x74}, 0, "48 89 4C 24 XX : mov QWORD PTR [rsp + XX], rcx"},
945 { 5, {0x48, 0x89, 0x54, 0x24, 0x74}, 0, "48 89 54 24 XX : mov QWORD PTR [rsp + XX], rdx"},
946 { 5, {0x48, 0x89, 0x5c, 0x24, 0x74}, 0, "48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx"},
947 { 5, {0x48, 0x89, 0x6c, 0x24, 0x74}, 0, "48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp"},
948 { 5, {0x48, 0x89, 0x74, 0x24, 0x74}, 0, "48 89 74 24 XX : mov QWORD PTR [rsp + XX], rsi"},
949 { 5, {0x48, 0x89, 0x7c, 0x24, 0x74}, 0, "48 89 7c 24 XX : mov QWORD PTR [rsp + XX], rdi"},
950 { 5, {0x48, 0x8b, 0x44, 0x24, 0x74}, 0, "48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX]"},
951 { 5, {0x48, 0x8d, 0x6c, 0x24, 0x74}, 0, "48 8d 6c 24 XX : lea rbp, [rsp + XX]"},
952 { 5, {0x4c, 0x89, 0x44, 0x24, 0x74}, 0, "4c 89 44 24 XX : mov QWORD PTR [rsp + XX], r8"},
953 { 5, {0x4c, 0x89, 0x4c, 0x24, 0x74}, 0, "4c 89 4c 24 XX : mov QWORD PTR [rsp + XX], r9"},
954 { 5, {0x83, 0x44, 0x72, 0x73, 0x74}, 0, "83 44 72 XX YY : add DWORD PTR [rdx+rsi*2+XX],YY"},
955 { 5, {0x83, 0x64, 0x24, 0x73, 0x74}, 0, "83 64 24 XX YY : and DWORD PTR [rsp+XX], YY"},
956 { 6, {0x48, 0x83, 0x64, 0x24, 0x74, 0x75}, 0, "48 83 64 24 XX YY : and QWORD PTR [rsp + XX], YY"},
957 { 6, {0x66, 0x81, 0x78, 0x73, 0x74, 0x75}, 0, "66 81 78 XX YY YY : cmp WORD PTR [rax+XX], YY YY"},
958 { 6, {0x66, 0x81, 0x79, 0x73, 0x74, 0x75}, 0, "66 81 79 XX YY YY : cmp WORD PTR [rcx+XX], YY YY"},
959 { 6, {0x66, 0x81, 0x7a, 0x73, 0x74, 0x75}, 0, "66 81 7a XX YY YY : cmp WORD PTR [rdx+XX], YY YY"},
960 { 6, {0x66, 0x81, 0x7b, 0x73, 0x74, 0x75}, 0, "66 81 7b XX YY YY : cmp WORD PTR [rbx+XX], YY YY"},
961 { 6, {0x66, 0x81, 0x7e, 0x73, 0x74, 0x75}, 0, "66 81 7e XX YY YY : cmp WORD PTR [rsi+XX], YY YY"},
962 { 6, {0x66, 0x81, 0x7f, 0x73, 0x74, 0x75}, 0, "66 81 7f XX YY YY : cmp WORD PTR [rdi+XX], YY YY"},
963 { 6, {0x8A, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8A 05 XX XX XX XX : mov al, byte ptr [XX XX XX XX]"},
964 { 6, {0x8B, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]"},
965 { 6, {0xF2, 0x0f, 0x11, 0x44, 0x24, 0x75}, 0, "f2 0f 11 44 24 XX : movsd QWORD PTR [rsp + XX], xmm0"},
966 { 6, {0xF2, 0x0f, 0x11, 0x4c, 0x24, 0x75}, 0, "f2 0f 11 4c 24 XX : movsd QWORD PTR [rsp + XX], xmm1"},
967 { 6, {0xF2, 0x0f, 0x11, 0x54, 0x24, 0x75}, 0, "f2 0f 11 54 24 XX : movsd QWORD PTR [rsp + XX], xmm2"},
968 { 6, {0xF2, 0x0f, 0x11, 0x5c, 0x24, 0x75}, 0, "f2 0f 11 5c 24 XX : movsd QWORD PTR [rsp + XX], xmm3"},
969 { 6, {0xF2, 0x0f, 0x11, 0x64, 0x24, 0x75}, 0, "f2 0f 11 64 24 XX : movsd QWORD PTR [rsp + XX], xmm4"},
970 { 7, {0x48, 0x81, 0xec, 0x73, 0x74, 0x75, 0x76}, 0, "48 81 EC XX XX XX XX : sub rsp, XXXXXXXX"},
971 { 7, {0x48, 0x89, 0x0d, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 0d XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rcx"},
972 { 7, {0x48, 0x89, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 15 XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rdx"},
973 { 7, {0x48, 0x8b, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8b 05 XX XX XX XX : mov rax, QWORD PTR [rip + XXXXXXXX]"},
974 { 7, {0x48, 0x8d, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8d 05 XX XX XX XX : lea rax, QWORD PTR [rip + XXXXXXXX]"},
975 { 7, {0x48, 0xff, 0x25, 0x73, 0x74, 0x75, 0x76}, 3, "48 ff 25 XX XX XX XX : rex.W jmp QWORD PTR [rip + XXXXXXXX]"},
976 { 7, {0x4C, 0x8D, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "4c 8d 15 XX XX XX XX : lea r10, [rip + XX]"},
977 { 7, {0x81, 0x78, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 78 YY XX XX XX XX : cmp DWORD PTR [rax+YY], XX XX XX XX"},
978 { 7, {0x81, 0x79, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 79 YY XX XX XX XX : cmp dword ptr [rcx+YY], XX XX XX XX"},
979 { 7, {0x81, 0x7A, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 7A YY XX XX XX XX : cmp DWORD PTR [rdx+YY], XX XX XX XX"},
980 { 7, {0x81, 0x7B, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 7B YY XX XX XX XX : cmp DWORD PTR [rbx+YY], XX XX XX XX"},
981 { 7, {0x81, 0x7D, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 7D YY XX XX XX XX : cmp DWORD PTR [rbp+YY], XX XX XX XX"},
982 { 7, {0x81, 0x7E, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "81 7E YY XX XX XX XX : cmp DWORD PTR [rsi+YY], XX XX XX XX"},
983 { 8, {0x41, 0x81, 0x78, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 78 XX YY YY YY YY : cmp DWORD PTR [r8+YY], XX XX XX XX"},
984 { 8, {0x41, 0x81, 0x79, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 79 XX YY YY YY YY : cmp DWORD PTR [r9+YY], XX XX XX XX"},
985 { 8, {0x41, 0x81, 0x7a, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7a XX YY YY YY YY : cmp DWORD PTR [r10+YY], XX XX XX XX"},
986 { 8, {0x41, 0x81, 0x7b, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7b XX YY YY YY YY : cmp DWORD PTR [r11+YY], XX XX XX XX"},
987 { 8, {0x41, 0x81, 0x7d, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7d XX YY YY YY YY : cmp DWORD PTR [r13+YY], XX XX XX XX"},
988 { 8, {0x41, 0x81, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7e XX YY YY YY YY : cmp DWORD PTR [r14+YY], XX XX XX XX"},
989 { 8, {0x41, 0x81, 0x7f, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "41 81 7f YY XX XX XX XX : cmp DWORD PTR [r15+YY], XX XX XX XX"},
990 { 8, {0x81, 0x7c, 0x24, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "81 7c 24 YY XX XX XX XX : cmp DWORD PTR [rsp+YY], XX XX XX XX"},
991 { 8, {0xc7, 0x44, 0x24, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "C7 44 24 XX YY YY YY YY : mov dword ptr [rsp + XX], YYYYYYYY"},
992 { 9, {0xA1, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78}, 0, "A1 XX XX XX XX XX XX XX XX : movabs eax, dword ptr ds:[XXXXXXXX]"},
995 { 3, {0x8B, 0x45, 0x72}, 0, "8B 45 XX : mov eax, dword ptr [ebp + XX]"},
996 { 3, {0x8B, 0x5D, 0x72}, 0, "8B 5D XX : mov ebx, dword ptr [ebp + XX]"},
997 { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov esi, dword ptr [ebp + XX]"},
998 { 3, {0x8B, 0x7D, 0x72}, 0, "8B 7D XX : mov edi, dword ptr [ebp + XX]"},
999 { 3, {0xFF, 0x75, 0x72}, 0, "FF 75 XX : push dword ptr [ebp + XX]"},
1000 { 4, {0x83, 0x7D, 0x72, 0x73}, 0, "83 7D XX YY : cmp dword ptr [ebp + XX], YY"},
1001 { 4, {0x8A, 0x44, 0x24, 0x73}, 0, "8A 44 24 XX : mov eal, dword ptr [esp + XX]"},
1002 { 4, {0x8B, 0x44, 0x24, 0x73}, 0, "8B 44 24 XX : mov eax, dword ptr [esp + XX]"},
1003 { 4, {0x8B, 0x4C, 0x24, 0x73}, 0, "8B 4C 24 XX : mov ecx, dword ptr [esp + XX]"},
1004 { 4, {0x8B, 0x54, 0x24, 0x73}, 0, "8B 54 24 XX : mov edx, dword ptr [esp + XX]"},
1005 { 4, {0x8B, 0x5C, 0x24, 0x73}, 0, "8B 5C 24 XX : mov ebx, dword ptr [esp + XX]"},
1006 { 4, {0x8B, 0x6C, 0x24, 0x73}, 0, "8B 6C 24 XX : mov ebp, dword ptr [esp + XX]"},
1007 { 4, {0x8B, 0x74, 0x24, 0x73}, 0, "8B 74 24 XX : mov esi, dword ptr [esp + XX]"},
1008 { 4, {0x8B, 0x7C, 0x24, 0x73}, 0, "8B 7C 24 XX : mov edi, dword ptr [esp + XX]"},
1009 { 5, {0x0F, 0xB6, 0x44, 0x24, 0x74}, 0, "0F B6 44 24 XX : movzx eax, byte ptr [esp + XX]"},
1010 { 5, {0xA1, 0x71, 0x72, 0x73, 0x74}, 0, "A1 XX XX XX XX : mov eax, dword ptr ds:[XXXXXXXX]"},
1011 { 6, {0xF7, 0xC1, 0x72, 0x73, 0x74, 0x75}, 0, "F7 C1 XX YY ZZ WW : test ecx, WWZZYYXX"},
1012 { 7, {0x83, 0x3D, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "83 3D XX YY ZZ WW TT : cmp TT, WWZZYYXX"},
1017 std::string
dumpInstruction(unsigned arrayIndex
,
1018 const InstructionSizeData
&data
) {
1019 std::stringstream ret
;
1020 ret
<< " with arrayIndex=" << arrayIndex
<< " {";
1021 for (size_t i
= 0; i
< data
.size
; i
++) {
1024 ret
<< "0x" << std::setfill('0') << std::setw(2) << std::right
<< std::hex
1025 << (int)data
.instr
[i
];
1027 ret
<< "} " << data
.comment
;
1031 TEST(Interception
, GetInstructionSize
) {
1032 for (unsigned i
= 0; i
< sizeof(data
) / sizeof(*data
); i
++) {
1033 size_t rel_offset
= ~0L;
1034 size_t size
= __interception::TestOnlyGetInstructionSize(
1035 (uptr
)data
[i
].instr
, &rel_offset
);
1036 EXPECT_EQ(data
[i
].size
, size
) << dumpInstruction(i
, data
[i
]);
1037 EXPECT_EQ(data
[i
].rel_offset
, rel_offset
) << dumpInstruction(i
, data
[i
]);
1041 } // namespace __interception
1043 # endif // !SANITIZER_WINDOWS_ARM64
1044 #endif // SANITIZER_WINDOWS
1045 #endif // #if !SANITIZER_DEBUG