1//===-- interception_win_test.cpp -----------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10// Tests for interception_win.h.
11//
12//===----------------------------------------------------------------------===//
13#include "interception/interception.h"
14
15#include "gtest/gtest.h"
16
17// Too slow for debug build
18// Disabling for ARM64 since testcases are x86/x64 assembly.
19#if !SANITIZER_DEBUG
20#if SANITIZER_WINDOWS
21# if !SANITIZER_WINDOWS_ARM64
22
23# include <stdarg.h>
24
25# define WIN32_LEAN_AND_MEAN
26# include <windows.h>
27
28namespace __interception {
29namespace {
30
31enum FunctionPrefixKind {
32 FunctionPrefixNone,
33 FunctionPrefixPadding,
34 FunctionPrefixHotPatch,
35 FunctionPrefixDetour,
36};
37
38typedef bool (*TestOverrideFunction)(uptr, uptr, uptr*);
39typedef int (*IdentityFunction)(int);
40
41#if SANITIZER_WINDOWS64
42
43const u8 kIdentityCodeWithPrologue[] = {
44 0x55, // push rbp
45 0x48, 0x89, 0xE5, // mov rbp,rsp
46 0x8B, 0xC1, // mov eax,ecx
47 0x5D, // pop rbp
48 0xC3, // ret
49};
50
51const u8 kIdentityCodeWithPushPop[] = {
52 0x55, // push rbp
53 0x48, 0x89, 0xE5, // mov rbp,rsp
54 0x53, // push rbx
55 0x50, // push rax
56 0x58, // pop rax
57 0x8B, 0xC1, // mov rax,rcx
58 0x5B, // pop rbx
59 0x5D, // pop rbp
60 0xC3, // ret
61};
62
63const u8 kIdentityTwiceOffset = 16;
64const u8 kIdentityTwice[] = {
65 0x55, // push rbp
66 0x48, 0x89, 0xE5, // mov rbp,rsp
67 0x8B, 0xC1, // mov eax,ecx
68 0x5D, // pop rbp
69 0xC3, // ret
70 0x90, 0x90, 0x90, 0x90,
71 0x90, 0x90, 0x90, 0x90,
72 0x55, // push rbp
73 0x48, 0x89, 0xE5, // mov rbp,rsp
74 0x8B, 0xC1, // mov eax,ecx
75 0x5D, // pop rbp
76 0xC3, // ret
77};
78
79const u8 kIdentityCodeWithMov[] = {
80 0x89, 0xC8, // mov eax, ecx
81 0xC3, // ret
82};
83
84const u8 kIdentityCodeWithJump[] = {
85 0xE9, 0x04, 0x00, 0x00,
86 0x00, // jmp + 4
87 0xCC, 0xCC, 0xCC, 0xCC,
88 0x89, 0xC8, // mov eax, ecx
89 0xC3, // ret
90};
91
92const u8 kIdentityCodeWithJumpBackwards[] = {
93 0x89, 0xC8, // mov eax, ecx
94 0xC3, // ret
95 0xE9, 0xF8, 0xFF, 0xFF,
96 0xFF, // jmp - 8
97 0xCC, 0xCC, 0xCC, 0xCC,
98};
99const u8 kIdentityCodeWithJumpBackwardsOffset = 3;
100
101# else
102
103const u8 kIdentityCodeWithPrologue[] = {
104 0x55, // push ebp
105 0x8B, 0xEC, // mov ebp,esp
106 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
107 0x5D, // pop ebp
108 0xC3, // ret
109};
110
111const u8 kIdentityCodeWithPushPop[] = {
112 0x55, // push ebp
113 0x8B, 0xEC, // mov ebp,esp
114 0x53, // push ebx
115 0x50, // push eax
116 0x58, // pop eax
117 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
118 0x5B, // pop ebx
119 0x5D, // pop ebp
120 0xC3, // ret
121};
122
123const u8 kIdentityTwiceOffset = 8;
124const u8 kIdentityTwice[] = {
125 0x55, // push ebp
126 0x8B, 0xEC, // mov ebp,esp
127 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
128 0x5D, // pop ebp
129 0xC3, // ret
130 0x55, // push ebp
131 0x8B, 0xEC, // mov ebp,esp
132 0x8B, 0x45, 0x08, // mov eax,dword ptr [ebp + 8]
133 0x5D, // pop ebp
134 0xC3, // ret
135};
136
137const u8 kIdentityCodeWithMov[] = {
138 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4]
139 0xC3, // ret
140};
141
142const u8 kIdentityCodeWithJump[] = {
143 0xE9, 0x04, 0x00, 0x00,
144 0x00, // jmp + 4
145 0xCC, 0xCC, 0xCC, 0xCC,
146 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4]
147 0xC3, // ret
148};
149
150const u8 kIdentityCodeWithJumpBackwards[] = {
151 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4]
152 0xC3, // ret
153 0xE9, 0xF6, 0xFF, 0xFF,
154 0xFF, // jmp - 10
155 0xCC, 0xCC, 0xCC, 0xCC,
156};
157const u8 kIdentityCodeWithJumpBackwardsOffset = 5;
158
159# endif
160
161const u8 kPatchableCode1[] = {
162 0xB8, 0x4B, 0x00, 0x00, 0x00, // mov eax,4B
163 0x33, 0xC9, // xor ecx,ecx
164 0xC3, // ret
165};
166
167const u8 kPatchableCode2[] = {
168 0x55, // push ebp
169 0x8B, 0xEC, // mov ebp,esp
170 0x33, 0xC0, // xor eax,eax
171 0x5D, // pop ebp
172 0xC3, // ret
173};
174
175const u8 kPatchableCode3[] = {
176 0x55, // push ebp
177 0x8B, 0xEC, // mov ebp,esp
178 0x6A, 0x00, // push 0
179 0xE8, 0x3D, 0xFF, 0xFF, 0xFF, // call <func>
180};
181
182const u8 kPatchableCode4[] = {
183 0xE9, 0xCC, 0xCC, 0xCC, 0xCC, // jmp <label>
184 0x90, 0x90, 0x90, 0x90,
185};
186
187const u8 kPatchableCode5[] = {
188 0x55, // push ebp
189 0x8b, 0xec, // mov ebp,esp
190 0x8d, 0xa4, 0x24, 0x30, 0xfd, 0xff, 0xff, // lea esp,[esp-2D0h]
191 0x54, // push esp
192};
193
194#if SANITIZER_WINDOWS64
195u8 kLoadGlobalCode[] = {
196 0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov eax [rip + global]
197 0xC3, // ret
198};
199#endif
200
201const u8 kUnpatchableCode1[] = {
202 0xC3, // ret
203};
204
205const u8 kUnpatchableCode2[] = {
206 0x33, 0xC9, // xor ecx,ecx
207 0xC3, // ret
208};
209
210const u8 kUnpatchableCode3[] = {
211 0x75, 0xCC, // jne <label>
212 0x33, 0xC9, // xor ecx,ecx
213 0xC3, // ret
214};
215
216const u8 kUnpatchableCode4[] = {
217 0x74, 0xCC, // jne <label>
218 0x33, 0xC9, // xor ecx,ecx
219 0xC3, // ret
220};
221
222const u8 kUnpatchableCode5[] = {
223 0xEB, 0x02, // jmp <label>
224 0x33, 0xC9, // xor ecx,ecx
225 0xC3, // ret
226};
227
228const u8 kUnpatchableCode6[] = {
229 0xE8, 0xCC, 0xCC, 0xCC, 0xCC, // call <func>
230 0x90, 0x90, 0x90, 0x90,
231};
232
233const u8 kUnpatchableCode7[] = {
234 0x33, 0xc0, // xor eax,eax
235 0x48, 0x85, 0xd2, // test rdx,rdx
236 0x74, 0x10, // je +16 (unpatchable)
237};
238
239const u8 kUnpatchableCode8[] = {
240 0x48, 0x8b, 0xc1, // mov rax,rcx
241 0x0f, 0xb7, 0x10, // movzx edx,word ptr [rax]
242 0x48, 0x83, 0xc0, 0x02, // add rax,2
243 0x66, 0x85, 0xd2, // test dx,dx
244 0x75, 0xf4, // jne -12 (unpatchable)
245};
246
247const u8 kUnpatchableCode9[] = {
248 0x4c, 0x8b, 0xc1, // mov r8,rcx
249 0x8a, 0x01, // mov al,byte ptr [rcx]
250 0x48, 0xff, 0xc1, // inc rcx
251 0x84, 0xc0, // test al,al
252 0x75, 0xf7, // jne -9 (unpatchable)
253};
254
255const u8 kPatchableCode6[] = {
256 0x48, 0x89, 0x54, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], rdx
257 0x33, 0xC9, // xor ecx,ecx
258 0xC3, // ret
259};
260
261const u8 kPatchableCode7[] = {
262 0x4c, 0x89, 0x4c, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], r9
263 0x33, 0xC9, // xor ecx,ecx
264 0xC3, // ret
265};
266
267const u8 kPatchableCode8[] = {
268 0x4c, 0x89, 0x44, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], r8
269 0x33, 0xC9, // xor ecx,ecx
270 0xC3, // ret
271};
272
273const u8 kPatchableCode9[] = {
274 0x8a, 0x01, // al,byte ptr [rcx]
275 0x45, 0x33, 0xc0, // xor r8d,r8d
276 0x84, 0xc0, // test al,al
277};
278
279const u8 kPatchableCode10[] = {
280 0x45, 0x33, 0xc0, // xor r8d,r8d
281 0x41, 0x8b, 0xc0, // mov eax,r8d
282 0x48, 0x85, 0xd2, // test rdx,rdx
283};
284
285const u8 kPatchableCode11[] = {
286 0x48, 0x83, 0xec, 0x38, // sub rsp,38h
287 0x83, 0x64, 0x24, 0x28, 0x00, // and dword ptr [rsp+28h],0
288};
289
290const u8 kPatchableCode12[] = {
291 0x55, // push ebp
292 0x53, // push ebx
293 0x57, // push edi
294 0x56, // push esi
295 0x8b, 0x6c, 0x24, 0x18, // mov ebp,dword ptr[esp+18h]
296};
297
298const u8 kPatchableCode13[] = {
299 0x55, // push ebp
300 0x53, // push ebx
301 0x57, // push edi
302 0x56, // push esi
303 0x8b, 0x5c, 0x24, 0x14, // mov ebx,dword ptr[esp+14h]
304};
305
306const u8 kPatchableCode14[] = {
307 0x55, // push ebp
308 0x89, 0xe5, // mov ebp,esp
309 0x53, // push ebx
310 0x57, // push edi
311 0x56, // push esi
312};
313
314const u8 kUnsupportedCode1[] = {
315 0x0f, 0x0b, // ud2
316 0x0f, 0x0b, // ud2
317 0x0f, 0x0b, // ud2
318 0x0f, 0x0b, // ud2
319};
320
321// A buffer holding the dynamically generated code under test.
322u8* ActiveCode;
323const size_t ActiveCodeLength = 4096;
324
325int InterceptorFunction(int x);
326
327/// Allocate code memory more than 2GB away from Base.
328u8 *AllocateCode2GBAway(u8 *Base) {
329 // Find a 64K aligned location after Base plus 2GB.
330 size_t TwoGB = 0x80000000;
331 size_t AllocGranularity = 0x10000;
332 Base = (u8 *)((((uptr)Base + TwoGB + AllocGranularity)) & ~(AllocGranularity - 1));
333
334 // Check if that location is free, and if not, loop over regions until we find
335 // one that is.
336 MEMORY_BASIC_INFORMATION mbi = {};
337 while (sizeof(mbi) == VirtualQuery(Base, &mbi, sizeof(mbi))) {
338 if (mbi.State & MEM_FREE) break;
339 Base += mbi.RegionSize;
340 }
341
342 // Allocate one RWX page at the free location.
343 return (u8 *)::VirtualAlloc(Base, ActiveCodeLength, MEM_COMMIT | MEM_RESERVE,
344 PAGE_EXECUTE_READWRITE);
345}
346
347template<class T>
348static void LoadActiveCode(
349 const T &code,
350 uptr *entry_point,
351 FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
352 if (ActiveCode == nullptr) {
353 ActiveCode = AllocateCode2GBAway((u8*)&InterceptorFunction);
354 ASSERT_NE(ActiveCode, nullptr) << "failed to allocate RWX memory 2GB away";
355 }
356
357 size_t position = 0;
358
359 // Add padding to avoid memory violation when scanning the prefix.
360 for (int i = 0; i < 16; ++i)
361 ActiveCode[position++] = 0xC3; // Instruction 'ret'.
362
363 // Add function padding.
364 size_t padding = 0;
365 if (prefix_kind == FunctionPrefixPadding)
366 padding = 16;
367 else if (prefix_kind == FunctionPrefixDetour ||
368 prefix_kind == FunctionPrefixHotPatch)
369 padding = FIRST_32_SECOND_64(5, 6);
370 // Insert |padding| instructions 'nop'.
371 for (size_t i = 0; i < padding; ++i)
372 ActiveCode[position++] = 0x90;
373
374 // Keep track of the entry point.
375 *entry_point = (uptr)&ActiveCode[position];
376
377 // Add the detour instruction (i.e. mov edi, edi)
378 if (prefix_kind == FunctionPrefixDetour) {
379#if SANITIZER_WINDOWS64
380 // Note that "mov edi,edi" is NOP in 32-bit only, in 64-bit it clears
381 // higher bits of RDI.
382 // Use 66,90H as NOP for Windows64.
383 ActiveCode[position++] = 0x66;
384 ActiveCode[position++] = 0x90;
385#else
386 // mov edi,edi.
387 ActiveCode[position++] = 0x8B;
388 ActiveCode[position++] = 0xFF;
389#endif
390
391 }
392
393 // Copy the function body.
394 for (size_t i = 0; i < sizeof(T); ++i)
395 ActiveCode[position++] = code[i];
396}
397
398int InterceptorFunctionCalled;
399IdentityFunction InterceptedRealFunction;
400
401int InterceptorFunction(int x) {
402 ++InterceptorFunctionCalled;
403 return InterceptedRealFunction(x);
404}
405
406} // namespace
407
408// Tests for interception_win.h
409TEST(Interception, InternalGetProcAddress) {
410 HMODULE ntdll_handle = ::GetModuleHandle("ntdll");
411 ASSERT_NE(nullptr, ntdll_handle);
412 uptr DbgPrint_expected = (uptr)::GetProcAddress(ntdll_handle, "DbgPrint");
413 uptr isdigit_expected = (uptr)::GetProcAddress(ntdll_handle, "isdigit");
414 uptr DbgPrint_adddress = InternalGetProcAddress(ntdll_handle, "DbgPrint");
415 uptr isdigit_address = InternalGetProcAddress(ntdll_handle, "isdigit");
416
417 EXPECT_EQ(DbgPrint_expected, DbgPrint_adddress);
418 EXPECT_EQ(isdigit_expected, isdigit_address);
419 EXPECT_NE(DbgPrint_adddress, isdigit_address);
420}
421
422template <class T>
423static void TestIdentityFunctionPatching(
424 const T &code, TestOverrideFunction override,
425 FunctionPrefixKind prefix_kind = FunctionPrefixNone,
426 int function_start_offset = 0) {
427 uptr identity_address;
428 LoadActiveCode(code, &identity_address, prefix_kind);
429 identity_address += function_start_offset;
430 IdentityFunction identity = (IdentityFunction)identity_address;
431
432 // Validate behavior before dynamic patching.
433 InterceptorFunctionCalled = 0;
434 EXPECT_EQ(0, identity(0));
435 EXPECT_EQ(42, identity(42));
436 EXPECT_EQ(0, InterceptorFunctionCalled);
437
438 // Patch the function.
439 uptr real_identity_address = 0;
440 bool success = override(identity_address,
441 (uptr)&InterceptorFunction,
442 &real_identity_address);
443 EXPECT_TRUE(success);
444 EXPECT_NE(0U, real_identity_address);
445 IdentityFunction real_identity = (IdentityFunction)real_identity_address;
446 InterceptedRealFunction = real_identity;
447
448 // Don't run tests if hooking failed or the real function is not valid.
449 if (!success || !real_identity_address)
450 return;
451
452 // Calling the redirected function.
453 InterceptorFunctionCalled = 0;
454 EXPECT_EQ(0, identity(0));
455 EXPECT_EQ(42, identity(42));
456 EXPECT_EQ(2, InterceptorFunctionCalled);
457
458 // Calling the real function.
459 InterceptorFunctionCalled = 0;
460 EXPECT_EQ(0, real_identity(0));
461 EXPECT_EQ(42, real_identity(42));
462 EXPECT_EQ(0, InterceptorFunctionCalled);
463
464 TestOnlyReleaseTrampolineRegions();
465}
466
467# if !SANITIZER_WINDOWS64
468TEST(Interception, OverrideFunctionWithDetour) {
469 TestOverrideFunction override = OverrideFunctionWithDetour;
470 FunctionPrefixKind prefix = FunctionPrefixDetour;
471 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
472 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
473 TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
474 TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
475}
476#endif // !SANITIZER_WINDOWS64
477
478TEST(Interception, OverrideFunctionWithRedirectJump) {
479 TestOverrideFunction override = OverrideFunctionWithRedirectJump;
480 TestIdentityFunctionPatching(kIdentityCodeWithJump, override);
481 TestIdentityFunctionPatching(kIdentityCodeWithJumpBackwards, override,
482 FunctionPrefixNone,
483 kIdentityCodeWithJumpBackwardsOffset);
484}
485
486TEST(Interception, OverrideFunctionWithHotPatch) {
487 TestOverrideFunction override = OverrideFunctionWithHotPatch;
488 FunctionPrefixKind prefix = FunctionPrefixHotPatch;
489 TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
490}
491
492TEST(Interception, OverrideFunctionWithTrampoline) {
493 TestOverrideFunction override = OverrideFunctionWithTrampoline;
494 FunctionPrefixKind prefix = FunctionPrefixNone;
495 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
496 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
497
498 prefix = FunctionPrefixPadding;
499 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
500 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
501}
502
503TEST(Interception, OverrideFunction) {
504 TestOverrideFunction override = OverrideFunction;
505 FunctionPrefixKind prefix = FunctionPrefixNone;
506 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
507 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
508 TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
509
510 prefix = FunctionPrefixPadding;
511 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
512 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
513 TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
514 TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
515
516 prefix = FunctionPrefixHotPatch;
517 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
518 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
519 TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
520 TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
521
522 prefix = FunctionPrefixDetour;
523 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix);
524 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix);
525 TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);
526 TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix);
527}
528
529template<class T>
530static void TestIdentityFunctionMultiplePatching(
531 const T &code,
532 TestOverrideFunction override,
533 FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
534 uptr identity_address;
535 LoadActiveCode(code, &identity_address, prefix_kind);
536
537 // Patch the function.
538 uptr real_identity_address = 0;
539 bool success = override(identity_address,
540 (uptr)&InterceptorFunction,
541 &real_identity_address);
542 EXPECT_TRUE(success);
543 EXPECT_NE(0U, real_identity_address);
544
545 // Re-patching the function should not work.
546 success = override(identity_address,
547 (uptr)&InterceptorFunction,
548 &real_identity_address);
549 EXPECT_FALSE(success);
550
551 TestOnlyReleaseTrampolineRegions();
552}
553
554TEST(Interception, OverrideFunctionMultiplePatchingIsFailing) {
555#if !SANITIZER_WINDOWS64
556 TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue,
557 OverrideFunctionWithDetour,
558 FunctionPrefixDetour);
559#endif
560
561 TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov,
562 OverrideFunctionWithHotPatch,
563 FunctionPrefixHotPatch);
564
565 TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop,
566 OverrideFunctionWithTrampoline,
567 FunctionPrefixPadding);
568}
569
570TEST(Interception, OverrideFunctionTwice) {
571 uptr identity_address1;
572 LoadActiveCode(kIdentityTwice, &identity_address1);
573 uptr identity_address2 = identity_address1 + kIdentityTwiceOffset;
574 IdentityFunction identity1 = (IdentityFunction)identity_address1;
575 IdentityFunction identity2 = (IdentityFunction)identity_address2;
576
577 // Patch the two functions.
578 uptr real_identity_address = 0;
579 EXPECT_TRUE(OverrideFunction(identity_address1,
580 (uptr)&InterceptorFunction,
581 &real_identity_address));
582 EXPECT_TRUE(OverrideFunction(identity_address2,
583 (uptr)&InterceptorFunction,
584 &real_identity_address));
585 IdentityFunction real_identity = (IdentityFunction)real_identity_address;
586 InterceptedRealFunction = real_identity;
587
588 // Calling the redirected function.
589 InterceptorFunctionCalled = 0;
590 EXPECT_EQ(42, identity1(42));
591 EXPECT_EQ(42, identity2(42));
592 EXPECT_EQ(2, InterceptorFunctionCalled);
593
594 TestOnlyReleaseTrampolineRegions();
595}
596
597template<class T>
598static bool TestFunctionPatching(
599 const T &code,
600 TestOverrideFunction override,
601 FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
602 uptr address;
603 LoadActiveCode(code, &address, prefix_kind);
604 uptr unused_real_address = 0;
605 bool result = override(
606 address, (uptr)&InterceptorFunction, &unused_real_address);
607
608 TestOnlyReleaseTrampolineRegions();
609 return result;
610}
611
612TEST(Interception, PatchableFunction) {
613 TestOverrideFunction override = OverrideFunction;
614 // Test without function padding.
615 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override));
616 EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override));
617#if SANITIZER_WINDOWS64
618 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
619#else
620 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override));
621#endif
622 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
623 EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override));
624#if SANITIZER_WINDOWS64
625 EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override));
626#endif
627
628 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
629 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
630 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
631 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
632 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
633 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
634}
635
636#if !SANITIZER_WINDOWS64
637TEST(Interception, PatchableFunctionWithDetour) {
638 TestOverrideFunction override = OverrideFunctionWithDetour;
639 // Without the prefix, no function can be detoured.
640 EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
641 EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
642 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
643 EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override));
644 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
645 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
646 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
647 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
648 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
649 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
650
651 // With the prefix, all functions can be detoured.
652 FunctionPrefixKind prefix = FunctionPrefixDetour;
653 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
654 EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
655 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
656 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
657 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
658 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
659 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
660 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
661 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
662 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
663}
664#endif // !SANITIZER_WINDOWS64
665
666TEST(Interception, PatchableFunctionWithRedirectJump) {
667 TestOverrideFunction override = OverrideFunctionWithRedirectJump;
668 EXPECT_FALSE(TestFunctionPatching(kPatchableCode1, override));
669 EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override));
670 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));
671 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
672 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
673 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));
674 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override));
675 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override));
676 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override));
677 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override));
678}
679
680TEST(Interception, PatchableFunctionWithHotPatch) {
681 TestOverrideFunction override = OverrideFunctionWithHotPatch;
682 FunctionPrefixKind prefix = FunctionPrefixHotPatch;
683
684 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
685 EXPECT_FALSE(TestFunctionPatching(kPatchableCode2, override, prefix));
686 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
687 EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
688#if SANITIZER_WINDOWS64
689 EXPECT_TRUE(TestFunctionPatching(kPatchableCode6, override, prefix));
690 EXPECT_TRUE(TestFunctionPatching(kPatchableCode7, override, prefix));
691 EXPECT_TRUE(TestFunctionPatching(kPatchableCode8, override, prefix));
692#endif
693 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
694 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
695 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
696 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
697 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
698 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
699}
700
701TEST(Interception, PatchableFunctionWithTrampoline) {
702 TestOverrideFunction override = OverrideFunctionWithTrampoline;
703 FunctionPrefixKind prefix = FunctionPrefixPadding;
704
705 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
706 EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
707#if SANITIZER_WINDOWS64
708 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
709 EXPECT_TRUE(TestFunctionPatching(kPatchableCode9, override, prefix));
710 EXPECT_TRUE(TestFunctionPatching(kPatchableCode10, override, prefix));
711 EXPECT_TRUE(TestFunctionPatching(kPatchableCode11, override, prefix));
712 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode7, override, prefix));
713 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode8, override, prefix));
714 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode9, override, prefix));
715#else
716 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
717 EXPECT_TRUE(TestFunctionPatching(kPatchableCode12, override, prefix));
718 EXPECT_TRUE(TestFunctionPatching(kPatchableCode13, override, prefix));
719#endif
720 EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix));
721 EXPECT_TRUE(TestFunctionPatching(kPatchableCode14, override, prefix));
722
723 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
724 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
725 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
726 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
727 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
728 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
729}
730
731TEST(Interception, UnsupportedInstructionWithTrampoline) {
732 TestOverrideFunction override = OverrideFunctionWithTrampoline;
733 FunctionPrefixKind prefix = FunctionPrefixPadding;
734
735 static bool reportCalled;
736 reportCalled = false;
737
738 struct Local {
739 static void Report(const char *format, ...) {
740 if (reportCalled)
741 FAIL() << "Report called more times than expected";
742 reportCalled = true;
743 ASSERT_STREQ(
744 "interception_win: unhandled instruction at %p: %02x %02x %02x %02x "
745 "%02x %02x %02x %02x\n",
746 format);
747 va_list args;
748 va_start(args, format);
749 u8 *ptr = va_arg(args, u8 *);
750 for (int i = 0; i < 8; i++) EXPECT_EQ(kUnsupportedCode1[i], ptr[i]);
751 int bytes[8];
752 for (int i = 0; i < 8; i++) {
753 bytes[i] = va_arg(args, int);
754 EXPECT_EQ(kUnsupportedCode1[i], bytes[i]);
755 }
756 va_end(args);
757 }
758 };
759
760 SetErrorReportCallback(Local::Report);
761 EXPECT_FALSE(TestFunctionPatching(kUnsupportedCode1, override, prefix));
762 SetErrorReportCallback(nullptr);
763
764 if (!reportCalled)
765 ADD_FAILURE() << "Report not called";
766}
767
768TEST(Interception, PatchableFunctionPadding) {
769 TestOverrideFunction override = OverrideFunction;
770 FunctionPrefixKind prefix = FunctionPrefixPadding;
771
772 EXPECT_TRUE(TestFunctionPatching(kPatchableCode1, override, prefix));
773 EXPECT_TRUE(TestFunctionPatching(kPatchableCode2, override, prefix));
774#if SANITIZER_WINDOWS64
775 EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));
776#else
777 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));
778#endif
779 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix));
780
781 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override, prefix));
782 EXPECT_TRUE(TestFunctionPatching(kUnpatchableCode2, override, prefix));
783 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode3, override, prefix));
784 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode4, override, prefix));
785 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode5, override, prefix));
786 EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode6, override, prefix));
787}
788
789TEST(Interception, EmptyExportTable) {
790 // We try to get a pointer to a function from an executable that doesn't
791 // export any symbol (empty export table).
792 uptr FunPtr = InternalGetProcAddress((void *)GetModuleHandleA(0), "example");
793 EXPECT_EQ(0U, FunPtr);
794}
795
796} // namespace __interception
797
798# endif // !SANITIZER_WINDOWS_ARM64
799#endif // SANITIZER_WINDOWS
800#endif // #if !SANITIZER_DEBUG
801

source code of compiler-rt/lib/interception/tests/interception_win_test.cpp