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 | |
28 | namespace __interception { |
29 | namespace { |
30 | |
31 | enum FunctionPrefixKind { |
32 | FunctionPrefixNone, |
33 | FunctionPrefixPadding, |
34 | FunctionPrefixHotPatch, |
35 | FunctionPrefixDetour, |
36 | }; |
37 | |
38 | typedef bool (*TestOverrideFunction)(uptr, uptr, uptr*); |
39 | typedef int (*IdentityFunction)(int); |
40 | |
41 | #if SANITIZER_WINDOWS64 |
42 | |
43 | const 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 | |
51 | const 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 | |
63 | const u8 kIdentityTwiceOffset = 16; |
64 | const 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 | |
79 | const u8 kIdentityCodeWithMov[] = { |
80 | 0x89, 0xC8, // mov eax, ecx |
81 | 0xC3, // ret |
82 | }; |
83 | |
84 | const 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 | |
92 | const 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 | }; |
99 | const u8 kIdentityCodeWithJumpBackwardsOffset = 3; |
100 | |
101 | # else |
102 | |
103 | const 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 | |
111 | const 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 | |
123 | const u8 kIdentityTwiceOffset = 8; |
124 | const 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 | |
137 | const u8 kIdentityCodeWithMov[] = { |
138 | 0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4] |
139 | 0xC3, // ret |
140 | }; |
141 | |
142 | const 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 | |
150 | const 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 | }; |
157 | const u8 kIdentityCodeWithJumpBackwardsOffset = 5; |
158 | |
159 | # endif |
160 | |
161 | const u8 kPatchableCode1[] = { |
162 | 0xB8, 0x4B, 0x00, 0x00, 0x00, // mov eax,4B |
163 | 0x33, 0xC9, // xor ecx,ecx |
164 | 0xC3, // ret |
165 | }; |
166 | |
167 | const 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 | |
175 | const 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 | |
182 | const u8 kPatchableCode4[] = { |
183 | 0xE9, 0xCC, 0xCC, 0xCC, 0xCC, // jmp <label> |
184 | 0x90, 0x90, 0x90, 0x90, |
185 | }; |
186 | |
187 | const 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 |
195 | u8 kLoadGlobalCode[] = { |
196 | 0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov eax [rip + global] |
197 | 0xC3, // ret |
198 | }; |
199 | #endif |
200 | |
201 | const u8 kUnpatchableCode1[] = { |
202 | 0xC3, // ret |
203 | }; |
204 | |
205 | const u8 kUnpatchableCode2[] = { |
206 | 0x33, 0xC9, // xor ecx,ecx |
207 | 0xC3, // ret |
208 | }; |
209 | |
210 | const u8 kUnpatchableCode3[] = { |
211 | 0x75, 0xCC, // jne <label> |
212 | 0x33, 0xC9, // xor ecx,ecx |
213 | 0xC3, // ret |
214 | }; |
215 | |
216 | const u8 kUnpatchableCode4[] = { |
217 | 0x74, 0xCC, // jne <label> |
218 | 0x33, 0xC9, // xor ecx,ecx |
219 | 0xC3, // ret |
220 | }; |
221 | |
222 | const u8 kUnpatchableCode5[] = { |
223 | 0xEB, 0x02, // jmp <label> |
224 | 0x33, 0xC9, // xor ecx,ecx |
225 | 0xC3, // ret |
226 | }; |
227 | |
228 | const u8 kUnpatchableCode6[] = { |
229 | 0xE8, 0xCC, 0xCC, 0xCC, 0xCC, // call <func> |
230 | 0x90, 0x90, 0x90, 0x90, |
231 | }; |
232 | |
233 | const u8 kUnpatchableCode7[] = { |
234 | 0x33, 0xc0, // xor eax,eax |
235 | 0x48, 0x85, 0xd2, // test rdx,rdx |
236 | 0x74, 0x10, // je +16 (unpatchable) |
237 | }; |
238 | |
239 | const 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 | |
247 | const 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 | |
255 | const 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 | |
261 | const 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 | |
267 | const 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 | |
273 | const u8 kPatchableCode9[] = { |
274 | 0x8a, 0x01, // al,byte ptr [rcx] |
275 | 0x45, 0x33, 0xc0, // xor r8d,r8d |
276 | 0x84, 0xc0, // test al,al |
277 | }; |
278 | |
279 | const 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 | |
285 | const u8 kPatchableCode11[] = { |
286 | 0x48, 0x83, 0xec, 0x38, // sub rsp,38h |
287 | 0x83, 0x64, 0x24, 0x28, 0x00, // and dword ptr [rsp+28h],0 |
288 | }; |
289 | |
290 | const 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 | |
298 | const 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 | |
306 | const 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 | |
314 | const 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. |
322 | u8* ActiveCode; |
323 | const size_t ActiveCodeLength = 4096; |
324 | |
325 | int InterceptorFunction(int x); |
326 | |
327 | /// Allocate code memory more than 2GB away from Base. |
328 | u8 *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 | |
347 | template<class T> |
348 | static 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 | |
398 | int InterceptorFunctionCalled; |
399 | IdentityFunction InterceptedRealFunction; |
400 | |
401 | int InterceptorFunction(int x) { |
402 | ++InterceptorFunctionCalled; |
403 | return InterceptedRealFunction(x); |
404 | } |
405 | |
406 | } // namespace |
407 | |
408 | // Tests for interception_win.h |
409 | TEST(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 | |
422 | template <class T> |
423 | static 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 |
468 | TEST(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 | |
478 | TEST(Interception, OverrideFunctionWithRedirectJump) { |
479 | TestOverrideFunction override = OverrideFunctionWithRedirectJump; |
480 | TestIdentityFunctionPatching(kIdentityCodeWithJump, override); |
481 | TestIdentityFunctionPatching(kIdentityCodeWithJumpBackwards, override, |
482 | FunctionPrefixNone, |
483 | kIdentityCodeWithJumpBackwardsOffset); |
484 | } |
485 | |
486 | TEST(Interception, OverrideFunctionWithHotPatch) { |
487 | TestOverrideFunction override = OverrideFunctionWithHotPatch; |
488 | FunctionPrefixKind prefix = FunctionPrefixHotPatch; |
489 | TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); |
490 | } |
491 | |
492 | TEST(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 | |
503 | TEST(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 | |
529 | template<class T> |
530 | static 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 | |
554 | TEST(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 | |
570 | TEST(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 | |
597 | template<class T> |
598 | static 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 | |
612 | TEST(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 |
637 | TEST(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 | |
666 | TEST(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 | |
680 | TEST(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 | |
701 | TEST(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 | |
731 | TEST(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 | |
768 | TEST(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 | |
789 | TEST(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 | |