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 # 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) 238 }; 239 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) 246 }; 247 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) 254 }; 255 256 const u8 kPatchableCode6[] = { 257 0x48, 0x89, 0x54, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], rdx 258 0x33, 0xC9, // xor ecx,ecx 259 0xC3, // ret 260 }; 261 262 const u8 kPatchableCode7[] = { 263 0x4c, 0x89, 0x4c, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], r9 264 0x33, 0xC9, // xor ecx,ecx 265 0xC3, // ret 266 }; 267 268 const u8 kPatchableCode8[] = { 269 0x4c, 0x89, 0x44, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], r8 270 0x33, 0xC9, // xor ecx,ecx 271 0xC3, // ret 272 }; 273 274 const u8 kPatchableCode9[] = { 275 0x8a, 0x01, // al,byte ptr [rcx] 276 0x45, 0x33, 0xc0, // xor r8d,r8d 277 0x84, 0xc0, // test al,al 278 }; 279 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 284 }; 285 286 const u8 kPatchableCode11[] = { 287 0x48, 0x83, 0xec, 0x38, // sub rsp,38h 288 0x83, 0x64, 0x24, 0x28, 0x00, // and dword ptr [rsp+28h],0 289 }; 290 # endif 291 292 # if !SANITIZER_WINDOWS64 293 const u8 kPatchableCode12[] = { 294 0x55, // push ebp 295 0x53, // push ebx 296 0x57, // push edi 297 0x56, // push esi 298 0x8b, 0x6c, 0x24, 0x18, // mov ebp,dword ptr[esp+18h] 299 }; 300 301 const u8 kPatchableCode13[] = { 302 0x55, // push ebp 303 0x53, // push ebx 304 0x57, // push edi 305 0x56, // push esi 306 0x8b, 0x5c, 0x24, 0x14, // mov ebx,dword ptr[esp+14h] 307 }; 308 # endif 309 310 const u8 kPatchableCode14[] = { 311 0x55, // push ebp 312 0x89, 0xe5, // mov ebp,esp 313 0x53, // push ebx 314 0x57, // push edi 315 0x56, // push esi 316 }; 317 318 const u8 kUnsupportedCode1[] = { 319 0x0f, 0x0b, // ud2 320 0x0f, 0x0b, // ud2 321 0x0f, 0x0b, // ud2 322 0x0f, 0x0b, // ud2 323 }; 324 325 // A buffer holding the dynamically generated code under test. 326 u8* ActiveCode; 327 const size_t ActiveCodeLength = 4096; 328 329 int InterceptorFunction(int x); 330 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)); 337 338 // Check if that location is free, and if not, loop over regions until we find 339 // one that is. 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; 344 } 345 346 // Allocate one RWX page at the free location. 347 return (u8 *)::VirtualAlloc(Base, ActiveCodeLength, MEM_COMMIT | MEM_RESERVE, 348 PAGE_EXECUTE_READWRITE); 349 } 350 351 template<class T> 352 static void LoadActiveCode( 353 const T &code, 354 uptr *entry_point, 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"; 359 } 360 361 size_t position = 0; 362 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'. 366 367 // Add function padding. 368 size_t padding = 0; 369 if (prefix_kind == FunctionPrefixPadding) 370 padding = 16; 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; 377 378 // Keep track of the entry point. 379 *entry_point = (uptr)&ActiveCode[position]; 380 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; 389 #else 390 // mov edi,edi. 391 ActiveCode[position++] = 0x8B; 392 ActiveCode[position++] = 0xFF; 393 #endif 394 395 } 396 397 // Copy the function body. 398 for (size_t i = 0; i < sizeof(T); ++i) 399 ActiveCode[position++] = code[i]; 400 } 401 402 int InterceptorFunctionCalled; 403 IdentityFunction InterceptedRealFunction; 404 405 int InterceptorFunction(int x) { 406 ++InterceptorFunctionCalled; 407 return InterceptedRealFunction(x); 408 } 409 410 } // namespace 411 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"); 420 421 EXPECT_EQ(DbgPrint_expected, DbgPrint_adddress); 422 EXPECT_EQ(isdigit_expected, isdigit_address); 423 EXPECT_NE(DbgPrint_adddress, isdigit_address); 424 } 425 426 template <class T> 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; 435 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); 441 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; 451 452 // Don't run tests if hooking failed or the real function is not valid. 453 if (!success || !real_identity_address) 454 return; 455 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); 461 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); 467 468 TestOnlyReleaseTrampolineRegions(); 469 } 470 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); 479 } 480 #endif // !SANITIZER_WINDOWS64 481 482 TEST(Interception, OverrideFunctionWithRedirectJump) { 483 TestOverrideFunction override = OverrideFunctionWithRedirectJump; 484 TestIdentityFunctionPatching(kIdentityCodeWithJump, override); 485 TestIdentityFunctionPatching(kIdentityCodeWithJumpBackwards, override, 486 FunctionPrefixNone, 487 kIdentityCodeWithJumpBackwardsOffset); 488 } 489 490 TEST(Interception, OverrideFunctionWithHotPatch) { 491 TestOverrideFunction override = OverrideFunctionWithHotPatch; 492 FunctionPrefixKind prefix = FunctionPrefixHotPatch; 493 TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); 494 } 495 496 TEST(Interception, OverrideFunctionWithTrampoline) { 497 TestOverrideFunction override = OverrideFunctionWithTrampoline; 498 FunctionPrefixKind prefix = FunctionPrefixNone; 499 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); 500 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); 501 502 prefix = FunctionPrefixPadding; 503 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); 504 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); 505 } 506 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); 513 514 prefix = FunctionPrefixPadding; 515 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); 516 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); 517 TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); 518 TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); 519 520 prefix = FunctionPrefixHotPatch; 521 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); 522 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); 523 TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); 524 TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); 525 526 prefix = FunctionPrefixDetour; 527 TestIdentityFunctionPatching(kIdentityCodeWithPrologue, override, prefix); 528 TestIdentityFunctionPatching(kIdentityCodeWithPushPop, override, prefix); 529 TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix); 530 TestIdentityFunctionPatching(kIdentityCodeWithJump, override, prefix); 531 } 532 533 template<class T> 534 static void TestIdentityFunctionMultiplePatching( 535 const T &code, 536 TestOverrideFunction override, 537 FunctionPrefixKind prefix_kind = FunctionPrefixNone) { 538 uptr identity_address; 539 LoadActiveCode(code, &identity_address, prefix_kind); 540 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); 548 549 // Re-patching the function should not work. 550 success = override(identity_address, 551 (uptr)&InterceptorFunction, 552 &real_identity_address); 553 EXPECT_FALSE(success); 554 555 TestOnlyReleaseTrampolineRegions(); 556 } 557 558 TEST(Interception, OverrideFunctionMultiplePatchingIsFailing) { 559 #if !SANITIZER_WINDOWS64 560 TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue, 561 OverrideFunctionWithDetour, 562 FunctionPrefixDetour); 563 #endif 564 565 TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov, 566 OverrideFunctionWithHotPatch, 567 FunctionPrefixHotPatch); 568 569 TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop, 570 OverrideFunctionWithTrampoline, 571 FunctionPrefixPadding); 572 } 573 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; 580 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; 591 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); 597 598 TestOnlyReleaseTrampolineRegions(); 599 } 600 601 template<class T> 602 static bool TestFunctionPatching( 603 const T &code, 604 TestOverrideFunction override, 605 FunctionPrefixKind prefix_kind = FunctionPrefixNone) { 606 uptr address; 607 LoadActiveCode(code, &address, prefix_kind); 608 uptr unused_real_address = 0; 609 bool result = override( 610 address, (uptr)&InterceptorFunction, &unused_real_address); 611 612 TestOnlyReleaseTrampolineRegions(); 613 return result; 614 } 615 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)); 623 #else 624 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override)); 625 #endif 626 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override)); 627 EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override)); 628 #if SANITIZER_WINDOWS64 629 EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override)); 630 #endif 631 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)); 638 } 639 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)); 654 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)); 667 } 668 #endif // !SANITIZER_WINDOWS64 669 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)); 682 } 683 684 TEST(Interception, PatchableFunctionWithHotPatch) { 685 TestOverrideFunction override = OverrideFunctionWithHotPatch; 686 FunctionPrefixKind prefix = FunctionPrefixHotPatch; 687 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)); 696 #endif 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)); 703 } 704 705 TEST(Interception, PatchableFunctionWithTrampoline) { 706 TestOverrideFunction override = OverrideFunctionWithTrampoline; 707 FunctionPrefixKind prefix = FunctionPrefixPadding; 708 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)); 719 #else 720 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix)); 721 EXPECT_TRUE(TestFunctionPatching(kPatchableCode12, override, prefix)); 722 EXPECT_TRUE(TestFunctionPatching(kPatchableCode13, override, prefix)); 723 #endif 724 EXPECT_FALSE(TestFunctionPatching(kPatchableCode4, override, prefix)); 725 EXPECT_TRUE(TestFunctionPatching(kPatchableCode14, override, prefix)); 726 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)); 733 } 734 735 TEST(Interception, UnsupportedInstructionWithTrampoline) { 736 TestOverrideFunction override = OverrideFunctionWithTrampoline; 737 FunctionPrefixKind prefix = FunctionPrefixPadding; 738 739 static bool reportCalled; 740 reportCalled = false; 741 742 struct Local { 743 static void Report(const char *format, ...) { 744 if (reportCalled) 745 FAIL() << "Report called more times than expected"; 746 reportCalled = true; 747 ASSERT_STREQ( 748 "interception_win: unhandled instruction at %p: %02x %02x %02x %02x " 749 "%02x %02x %02x %02x\n", 750 format); 751 va_list args; 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]); 755 int bytes[8]; 756 for (int i = 0; i < 8; i++) { 757 bytes[i] = va_arg(args, int); 758 EXPECT_EQ(kUnsupportedCode1[i], bytes[i]); 759 } 760 va_end(args); 761 } 762 }; 763 764 SetErrorReportCallback(Local::Report); 765 EXPECT_FALSE(TestFunctionPatching(kUnsupportedCode1, override, prefix)); 766 SetErrorReportCallback(nullptr); 767 768 if (!reportCalled) 769 ADD_FAILURE() << "Report not called"; 770 } 771 772 TEST(Interception, PatchableFunctionPadding) { 773 TestOverrideFunction override = OverrideFunction; 774 FunctionPrefixKind prefix = FunctionPrefixPadding; 775 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)); 780 #else 781 EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix)); 782 #endif 783 EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override, prefix)); 784 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)); 791 } 792 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); 798 } 799 800 const struct InstructionSizeData { 801 size_t size; // hold instruction size or 0 for failure, 802 // e.g. on control instructions 803 u8 instr[16]; 804 size_t rel_offset; // adjustment for RIP-relative addresses when copying 805 // instructions during hooking via hotpatch or trampoline. 806 const char *comment; 807 } data[] = { 808 // clang-format off 809 // sorted list 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, {0x31, 0xC0}, 0, "31 C0 : xor eax, eax"}, 843 { 2, {0x31, 0xC9}, 0, "31 C9 : xor ecx, ecx"}, 844 { 2, {0x31, 0xD2}, 0, "31 D2 : xor edx, edx"}, 845 { 2, {0x33, 0xC0}, 0, "33 C0 : xor eax, eax"}, 846 { 2, {0x33, 0xC9}, 0, "33 C9 : xor ecx, ecx"}, 847 { 2, {0x33, 0xD2}, 0, "33 D2 : xor edx, edx"}, 848 { 2, {0x6A, 0x71}, 0, "6A XX : push XX"}, 849 { 2, {0x84, 0xC0}, 0, "84 C0 : test al,al"}, 850 { 2, {0x84, 0xC9}, 0, "84 C9 : test cl,cl"}, 851 { 2, {0x84, 0xD2}, 0, "84 D2 : test dl,dl"}, 852 { 2, {0x84, 0xDB}, 0, "84 DB : test bl,bl"}, 853 { 2, {0x89, 0xc8}, 0, "89 C8 : mov eax, ecx"}, 854 { 2, {0x89, 0xD1}, 0, "89 D1 : mov ecx, edx"}, 855 { 2, {0x89, 0xE5}, 0, "89 E5 : mov ebp, esp"}, 856 { 2, {0x8A, 0x01}, 0, "8A 01 : mov al, byte ptr [ecx]"}, 857 { 2, {0x8B, 0xC1}, 0, "8B C1 : mov eax, ecx"}, 858 { 2, {0x8B, 0xEC}, 0, "8B EC : mov ebp, esp"}, 859 { 2, {0x8B, 0xFF}, 0, "8B FF : mov edi, edi"}, 860 { 3, {0x80, 0x39, 0x72}, 0, "80 39 XX : cmp BYTE PTR [rcx], XX"}, 861 { 3, {0x83, 0xE4, 0x72}, 0, "83 E4 XX : and esp, XX"}, 862 { 3, {0x83, 0xEC, 0x72}, 0, "83 EC XX : sub esp, XX"}, 863 { 3, {0x8B, 0x4D, 0x72}, 0, "8B 4D XX : mov XX(%ebp), ecx"}, 864 { 3, {0x8B, 0x55, 0x72}, 0, "8B 55 XX : mov XX(%ebp), edx"}, 865 { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov XX(%ebp), esp"}, 866 { 3, {0xc2, 0x71, 0x72}, 0, "C2 XX XX : ret XX (needed for registering weak functions)"}, 867 { 4, {0x8D, 0x4C, 0x24, 0x73}, 0, "8D 4C 24 XX : lea ecx, [esp + XX]"}, 868 { 4, {0xFF, 0x74, 0x24, 0x73}, 0, "FF 74 24 XX : push qword ptr [rsp + XX]"}, 869 { 5, {0x68, 0x71, 0x72, 0x73, 0x74}, 0, "68 XX XX XX XX : push imm32"}, 870 { 5, {0xb8, 0x71, 0x72, 0x73, 0x74}, 0, "b8 XX XX XX XX : mov eax, XX XX XX XX"}, 871 { 5, {0xB9, 0x71, 0x72, 0x73, 0x74}, 0, "b9 XX XX XX XX : mov ecx, XX XX XX XX"}, 872 { 5, {0xBA, 0x71, 0x72, 0x73, 0x74}, 0, "ba XX XX XX XX : mov edx, XX XX XX XX"}, 873 { 6, {0x81, 0xEC, 0x72, 0x73, 0x74, 0x75}, 0, "81 EC XX XX XX XX : sub esp, XX XX XX XX"}, 874 { 6, {0xFF, 0x89, 0x72, 0x73, 0x74, 0x75}, 0, "FF 89 XX XX XX XX : dec dword ptr [ecx + XX XX XX XX]"}, 875 { 7, {0x8D, 0xA4, 0x24, 0x73, 0x74, 0x75, 0x76}, 0, "8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX]"}, 876 #if SANITIZER_WINDOWS_x64 877 // sorted list 878 { 2, {0x40, 0x50}, 0, "40 50 : push rax"}, 879 { 2, {0x40, 0x51}, 0, "40 51 : push rcx"}, 880 { 2, {0x40, 0x52}, 0, "40 52 : push rdx"}, 881 { 2, {0x40, 0x53}, 0, "40 53 : push rbx"}, 882 { 2, {0x40, 0x54}, 0, "40 54 : push rsp"}, 883 { 2, {0x40, 0x55}, 0, "40 55 : push rbp"}, 884 { 2, {0x40, 0x56}, 0, "40 56 : push rsi"}, 885 { 2, {0x40, 0x57}, 0, "40 57 : push rdi"}, 886 { 2, {0x41, 0x54}, 0, "41 54 : push r12"}, 887 { 2, {0x41, 0x55}, 0, "41 55 : push r13"}, 888 { 2, {0x41, 0x56}, 0, "41 56 : push r14"}, 889 { 2, {0x41, 0x57}, 0, "41 57 : push r15"}, 890 { 2, {0x66, 0x90}, 0, "66 90 : Two-byte NOP"}, 891 { 2, {0x84, 0xc0}, 0, "84 c0 : test al, al"}, 892 { 2, {0x8a, 0x01}, 0, "8a 01 : mov al, byte ptr [rcx]"}, 893 { 3, {0x0f, 0xb6, 0x01}, 0, "0f b6 01 : movzx eax, BYTE PTR [rcx]"}, 894 { 3, {0x0f, 0xb6, 0x09}, 0, "0f b6 09 : movzx ecx, BYTE PTR [rcx]"}, 895 { 3, {0x0f, 0xb6, 0x11}, 0, "0f b6 11 : movzx edx, BYTE PTR [rcx]"}, 896 { 3, {0x0f, 0xb6, 0xc2}, 0, "0f b6 c2 : movzx eax, dl"}, 897 { 3, {0x0f, 0xb6, 0xd2}, 0, "0f b6 d2 : movzx edx, dl"}, 898 { 3, {0x0f, 0xb7, 0x10}, 0, "0f b7 10 : movzx edx, WORD PTR [rax]"}, 899 { 3, {0x0f, 0xbe, 0xd2}, 0, "0f be d2 : movsx edx, dl"}, 900 { 3, {0x41, 0x8b, 0xc0}, 0, "41 8b c0 : mov eax, r8d"}, 901 { 3, {0x41, 0x8b, 0xc1}, 0, "41 8b c1 : mov eax, r9d"}, 902 { 3, {0x41, 0x8b, 0xc2}, 0, "41 8b c2 : mov eax, r10d"}, 903 { 3, {0x41, 0x8b, 0xc3}, 0, "41 8b c3 : mov eax, r11d"}, 904 { 3, {0x41, 0x8b, 0xc4}, 0, "41 8b c4 : mov eax, r12d"}, 905 { 3, {0x45, 0x31, 0xc0}, 0, "45 31 c0 : xor r8d,r8d"}, 906 { 3, {0x45, 0x31, 0xc9}, 0, "45 31 c9 : xor r9d,r9d"}, 907 { 3, {0x45, 0x33, 0xc0}, 0, "45 33 c0 : xor r8d, r8d"}, 908 { 3, {0x45, 0x33, 0xc9}, 0, "45 33 c9 : xor r9d, r9d"}, 909 { 3, {0x45, 0x33, 0xdb}, 0, "45 33 db : xor r11d, r11d"}, 910 { 3, {0x45, 0x84, 0xc0}, 0, "45 84 c0 : test r8b,r8b"}, 911 { 3, {0x45, 0x84, 0xd2}, 0, "45 84 d2 : test r10b,r10b"}, 912 { 3, {0x48, 0x29, 0xd1}, 0, "48 29 d1 : sub rcx, rdx"}, 913 { 3, {0x48, 0x2b, 0xca}, 0, "48 2b ca : sub rcx, rdx"}, 914 { 3, {0x48, 0x2b, 0xd1}, 0, "48 2b d1 : sub rdx, rcx"}, 915 { 3, {0x48, 0x3b, 0xca}, 0, "48 3b ca : cmp rcx, rdx"}, 916 { 3, {0x48, 0x85, 0xc0}, 0, "48 85 c0 : test rax, rax"}, 917 { 3, {0x48, 0x85, 0xc9}, 0, "48 85 c9 : test rcx, rcx"}, 918 { 3, {0x48, 0x85, 0xd2}, 0, "48 85 d2 : test rdx, rdx"}, 919 { 3, {0x48, 0x85, 0xdb}, 0, "48 85 db : test rbx, rbx"}, 920 { 3, {0x48, 0x85, 0xe4}, 0, "48 85 e4 : test rsp, rsp"}, 921 { 3, {0x48, 0x85, 0xed}, 0, "48 85 ed : test rbp, rbp"}, 922 { 3, {0x48, 0x89, 0xc8}, 0, "48 89 c8 : mov rax,rcx"}, 923 { 3, {0x48, 0x89, 0xcb}, 0, "48 89 cb : mov rbx,rcx"}, 924 { 3, {0x48, 0x89, 0xd0}, 0, "48 89 d0 : mov rax,rdx"}, 925 { 3, {0x48, 0x89, 0xd1}, 0, "48 89 d1 : mov rcx,rdx"}, 926 { 3, {0x48, 0x89, 0xd3}, 0, "48 89 d3 : mov rbx,rdx"}, 927 { 3, {0x48, 0x89, 0xe5}, 0, "48 89 e5 : mov rbp, rsp"}, 928 { 3, {0x48, 0x8b, 0xc1}, 0, "48 8b c1 : mov rax, rcx"}, 929 { 3, {0x48, 0x8b, 0xc4}, 0, "48 8b c4 : mov rax, rsp"}, 930 { 3, {0x48, 0x8b, 0xd1}, 0, "48 8b d1 : mov rdx, rcx"}, 931 { 3, {0x48, 0xf7, 0xd9}, 0, "48 f7 d9 : neg rcx"}, 932 { 3, {0x48, 0xff, 0xc0}, 0, "48 ff c0 : inc rax"}, 933 { 3, {0x48, 0xff, 0xc1}, 0, "48 ff c1 : inc rcx"}, 934 { 3, {0x48, 0xff, 0xc2}, 0, "48 ff c2 : inc rdx"}, 935 { 3, {0x48, 0xff, 0xc3}, 0, "48 ff c3 : inc rbx"}, 936 { 3, {0x48, 0xff, 0xc6}, 0, "48 ff c6 : inc rsi"}, 937 { 3, {0x48, 0xff, 0xc7}, 0, "48 ff c7 : inc rdi"}, 938 { 3, {0x49, 0x89, 0xc8}, 0, "49 89 c8 : mov r8, rcx"}, 939 { 3, {0x49, 0x89, 0xc9}, 0, "49 89 c9 : mov r9, rcx"}, 940 { 3, {0x49, 0x89, 0xca}, 0, "49 89 ca : mov r10,rcx"}, 941 { 3, {0x49, 0x89, 0xd0}, 0, "49 89 d0 : mov r8, rdx"}, 942 { 3, {0x49, 0x89, 0xd1}, 0, "49 89 d1 : mov r9, rdx"}, 943 { 3, {0x49, 0x89, 0xd2}, 0, "49 89 d2 : mov r10, rdx"}, 944 { 3, {0x49, 0x89, 0xd3}, 0, "49 89 d3 : mov r11, rdx"}, 945 { 3, {0x49, 0xff, 0xc0}, 0, "49 ff c0 : inc r8"}, 946 { 3, {0x49, 0xff, 0xc1}, 0, "49 ff c1 : inc r9"}, 947 { 3, {0x49, 0xff, 0xc2}, 0, "49 ff c2 : inc r10"}, 948 { 3, {0x49, 0xff, 0xc3}, 0, "49 ff c3 : inc r11"}, 949 { 3, {0x49, 0xff, 0xc4}, 0, "49 ff c4 : inc r12"}, 950 { 3, {0x49, 0xff, 0xc5}, 0, "49 ff c5 : inc r13"}, 951 { 3, {0x49, 0xff, 0xc6}, 0, "49 ff c6 : inc r14"}, 952 { 3, {0x49, 0xff, 0xc7}, 0, "49 ff c7 : inc r15"}, 953 { 3, {0x4c, 0x8b, 0xc1}, 0, "4c 8b c1 : mov r8, rcx"}, 954 { 3, {0x4c, 0x8b, 0xc9}, 0, "4c 8b c9 : mov r9, rcx"}, 955 { 3, {0x4c, 0x8b, 0xd1}, 0, "4c 8b d1 : mov r10, rcx"}, 956 { 3, {0x4c, 0x8b, 0xd2}, 0, "4c 8b d2 : mov r10, rdx"}, 957 { 3, {0x4c, 0x8b, 0xd9}, 0, "4c 8b d9 : mov r11, rcx"}, 958 { 3, {0x4c, 0x8b, 0xdc}, 0, "4c 8b dc : mov r11, rsp"}, 959 { 3, {0x4d, 0x0b, 0xc0}, 0, "4d 0b c0 : or r8, r8"}, 960 { 3, {0x4d, 0x85, 0xc0}, 0, "4d 85 c0 : test r8, r8"}, 961 { 3, {0x4d, 0x85, 0xc9}, 0, "4d 85 c9 : test r9, r9"}, 962 { 3, {0x4d, 0x85, 0xd2}, 0, "4d 85 d2 : test r10, r10"}, 963 { 3, {0x4d, 0x85, 0xdb}, 0, "4d 85 db : test r11, r11"}, 964 { 3, {0x4d, 0x85, 0xe4}, 0, "4d 85 e4 : test r12, r12"}, 965 { 3, {0x4d, 0x85, 0xed}, 0, "4d 85 ed : test r13, r13"}, 966 { 3, {0x4d, 0x85, 0xf6}, 0, "4d 85 f6 : test r14, r14"}, 967 { 3, {0x4d, 0x85, 0xff}, 0, "4d 85 ff : test r15, r15"}, 968 { 3, {0xf6, 0xc1, 0x72}, 0, "f6 c1 XX : test cl, XX"}, 969 { 4, {0x44, 0x0f, 0xb6, 0x01}, 0, "44 0f b6 01 : movzx r8d, BYTE PTR [rcx]"}, 970 { 4, {0x44, 0x0f, 0xb6, 0x09}, 0, "44 0f b6 09 : movzx r9d, BYTE PTR [rcx]"}, 971 { 4, {0x44, 0x0f, 0xb6, 0x0a}, 0, "44 0f b6 0a : movzx r8d, BYTE PTR [rdx]"}, 972 { 4, {0x44, 0x0f, 0xb6, 0x11}, 0, "44 0f b6 11 : movzx r10d, BYTE PTR [rcx]"}, 973 { 4, {0x44, 0x0f, 0xb6, 0x1a}, 0, "44 0f b6 1a : movzx r11d, BYTE PTR [rdx]"}, 974 { 4, {0x44, 0x8d, 0x42, 0x73}, 0, "44 8d 42 XX : lea r8d , [rdx + XX]"}, 975 { 4, {0x48, 0x83, 0xec, 0x73}, 0, "48 83 ec XX : sub rsp, XX"}, 976 { 4, {0x48, 0x89, 0x58, 0x73}, 0, "48 89 58 XX : mov QWORD PTR[rax + XX], rbx"}, 977 { 4, {0x49, 0x83, 0xf8, 0x73}, 0, "49 83 f8 XX : cmp r8, XX"}, 978 { 4, {0x49, 0x8d, 0x48, 0x73}, 0, "49 8d 48 XX : lea rcx, [...]"}, 979 { 4, {0x4c, 0x8d, 0x04, 0x73}, 0, "4c 8d 04 XX : lea r8, [...]"}, 980 { 4, {0x4e, 0x8d, 0x14, 0x73}, 0, "4e 8d 14 XX : lea r10, [...]"}, 981 { 4, {0x66, 0x83, 0x39, 0x73}, 0, "66 83 39 XX : cmp WORD PTR [rcx], XX"}, 982 { 4, {0x80, 0x78, 0x72, 0x73}, 0, "80 78 YY XX : cmp BYTE PTR [rax+YY], XX"}, 983 { 4, {0x80, 0x79, 0x72, 0x73}, 0, "80 79 YY XX : cmp BYTE ptr [rcx+YY], XX"}, 984 { 4, {0x80, 0x7A, 0x72, 0x73}, 0, "80 7A YY XX : cmp BYTE PTR [rdx+YY], XX"}, 985 { 4, {0x80, 0x7B, 0x72, 0x73}, 0, "80 7B YY XX : cmp BYTE PTR [rbx+YY], XX"}, 986 { 4, {0x80, 0x7D, 0x72, 0x73}, 0, "80 7D YY XX : cmp BYTE PTR [rbp+YY], XX"}, 987 { 4, {0x80, 0x7E, 0x72, 0x73}, 0, "80 7E YY XX : cmp BYTE PTR [rsi+YY], XX"}, 988 { 4, {0x89, 0x54, 0x24, 0x73}, 0, "89 54 24 XX : mov DWORD PTR[rsp + XX], edx"}, 989 { 5, {0x0F, 0x1F, 0x44, 0x73, 0x74}, 0, "0F 1F 44 XX XX : nop DWORD PTR [...]"}, 990 { 5, {0x44, 0x89, 0x44, 0x24, 0x74}, 0, "44 89 44 24 XX : mov DWORD PTR [rsp + XX], r8d"}, 991 { 5, {0x44, 0x89, 0x4c, 0x24, 0x74}, 0, "44 89 4c 24 XX : mov DWORD PTR [rsp + XX], r9d"}, 992 { 5, {0x48, 0x89, 0x4C, 0x24, 0x74}, 0, "48 89 4C 24 XX : mov QWORD PTR [rsp + XX], rcx"}, 993 { 5, {0x48, 0x89, 0x54, 0x24, 0x74}, 0, "48 89 54 24 XX : mov QWORD PTR [rsp + XX], rdx"}, 994 { 5, {0x48, 0x89, 0x5c, 0x24, 0x74}, 0, "48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx"}, 995 { 5, {0x48, 0x89, 0x6c, 0x24, 0x74}, 0, "48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp"}, 996 { 5, {0x48, 0x89, 0x74, 0x24, 0x74}, 0, "48 89 74 24 XX : mov QWORD PTR [rsp + XX], rsi"}, 997 { 5, {0x48, 0x89, 0x7c, 0x24, 0x74}, 0, "48 89 7c 24 XX : mov QWORD PTR [rsp + XX], rdi"}, 998 { 5, {0x48, 0x8b, 0x44, 0x24, 0x74}, 0, "48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX]"}, 999 { 5, {0x48, 0x8d, 0x6c, 0x24, 0x74}, 0, "48 8d 6c 24 XX : lea rbp, [rsp + XX]"}, 1000 { 5, {0x4c, 0x89, 0x44, 0x24, 0x74}, 0, "4c 89 44 24 XX : mov QWORD PTR [rsp + XX], r8"}, 1001 { 5, {0x4c, 0x89, 0x4c, 0x24, 0x74}, 0, "4c 89 4c 24 XX : mov QWORD PTR [rsp + XX], r9"}, 1002 { 5, {0x66, 0x48, 0x0F, 0x7E, 0xC0}, 0, "66 48 0F 7E C0 : movq rax, xmm0"}, 1003 { 5, {0x83, 0x44, 0x72, 0x73, 0x74}, 0, "83 44 72 XX YY : add DWORD PTR [rdx+rsi*2+XX],YY"}, 1004 { 5, {0x83, 0x64, 0x24, 0x73, 0x74}, 0, "83 64 24 XX YY : and DWORD PTR [rsp+XX], YY"}, 1005 { 6, {0x41, 0xB8, 0x72, 0x73, 0x74, 0x75}, 0, "41 B8 XX XX XX XX : mov r8d, XX XX XX XX"}, 1006 { 6, {0x48, 0x83, 0x64, 0x24, 0x74, 0x75}, 0, "48 83 64 24 XX YY : and QWORD PTR [rsp + XX], YY"}, 1007 { 6, {0x66, 0x81, 0x78, 0x73, 0x74, 0x75}, 0, "66 81 78 XX YY YY : cmp WORD PTR [rax+XX], YY YY"}, 1008 { 6, {0x66, 0x81, 0x79, 0x73, 0x74, 0x75}, 0, "66 81 79 XX YY YY : cmp WORD PTR [rcx+XX], YY YY"}, 1009 { 6, {0x66, 0x81, 0x7a, 0x73, 0x74, 0x75}, 0, "66 81 7a XX YY YY : cmp WORD PTR [rdx+XX], YY YY"}, 1010 { 6, {0x66, 0x81, 0x7b, 0x73, 0x74, 0x75}, 0, "66 81 7b XX YY YY : cmp WORD PTR [rbx+XX], YY YY"}, 1011 { 6, {0x66, 0x81, 0x7e, 0x73, 0x74, 0x75}, 0, "66 81 7e XX YY YY : cmp WORD PTR [rsi+XX], YY YY"}, 1012 { 6, {0x66, 0x81, 0x7f, 0x73, 0x74, 0x75}, 0, "66 81 7f XX YY YY : cmp WORD PTR [rdi+XX], YY YY"}, 1013 { 6, {0x8A, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8A 05 XX XX XX XX : mov al, byte ptr [XX XX XX XX]"}, 1014 { 6, {0x8B, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]"}, 1015 { 6, {0xF2, 0x0f, 0x11, 0x44, 0x24, 0x75}, 0, "f2 0f 11 44 24 XX : movsd QWORD PTR [rsp + XX], xmm0"}, 1016 { 6, {0xF2, 0x0f, 0x11, 0x4c, 0x24, 0x75}, 0, "f2 0f 11 4c 24 XX : movsd QWORD PTR [rsp + XX], xmm1"}, 1017 { 6, {0xF2, 0x0f, 0x11, 0x54, 0x24, 0x75}, 0, "f2 0f 11 54 24 XX : movsd QWORD PTR [rsp + XX], xmm2"}, 1018 { 6, {0xF2, 0x0f, 0x11, 0x5c, 0x24, 0x75}, 0, "f2 0f 11 5c 24 XX : movsd QWORD PTR [rsp + XX], xmm3"}, 1019 { 6, {0xF2, 0x0f, 0x11, 0x64, 0x24, 0x75}, 0, "f2 0f 11 64 24 XX : movsd QWORD PTR [rsp + XX], xmm4"}, 1020 { 7, {0x48, 0x81, 0xec, 0x73, 0x74, 0x75, 0x76}, 0, "48 81 EC XX XX XX XX : sub rsp, XXXXXXXX"}, 1021 { 7, {0x48, 0x89, 0x0d, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 0d XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rcx"}, 1022 { 7, {0x48, 0x89, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 15 XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rdx"}, 1023 { 7, {0x48, 0x8b, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8b 05 XX XX XX XX : mov rax, QWORD PTR [rip + XXXXXXXX]"}, 1024 { 7, {0x48, 0x8d, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8d 05 XX XX XX XX : lea rax, QWORD PTR [rip + XXXXXXXX]"}, 1025 { 7, {0x48, 0xc7, 0xc0, 0x73, 0x74, 0x75, 0x76}, 0, "48 C7 C0 XX XX XX XX : mov rax, XX XX XX XX"}, 1026 { 7, {0x48, 0xff, 0x25, 0x73, 0x74, 0x75, 0x76}, 3, "48 ff 25 XX XX XX XX : rex.W jmp QWORD PTR [rip + XXXXXXXX]"}, 1027 { 7, {0x4C, 0x8D, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "4c 8d 15 XX XX XX XX : lea r10, [rip + XX]"}, 1028 { 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"}, 1029 { 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"}, 1030 { 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"}, 1031 { 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"}, 1032 { 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"}, 1033 { 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"}, 1034 { 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"}, 1035 { 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"}, 1036 { 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"}, 1037 { 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"}, 1038 { 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"}, 1039 { 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"}, 1040 { 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"}, 1041 { 8, {0x48, 0x8D, 0xA4, 0x24, 0x74, 0x75, 0x76, 0x77}, 0, "48 8D A4 24 XX XX XX XX : lea rsp, [rsp + XX XX XX XX]"}, 1042 { 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"}, 1043 { 8, {0xc7, 0x44, 0x24, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "C7 44 24 XX YY YY YY YY : mov dword ptr [rsp + XX], YYYYYYYY"}, 1044 { 9, {0x41, 0x81, 0x7c, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78}, 0, "41 81 7c ZZ YY XX XX XX XX : cmp DWORD PTR [reg+reg*n+YY], XX XX XX XX"}, 1045 { 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]"}, 1046 #else 1047 // sorted list 1048 { 3, {0x8B, 0x45, 0x72}, 0, "8B 45 XX : mov eax, dword ptr [ebp + XX]"}, 1049 { 3, {0x8B, 0x5D, 0x72}, 0, "8B 5D XX : mov ebx, dword ptr [ebp + XX]"}, 1050 { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov esi, dword ptr [ebp + XX]"}, 1051 { 3, {0x8B, 0x7D, 0x72}, 0, "8B 7D XX : mov edi, dword ptr [ebp + XX]"}, 1052 { 3, {0xFF, 0x75, 0x72}, 0, "FF 75 XX : push dword ptr [ebp + XX]"}, 1053 { 4, {0x83, 0x7D, 0x72, 0x73}, 0, "83 7D XX YY : cmp dword ptr [ebp + XX], YY"}, 1054 { 4, {0x8A, 0x44, 0x24, 0x73}, 0, "8A 44 24 XX : mov eal, dword ptr [esp + XX]"}, 1055 { 4, {0x8B, 0x44, 0x24, 0x73}, 0, "8B 44 24 XX : mov eax, dword ptr [esp + XX]"}, 1056 { 4, {0x8B, 0x4C, 0x24, 0x73}, 0, "8B 4C 24 XX : mov ecx, dword ptr [esp + XX]"}, 1057 { 4, {0x8B, 0x54, 0x24, 0x73}, 0, "8B 54 24 XX : mov edx, dword ptr [esp + XX]"}, 1058 { 4, {0x8B, 0x5C, 0x24, 0x73}, 0, "8B 5C 24 XX : mov ebx, dword ptr [esp + XX]"}, 1059 { 4, {0x8B, 0x6C, 0x24, 0x73}, 0, "8B 6C 24 XX : mov ebp, dword ptr [esp + XX]"}, 1060 { 4, {0x8B, 0x74, 0x24, 0x73}, 0, "8B 74 24 XX : mov esi, dword ptr [esp + XX]"}, 1061 { 4, {0x8B, 0x7C, 0x24, 0x73}, 0, "8B 7C 24 XX : mov edi, dword ptr [esp + XX]"}, 1062 { 5, {0x0F, 0xB6, 0x44, 0x24, 0x74}, 0, "0F B6 44 24 XX : movzx eax, byte ptr [esp + XX]"}, 1063 { 5, {0xA1, 0x71, 0x72, 0x73, 0x74}, 0, "A1 XX XX XX XX : mov eax, dword ptr ds:[XXXXXXXX]"}, 1064 { 6, {0xF7, 0xC1, 0x72, 0x73, 0x74, 0x75}, 0, "F7 C1 XX YY ZZ WW : test ecx, WWZZYYXX"}, 1065 { 7, {0x83, 0x3D, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "83 3D XX YY ZZ WW TT : cmp TT, WWZZYYXX"}, 1066 #endif 1067 // clang-format on 1068 }; 1069 1070 std::string dumpInstruction(unsigned arrayIndex, 1071 const InstructionSizeData &data) { 1072 std::stringstream ret; 1073 ret << " with arrayIndex=" << arrayIndex << " {"; 1074 for (size_t i = 0; i < data.size; i++) { 1075 if (i > 0) 1076 ret << ", "; 1077 ret << "0x" << std::setfill('0') << std::setw(2) << std::right << std::hex 1078 << (int)data.instr[i]; 1079 } 1080 ret << "} " << data.comment; 1081 return ret.str(); 1082 } 1083 1084 TEST(Interception, GetInstructionSize) { 1085 for (unsigned i = 0; i < sizeof(data) / sizeof(*data); i++) { 1086 size_t rel_offset = ~0L; 1087 size_t size = __interception::TestOnlyGetInstructionSize( 1088 (uptr)data[i].instr, &rel_offset); 1089 EXPECT_EQ(data[i].size, size) << dumpInstruction(i, data[i]); 1090 EXPECT_EQ(data[i].rel_offset, rel_offset) << dumpInstruction(i, data[i]); 1091 } 1092 } 1093 1094 } // namespace __interception 1095 1096 # endif // !SANITIZER_WINDOWS_ARM64 1097 #endif // SANITIZER_WINDOWS 1098 #endif // #if !SANITIZER_DEBUG 1099