brintos

brintos / llvm-project-archived public Read only

0
0
Text · 49.6 KiB · e3dc4cf Raw
1105 lines · cpp
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-exception6//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 build18// Disabling for ARM64 since testcases are x86/x64 assembly.19#if !SANITIZER_DEBUG20#if SANITIZER_WINDOWS21#    if !SANITIZER_WINDOWS_ARM6422 23#      include <stdarg.h>24 25#      define WIN32_LEAN_AND_MEAN26#      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_WINDOWS6442 43const u8 kIdentityCodeWithPrologue[] = {44    0x55,                   // push        rbp45    0x48, 0x89, 0xE5,       // mov         rbp,rsp46    0x8B, 0xC1,             // mov         eax,ecx47    0x5D,                   // pop         rbp48    0xC3,                   // ret49};50 51const u8 kIdentityCodeWithPushPop[] = {52    0x55,                   // push        rbp53    0x48, 0x89, 0xE5,       // mov         rbp,rsp54    0x53,                   // push        rbx55    0x50,                   // push        rax56    0x58,                   // pop         rax57    0x8B, 0xC1,             // mov         rax,rcx58    0x5B,                   // pop         rbx59    0x5D,                   // pop         rbp60    0xC3,                   // ret61};62 63const u8 kIdentityTwiceOffset = 16;64const u8 kIdentityTwice[] = {65    0x55,                   // push        rbp66    0x48, 0x89, 0xE5,       // mov         rbp,rsp67    0x8B, 0xC1,             // mov         eax,ecx68    0x5D,                   // pop         rbp69    0xC3,                   // ret70    0x90, 0x90, 0x90, 0x90,71    0x90, 0x90, 0x90, 0x90,72    0x55,                   // push        rbp73    0x48, 0x89, 0xE5,       // mov         rbp,rsp74    0x8B, 0xC1,             // mov         eax,ecx75    0x5D,                   // pop         rbp76    0xC3,                   // ret77};78 79const u8 kIdentityCodeWithMov[] = {80    0x89, 0xC8,             // mov         eax, ecx81    0xC3,                   // ret82};83 84const u8 kIdentityCodeWithJump[] = {85    0xE9, 0x04, 0x00, 0x00,86    0x00,                   // jmp + 487    0xCC, 0xCC, 0xCC, 0xCC,88    0x89, 0xC8,             // mov         eax, ecx89    0xC3,                   // ret90};91 92const u8 kIdentityCodeWithJumpBackwards[] = {93    0x89, 0xC8,  // mov         eax, ecx94    0xC3,        // ret95    0xE9, 0xF8, 0xFF, 0xFF,96    0xFF,  // jmp - 897    0xCC, 0xCC, 0xCC, 0xCC,98};99const u8 kIdentityCodeWithJumpBackwardsOffset = 3;100 101#    else102 103const u8 kIdentityCodeWithPrologue[] = {104    0x55,                   // push        ebp105    0x8B, 0xEC,             // mov         ebp,esp106    0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]107    0x5D,                   // pop         ebp108    0xC3,                   // ret109};110 111const u8 kIdentityCodeWithPushPop[] = {112    0x55,                   // push        ebp113    0x8B, 0xEC,             // mov         ebp,esp114    0x53,                   // push        ebx115    0x50,                   // push        eax116    0x58,                   // pop         eax117    0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]118    0x5B,                   // pop         ebx119    0x5D,                   // pop         ebp120    0xC3,                   // ret121};122 123const u8 kIdentityTwiceOffset = 8;124const u8 kIdentityTwice[] = {125    0x55,                   // push        ebp126    0x8B, 0xEC,             // mov         ebp,esp127    0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]128    0x5D,                   // pop         ebp129    0xC3,                   // ret130    0x55,                   // push        ebp131    0x8B, 0xEC,             // mov         ebp,esp132    0x8B, 0x45, 0x08,       // mov         eax,dword ptr [ebp + 8]133    0x5D,                   // pop         ebp134    0xC3,                   // ret135};136 137const u8 kIdentityCodeWithMov[] = {138    0x8B, 0x44, 0x24, 0x04, // mov         eax,dword ptr [esp + 4]139    0xC3,                   // ret140};141 142const u8 kIdentityCodeWithJump[] = {143    0xE9, 0x04, 0x00, 0x00,144    0x00,                   // jmp + 4145    0xCC, 0xCC, 0xCC, 0xCC,146    0x8B, 0x44, 0x24, 0x04, // mov         eax,dword ptr [esp + 4]147    0xC3,                   // ret148};149 150const u8 kIdentityCodeWithJumpBackwards[] = {151    0x8B, 0x44, 0x24, 0x04,  // mov         eax,dword ptr [esp + 4]152    0xC3,                    // ret153    0xE9, 0xF6, 0xFF, 0xFF,154    0xFF,  // jmp - 10155    0xCC, 0xCC, 0xCC, 0xCC,156};157const u8 kIdentityCodeWithJumpBackwardsOffset = 5;158 159#    endif160 161const u8 kPatchableCode1[] = {162    0xB8, 0x4B, 0x00, 0x00, 0x00,   // mov eax,4B163    0x33, 0xC9,                     // xor ecx,ecx164    0xC3,                           // ret165};166 167const u8 kPatchableCode2[] = {168    0x55,                           // push ebp169    0x8B, 0xEC,                     // mov ebp,esp170    0x33, 0xC0,                     // xor eax,eax171    0x5D,                           // pop ebp172    0xC3,                           // ret173};174 175const u8 kPatchableCode3[] = {176    0x55,                           // push ebp177    0x8B, 0xEC,                     // mov ebp,esp178    0x6A, 0x00,                     // push 0179    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    ebp189    0x8b, 0xec,                                // mov     ebp,esp190    0x8d, 0xa4, 0x24, 0x30, 0xfd, 0xff, 0xff,  // lea     esp,[esp-2D0h]191    0x54,                                      // push    esp192};193 194#if SANITIZER_WINDOWS64195u8 kLoadGlobalCode[] = {196  0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov    eax [rip + global]197  0xC3,                               // ret198};199#endif200 201const u8 kUnpatchableCode1[] = {202    0xC3,                           // ret203};204 205const u8 kUnpatchableCode2[] = {206    0x33, 0xC9,                     // xor ecx,ecx207    0xC3,                           // ret208};209 210const u8 kUnpatchableCode3[] = {211    0x75, 0xCC,                     // jne <label>212    0x33, 0xC9,                     // xor ecx,ecx213    0xC3,                           // ret214};215 216const u8 kUnpatchableCode4[] = {217    0x74, 0xCC,                     // jne <label>218    0x33, 0xC9,                     // xor ecx,ecx219    0xC3,                           // ret220};221 222const u8 kUnpatchableCode5[] = {223    0xEB, 0x02,                     // jmp <label>224    0x33, 0xC9,                     // xor ecx,ecx225    0xC3,                           // ret226};227 228const u8 kUnpatchableCode6[] = {229    0xE8, 0xCC, 0xCC, 0xCC, 0xCC,   // call <func>230    0x90, 0x90, 0x90, 0x90,231};232 233#      if SANITIZER_WINDOWS64234const u8 kUnpatchableCode7[] = {235    0x33, 0xc0,                     // xor     eax,eax236    0x48, 0x85, 0xd2,               // test    rdx,rdx237    0x74, 0x10,                     // je      +16  (unpatchable)238};239 240const u8 kUnpatchableCode8[] = {241    0x48, 0x8b, 0xc1,               // mov     rax,rcx242    0x0f, 0xb7, 0x10,               // movzx   edx,word ptr [rax]243    0x48, 0x83, 0xc0, 0x02,         // add     rax,2244    0x66, 0x85, 0xd2,               // test    dx,dx245    0x75, 0xf4,                     // jne     -12  (unpatchable)246};247 248const u8 kUnpatchableCode9[] = {249    0x4c, 0x8b, 0xc1,               // mov     r8,rcx250    0x8a, 0x01,                     // mov     al,byte ptr [rcx]251    0x48, 0xff, 0xc1,               // inc     rcx252    0x84, 0xc0,                     // test    al,al253    0x75, 0xf7,                     // jne     -9  (unpatchable)254};255 256const u8 kPatchableCode6[] = {257    0x48, 0x89, 0x54, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], rdx258    0x33, 0xC9,                   // xor ecx,ecx259    0xC3,                         // ret260};261 262const u8 kPatchableCode7[] = {263    0x4c, 0x89, 0x4c, 0x24, 0xBB,  // mov QWORD PTR [rsp + 0xBB], r9264    0x33, 0xC9,                   // xor ecx,ecx265    0xC3,                         // ret266};267 268const u8 kPatchableCode8[] = {269    0x4c, 0x89, 0x44, 0x24, 0xBB, // mov QWORD PTR [rsp + 0xBB], r8270    0x33, 0xC9,                   // xor ecx,ecx271    0xC3,                         // ret272};273 274const u8 kPatchableCode9[] = {275    0x8a, 0x01,                     // al,byte ptr [rcx]276    0x45, 0x33, 0xc0,               // xor     r8d,r8d277    0x84, 0xc0,                     // test    al,al278};279 280const u8 kPatchableCode10[] = {281    0x45, 0x33, 0xc0,               // xor     r8d,r8d282    0x41, 0x8b, 0xc0,               // mov     eax,r8d283    0x48, 0x85, 0xd2,               // test    rdx,rdx284};285 286const u8 kPatchableCode11[] = {287    0x48, 0x83, 0xec, 0x38,         // sub     rsp,38h288    0x83, 0x64, 0x24, 0x28, 0x00,   // and     dword ptr [rsp+28h],0289};290#      endif291 292#      if !SANITIZER_WINDOWS64293const u8 kPatchableCode12[] = {294    0x55,                           // push    ebp295    0x53,                           // push    ebx296    0x57,                           // push    edi297    0x56,                           // push    esi298    0x8b, 0x6c, 0x24, 0x18,         // mov     ebp,dword ptr[esp+18h]299};300 301const u8 kPatchableCode13[] = {302    0x55,                           // push    ebp303    0x53,                           // push    ebx304    0x57,                           // push    edi305    0x56,                           // push    esi306    0x8b, 0x5c, 0x24, 0x14,         // mov     ebx,dword ptr[esp+14h]307};308#      endif309 310const u8 kPatchableCode14[] = {311    0x55,                           // push    ebp312    0x89, 0xe5,                     // mov     ebp,esp313    0x53,                           // push    ebx314    0x57,                           // push    edi315    0x56,                           // push    esi316};317 318const u8 kUnsupportedCode1[] = {319    0x0f, 0x0b,                     // ud2320    0x0f, 0x0b,                     // ud2321    0x0f, 0x0b,                     // ud2322    0x0f, 0x0b,                     // ud2323};324 325// A buffer holding the dynamically generated code under test.326u8* ActiveCode;327const size_t ActiveCodeLength = 4096;328 329int InterceptorFunction(int x);330 331/// Allocate code memory more than 2GB away from Base.332u8 *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 find339  // 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 351template<class T>352static 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_WINDOWS64384    // Note that "mov edi,edi" is NOP in 32-bit only, in 64-bit it clears385    // higher bits of RDI.386    // Use 66,90H as NOP for Windows64.387    ActiveCode[position++] = 0x66;388    ActiveCode[position++] = 0x90;389#else390    // mov edi,edi.391    ActiveCode[position++] = 0x8B;392    ActiveCode[position++] = 0xFF;393#endif394 395  }396 397  // Copy the function body.398  for (size_t i = 0; i < sizeof(T); ++i)399    ActiveCode[position++] = code[i];400}401 402int InterceptorFunctionCalled;403IdentityFunction InterceptedRealFunction;404 405int InterceptorFunction(int x) {406  ++InterceptorFunctionCalled;407  return InterceptedRealFunction(x);408}409 410}  // namespace411 412// Tests for interception_win.h413TEST(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 426template <class T>427static 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_WINDOWS64472TEST(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_WINDOWS64481 482TEST(Interception, OverrideFunctionWithRedirectJump) {483  TestOverrideFunction override = OverrideFunctionWithRedirectJump;484  TestIdentityFunctionPatching(kIdentityCodeWithJump, override);485  TestIdentityFunctionPatching(kIdentityCodeWithJumpBackwards, override,486                               FunctionPrefixNone,487                               kIdentityCodeWithJumpBackwardsOffset);488}489 490TEST(Interception, OverrideFunctionWithHotPatch) {491  TestOverrideFunction override = OverrideFunctionWithHotPatch;492  FunctionPrefixKind prefix = FunctionPrefixHotPatch;493  TestIdentityFunctionPatching(kIdentityCodeWithMov, override, prefix);494}495 496TEST(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 507TEST(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 533template<class T>534static 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 558TEST(Interception, OverrideFunctionMultiplePatchingIsFailing) {559#if !SANITIZER_WINDOWS64560  TestIdentityFunctionMultiplePatching(kIdentityCodeWithPrologue,561                                       OverrideFunctionWithDetour,562                                       FunctionPrefixDetour);563#endif564 565  TestIdentityFunctionMultiplePatching(kIdentityCodeWithMov,566                                       OverrideFunctionWithHotPatch,567                                       FunctionPrefixHotPatch);568 569  TestIdentityFunctionMultiplePatching(kIdentityCodeWithPushPop,570                                       OverrideFunctionWithTrampoline,571                                       FunctionPrefixPadding);572}573 574TEST(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 601template<class T>602static 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 616TEST(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_WINDOWS64622  EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override));623#else624  EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override));625#endif626  EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));627  EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override));628#if SANITIZER_WINDOWS64629  EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override));630#endif631 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_WINDOWS64641TEST(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_WINDOWS64669 670TEST(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 684TEST(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_WINDOWS64693  EXPECT_TRUE(TestFunctionPatching(kPatchableCode6, override, prefix));694  EXPECT_TRUE(TestFunctionPatching(kPatchableCode7, override, prefix));695  EXPECT_TRUE(TestFunctionPatching(kPatchableCode8, override, prefix));696#endif697  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 705TEST(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_WINDOWS64712  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#else720  EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));721  EXPECT_TRUE(TestFunctionPatching(kPatchableCode12, override, prefix));722  EXPECT_TRUE(TestFunctionPatching(kPatchableCode13, override, prefix));723#endif724  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 735TEST(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 772TEST(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_WINDOWS64779  EXPECT_FALSE(TestFunctionPatching(kPatchableCode3, override, prefix));780#else781  EXPECT_TRUE(TestFunctionPatching(kPatchableCode3, override, prefix));782#endif783  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 793TEST(Interception, EmptyExportTable) {794  // We try to get a pointer to a function from an executable that doesn't795  // export any symbol (empty export table).796  uptr FunPtr = InternalGetProcAddress((void *)GetModuleHandleA(0), "example");797  EXPECT_EQ(0U, FunPtr);798}799 800const struct InstructionSizeData {801  size_t size;  // hold instruction size or 0 for failure,802                // e.g. on control instructions803  u8 instr[16];804  size_t rel_offset;  // adjustment for RIP-relative addresses when copying805                      // instructions during hooking via hotpatch or trampoline.806  const char *comment;807} data[] = {808    // clang-format off809    // sorted list810    { 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, {0x33, 0xFF}, 0, "33 FF : xor edi, edi"},845    { 2, {0x31, 0xD2}, 0, "31 D2 : xor edx, edx"},846    { 2, {0x33, 0xC0}, 0, "33 C0 : xor eax, eax"},847    { 2, {0x33, 0xC9}, 0, "33 C9 : xor ecx, ecx"},848    { 2, {0x33, 0xD2}, 0, "33 D2 : xor edx, edx"},849    { 2, {0x66, 0x90}, 0, "66 90 : xchg %ax,%ax (Two-byte NOP)"},850    { 2, {0x6A, 0x71}, 0, "6A XX : push XX"},851    { 2, {0x84, 0xC0}, 0, "84 C0 : test al,al"},852    { 2, {0x84, 0xC9}, 0, "84 C9 : test cl,cl"},853    { 2, {0x84, 0xD2}, 0, "84 D2 : test dl,dl"},854    { 2, {0x84, 0xDB}, 0, "84 DB : test bl,bl"},855    { 2, {0x89, 0xc8}, 0, "89 C8 : mov eax, ecx"},856    { 2, {0x89, 0xD1}, 0, "89 D1 : mov ecx, edx"},857    { 2, {0x89, 0xE5}, 0, "89 E5 : mov ebp, esp"},858    { 2, {0x8A, 0x01}, 0, "8A 01 : mov al, byte ptr [ecx]"},859    { 2, {0x8B, 0xC1}, 0, "8B C1 : mov eax, ecx"},860    { 2, {0x8B, 0xEC}, 0, "8B EC : mov ebp, esp"},861    { 2, {0x8B, 0xFF}, 0, "8B FF : mov edi, edi"},862    { 3, {0x80, 0x39, 0x72}, 0, "80 39 XX : cmp BYTE PTR [rcx], XX"},863    { 3, {0x83, 0xE4, 0x72}, 0, "83 E4 XX : and esp, XX"},864    { 3, {0x83, 0xEC, 0x72}, 0, "83 EC XX : sub esp, XX"},865    { 3, {0x8B, 0x4D, 0x72}, 0, "8B 4D XX : mov XX(%ebp), ecx"},866    { 3, {0x8B, 0x55, 0x72}, 0, "8B 55 XX : mov XX(%ebp), edx"},867    { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov XX(%ebp), esp"},868    { 3, {0xc2, 0x71, 0x72}, 0, "C2 XX XX : ret XX (needed for registering weak functions)"},869    { 4, {0x8D, 0x4C, 0x24, 0x73}, 0, "8D 4C 24 XX : lea ecx, [esp + XX]"},870    { 4, {0xFF, 0x74, 0x24, 0x73}, 0, "FF 74 24 XX : push qword ptr [rsp + XX]"},871    { 5, {0x68, 0x71, 0x72, 0x73, 0x74}, 0, "68 XX XX XX XX : push imm32"},872    { 5, {0xb8, 0x71, 0x72, 0x73, 0x74}, 0, "b8 XX XX XX XX : mov eax, XX XX XX XX"},873    { 5, {0xB9, 0x71, 0x72, 0x73, 0x74}, 0, "b9 XX XX XX XX : mov ecx, XX XX XX XX"},874    { 5, {0xBA, 0x71, 0x72, 0x73, 0x74}, 0, "ba XX XX XX XX : mov edx, XX XX XX XX"},875    { 6, {0x81, 0xEC, 0x72, 0x73, 0x74, 0x75}, 0, "81 EC XX XX XX XX : sub esp, XX XX XX XX"},876    { 6, {0xFF, 0x89, 0x72, 0x73, 0x74, 0x75}, 0, "FF 89 XX XX XX XX : dec dword ptr [ecx + XX XX XX XX]"},877    { 7, {0x8D, 0xA4, 0x24, 0x73, 0x74, 0x75, 0x76}, 0, "8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX]"},878#if SANITIZER_WINDOWS_x64879    // sorted list880    { 2, {0x40, 0x50}, 0, "40 50 : push rax"},881    { 2, {0x40, 0x51}, 0, "40 51 : push rcx"},882    { 2, {0x40, 0x52}, 0, "40 52 : push rdx"},883    { 2, {0x40, 0x53}, 0, "40 53 : push rbx"},884    { 2, {0x40, 0x54}, 0, "40 54 : push rsp"},885    { 2, {0x40, 0x55}, 0, "40 55 : push rbp"},886    { 2, {0x40, 0x56}, 0, "40 56 : push rsi"},887    { 2, {0x40, 0x57}, 0, "40 57 : push rdi"},888    { 2, {0x41, 0x54}, 0, "41 54 : push r12"},889    { 2, {0x41, 0x55}, 0, "41 55 : push r13"},890    { 2, {0x41, 0x56}, 0, "41 56 : push r14"},891    { 2, {0x41, 0x57}, 0, "41 57 : push r15"},892    { 2, {0x84, 0xc0}, 0, "84 c0 : test al, al"},893    { 2, {0x8a, 0x01}, 0, "8a 01 : mov al, byte ptr [rcx]"},894    { 3, {0x0f, 0xb6, 0x01}, 0, "0f b6 01 : movzx eax, BYTE PTR [rcx]"},895    { 3, {0x0f, 0xb6, 0x09}, 0, "0f b6 09 : movzx ecx, BYTE PTR [rcx]"},896    { 3, {0x0f, 0xb6, 0x11}, 0, "0f b6 11 : movzx edx, BYTE PTR [rcx]"},897    { 3, {0x0f, 0xb6, 0xc2}, 0, "0f b6 c2 : movzx eax, dl"},898    { 3, {0x0f, 0xb6, 0xd2}, 0, "0f b6 d2 : movzx edx, dl"},899    { 3, {0x0f, 0xb7, 0x02}, 0, "0f b7 02 : movzx eax, WORD PTR [rdx]"},900    { 3, {0x0f, 0xb7, 0x10}, 0, "0f b7 10 : movzx edx, WORD PTR [rax]"},901    { 3, {0x0f, 0xbe, 0xd2}, 0, "0f be d2 : movsx edx, dl"},902    { 3, {0x41, 0x8b, 0xc0}, 0, "41 8b c0 : mov eax, r8d"},903    { 3, {0x41, 0x8b, 0xc1}, 0, "41 8b c1 : mov eax, r9d"},904    { 3, {0x41, 0x8b, 0xc2}, 0, "41 8b c2 : mov eax, r10d"},905    { 3, {0x41, 0x8b, 0xc3}, 0, "41 8b c3 : mov eax, r11d"},906    { 3, {0x41, 0x8b, 0xc4}, 0, "41 8b c4 : mov eax, r12d"},907    { 3, {0x45, 0x31, 0xc0}, 0, "45 31 c0 : xor r8d,r8d"},908    { 3, {0x45, 0x31, 0xc9}, 0, "45 31 c9 : xor r9d,r9d"},909    { 3, {0x45, 0x33, 0xc0}, 0, "45 33 c0 : xor r8d, r8d"},910    { 3, {0x45, 0x33, 0xc9}, 0, "45 33 c9 : xor r9d, r9d"},911    { 3, {0x45, 0x33, 0xd2}, 0, "45 33 d2 : xor r10d, r10d"},912    { 3, {0x45, 0x33, 0xdb}, 0, "45 33 db : xor r11d, r11d"},913    { 3, {0x45, 0x84, 0xc0}, 0, "45 84 c0 : test r8b,r8b"},914    { 3, {0x45, 0x84, 0xd2}, 0, "45 84 d2 : test r10b,r10b"},915    { 3, {0x48, 0x29, 0xd1}, 0, "48 29 d1 : sub rcx, rdx"},916    { 3, {0x48, 0x2b, 0xca}, 0, "48 2b ca : sub rcx, rdx"},917    { 3, {0x48, 0x2b, 0xd1}, 0, "48 2b d1 : sub rdx, rcx"},918    { 3, {0x48, 0x3b, 0xca}, 0, "48 3b ca : cmp rcx, rdx"},919    { 3, {0x48, 0x85, 0xc0}, 0, "48 85 c0 : test rax, rax"},920    { 3, {0x48, 0x85, 0xc9}, 0, "48 85 c9 : test rcx, rcx"},921    { 3, {0x48, 0x85, 0xd2}, 0, "48 85 d2 : test rdx, rdx"},922    { 3, {0x48, 0x85, 0xdb}, 0, "48 85 db : test rbx, rbx"},923    { 3, {0x48, 0x85, 0xe4}, 0, "48 85 e4 : test rsp, rsp"},924    { 3, {0x48, 0x85, 0xed}, 0, "48 85 ed : test rbp, rbp"},925    { 3, {0x48, 0x89, 0xc8}, 0, "48 89 c8 : mov rax,rcx"},926    { 3, {0x48, 0x89, 0xcb}, 0, "48 89 cb : mov rbx,rcx"},927    { 3, {0x48, 0x89, 0xd0}, 0, "48 89 d0 : mov rax,rdx"},928    { 3, {0x48, 0x89, 0xd1}, 0, "48 89 d1 : mov rcx,rdx"},929    { 3, {0x48, 0x89, 0xd3}, 0, "48 89 d3 : mov rbx,rdx"},930    { 3, {0x48, 0x89, 0xe5}, 0, "48 89 e5 : mov rbp, rsp"},931    { 3, {0x48, 0x8b, 0xc1}, 0, "48 8b c1 : mov rax, rcx"},932    { 3, {0x48, 0x8b, 0xc4}, 0, "48 8b c4 : mov rax, rsp"},933    { 3, {0x48, 0x8b, 0xd1}, 0, "48 8b d1 : mov rdx, rcx"},934    { 3, {0x48, 0xf7, 0xd9}, 0, "48 f7 d9 : neg rcx"},935    { 3, {0x48, 0xff, 0xc0}, 0, "48 ff c0 : inc rax"},936    { 3, {0x48, 0xff, 0xc1}, 0, "48 ff c1 : inc rcx"},937    { 3, {0x48, 0xff, 0xc2}, 0, "48 ff c2 : inc rdx"},938    { 3, {0x48, 0xff, 0xc3}, 0, "48 ff c3 : inc rbx"},939    { 3, {0x48, 0xff, 0xc6}, 0, "48 ff c6 : inc rsi"},940    { 3, {0x48, 0xff, 0xc7}, 0, "48 ff c7 : inc rdi"},941    { 3, {0x49, 0x89, 0xc8}, 0, "49 89 c8 : mov r8, rcx"},942    { 3, {0x49, 0x89, 0xc9}, 0, "49 89 c9 : mov r9, rcx"},943    { 3, {0x49, 0x89, 0xca}, 0, "49 89 ca : mov r10,rcx"},944    { 3, {0x49, 0x89, 0xd0}, 0, "49 89 d0 : mov r8, rdx"},945    { 3, {0x49, 0x89, 0xd1}, 0, "49 89 d1 : mov r9, rdx"},946    { 3, {0x49, 0x89, 0xd2}, 0, "49 89 d2 : mov r10, rdx"},947    { 3, {0x49, 0x89, 0xd3}, 0, "49 89 d3 : mov r11, rdx"},948    { 3, {0x49, 0xff, 0xc0}, 0, "49 ff c0 : inc r8"},949    { 3, {0x49, 0xff, 0xc1}, 0, "49 ff c1 : inc r9"},950    { 3, {0x49, 0xff, 0xc2}, 0, "49 ff c2 : inc r10"},951    { 3, {0x49, 0xff, 0xc3}, 0, "49 ff c3 : inc r11"},952    { 3, {0x49, 0xff, 0xc4}, 0, "49 ff c4 : inc r12"},953    { 3, {0x49, 0xff, 0xc5}, 0, "49 ff c5 : inc r13"},954    { 3, {0x49, 0xff, 0xc6}, 0, "49 ff c6 : inc r14"},955    { 3, {0x49, 0xff, 0xc7}, 0, "49 ff c7 : inc r15"},956    { 3, {0x4c, 0x2b, 0xc2}, 0, "4c 2b c2 : sub r8, rdx"},957    { 3, {0x4c, 0x8b, 0xc1}, 0, "4c 8b c1 : mov r8, rcx"},958    { 3, {0x4c, 0x8b, 0xc9}, 0, "4c 8b c9 : mov r9, rcx"},959    { 3, {0x4c, 0x8b, 0xd1}, 0, "4c 8b d1 : mov r10, rcx"},960    { 3, {0x4c, 0x8b, 0xd2}, 0, "4c 8b d2 : mov r10, rdx"},961    { 3, {0x4c, 0x8b, 0xd9}, 0, "4c 8b d9 : mov r11, rcx"},962    { 3, {0x4c, 0x8b, 0xdc}, 0, "4c 8b dc : mov r11, rsp"},963    { 3, {0x4d, 0x0b, 0xc0}, 0, "4d 0b c0 : or r8, r8"},964    { 3, {0x4d, 0x85, 0xc0}, 0, "4d 85 c0 : test r8, r8"},965    { 3, {0x4d, 0x85, 0xc9}, 0, "4d 85 c9 : test r9, r9"},966    { 3, {0x4d, 0x85, 0xd2}, 0, "4d 85 d2 : test r10, r10"},967    { 3, {0x4d, 0x85, 0xdb}, 0, "4d 85 db : test r11, r11"},968    { 3, {0x4d, 0x85, 0xe4}, 0, "4d 85 e4 : test r12, r12"},969    { 3, {0x4d, 0x85, 0xed}, 0, "4d 85 ed : test r13, r13"},970    { 3, {0x4d, 0x85, 0xf6}, 0, "4d 85 f6 : test r14, r14"},971    { 3, {0x4d, 0x85, 0xff}, 0, "4d 85 ff : test r15, r15"},972    { 3, {0xf6, 0xc1, 0x72}, 0, "f6 c1 XX : test cl, XX"},973    { 4, {0x44, 0x0f, 0xb6, 0x01}, 0, "44 0f b6 01 : movzx r8d, BYTE PTR [rcx]"},974    { 4, {0x44, 0x0f, 0xb6, 0x09}, 0, "44 0f b6 09 : movzx r9d, BYTE PTR [rcx]"},975    { 4, {0x44, 0x0f, 0xb6, 0x0a}, 0, "44 0f b6 0a : movzx r8d, BYTE PTR [rdx]"},976    { 4, {0x44, 0x0f, 0xb6, 0x11}, 0, "44 0f b6 11 : movzx r10d, BYTE PTR [rcx]"},977    { 4, {0x44, 0x0f, 0xb6, 0x1a}, 0, "44 0f b6 1a : movzx r11d, BYTE PTR [rdx]"},978    { 4, {0x44, 0x8d, 0x42, 0x73}, 0, "44 8d 42 XX : lea r8d , [rdx + XX]"},979    { 4, {0x48, 0x83, 0xec, 0x73}, 0, "48 83 ec XX : sub rsp, XX"},980    { 4, {0x48, 0x89, 0x58, 0x73}, 0, "48 89 58 XX : mov QWORD PTR[rax + XX], rbx"},981    { 4, {0x49, 0x83, 0xf8, 0x73}, 0, "49 83 f8 XX : cmp r8, XX"},982    { 4, {0x49, 0x8d, 0x48, 0x73}, 0, "49 8d 48 XX : lea rcx, [...]"},983    { 4, {0x4c, 0x8d, 0x04, 0x73}, 0, "4c 8d 04 XX : lea r8, [...]"},984    { 4, {0x4e, 0x8d, 0x14, 0x73}, 0, "4e 8d 14 XX : lea r10, [...]"},985    { 4, {0x66, 0x83, 0x39, 0x73}, 0, "66 83 39 XX : cmp WORD PTR [rcx], XX"},986    { 4, {0x80, 0x78, 0x72, 0x73}, 0, "80 78 YY XX : cmp BYTE PTR [rax+YY], XX"},987    { 4, {0x80, 0x79, 0x72, 0x73}, 0, "80 79 YY XX : cmp BYTE ptr [rcx+YY], XX"},988    { 4, {0x80, 0x7A, 0x72, 0x73}, 0, "80 7A YY XX : cmp BYTE PTR [rdx+YY], XX"},989    { 4, {0x80, 0x7B, 0x72, 0x73}, 0, "80 7B YY XX : cmp BYTE PTR [rbx+YY], XX"},990    { 4, {0x80, 0x7D, 0x72, 0x73}, 0, "80 7D YY XX : cmp BYTE PTR [rbp+YY], XX"},991    { 4, {0x80, 0x7E, 0x72, 0x73}, 0, "80 7E YY XX : cmp BYTE PTR [rsi+YY], XX"},992    { 4, {0x89, 0x54, 0x24, 0x73}, 0, "89 54 24 XX : mov DWORD PTR[rsp + XX], edx"},993    { 5, {0x0F, 0x1F, 0x44, 0x73, 0x74}, 0, "0F 1F 44 XX XX : nop DWORD PTR [...]"},994    { 5, {0x44, 0x89, 0x44, 0x24, 0x74}, 0, "44 89 44 24 XX : mov DWORD PTR [rsp + XX], r8d"},995    { 5, {0x44, 0x89, 0x4c, 0x24, 0x74}, 0, "44 89 4c 24 XX : mov DWORD PTR [rsp + XX], r9d"},996    { 5, {0x48, 0x89, 0x4C, 0x24, 0x74}, 0, "48 89 4C 24 XX : mov QWORD PTR [rsp + XX], rcx"},997    { 5, {0x48, 0x89, 0x54, 0x24, 0x74}, 0, "48 89 54 24 XX : mov QWORD PTR [rsp + XX], rdx"},998    { 5, {0x48, 0x89, 0x5c, 0x24, 0x74}, 0, "48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx"},999    { 5, {0x48, 0x89, 0x6c, 0x24, 0x74}, 0, "48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp"},1000    { 5, {0x48, 0x89, 0x74, 0x24, 0x74}, 0, "48 89 74 24 XX : mov QWORD PTR [rsp + XX], rsi"},1001    { 5, {0x48, 0x89, 0x7c, 0x24, 0x74}, 0, "48 89 7c 24 XX : mov QWORD PTR [rsp + XX], rdi"},1002    { 5, {0x48, 0x8b, 0x44, 0x24, 0x74}, 0, "48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX]"},1003    { 5, {0x48, 0x8d, 0x6c, 0x24, 0x74}, 0, "48 8d 6c 24 XX : lea rbp, [rsp + XX]"},1004    { 5, {0x4c, 0x89, 0x44, 0x24, 0x74}, 0, "4c 89 44 24 XX : mov QWORD PTR [rsp + XX], r8"},1005    { 5, {0x4c, 0x89, 0x4c, 0x24, 0x74}, 0, "4c 89 4c 24 XX : mov QWORD PTR [rsp + XX], r9"},1006    { 5, {0x66, 0x48, 0x0F, 0x7E, 0xC0}, 0, "66 48 0F 7E C0 : movq rax, xmm0"},1007    { 5, {0x83, 0x44, 0x72, 0x73, 0x74}, 0, "83 44 72 XX YY : add DWORD PTR [rdx+rsi*2+XX],YY"},1008    { 5, {0x83, 0x64, 0x24, 0x73, 0x74}, 0, "83 64 24 XX YY : and DWORD PTR [rsp+XX], YY"},1009    { 6, {0x41, 0xB8, 0x72, 0x73, 0x74, 0x75}, 0, "41 B8 XX XX XX XX : mov r8d, XX XX XX XX"},1010    { 6, {0x48, 0x83, 0x64, 0x24, 0x74, 0x75}, 0, "48 83 64 24 XX YY : and QWORD PTR [rsp + XX], YY"},1011    { 6, {0x66, 0x81, 0x78, 0x73, 0x74, 0x75}, 0, "66 81 78 XX YY YY : cmp WORD PTR [rax+XX], YY YY"},1012    { 6, {0x66, 0x81, 0x79, 0x73, 0x74, 0x75}, 0, "66 81 79 XX YY YY : cmp WORD PTR [rcx+XX], YY YY"},1013    { 6, {0x66, 0x81, 0x7a, 0x73, 0x74, 0x75}, 0, "66 81 7a XX YY YY : cmp WORD PTR [rdx+XX], YY YY"},1014    { 6, {0x66, 0x81, 0x7b, 0x73, 0x74, 0x75}, 0, "66 81 7b XX YY YY : cmp WORD PTR [rbx+XX], YY YY"},1015    { 6, {0x66, 0x81, 0x7e, 0x73, 0x74, 0x75}, 0, "66 81 7e XX YY YY : cmp WORD PTR [rsi+XX], YY YY"},1016    { 6, {0x66, 0x81, 0x7f, 0x73, 0x74, 0x75}, 0, "66 81 7f XX YY YY : cmp WORD PTR [rdi+XX], YY YY"},1017    { 6, {0x8A, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8A 05 XX XX XX XX : mov al, byte ptr [XX XX XX XX]"},1018    { 6, {0x8B, 0x05, 0x72, 0x73, 0x74, 0x75}, 2, "8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]"},1019    { 6, {0xF2, 0x0f, 0x11, 0x44, 0x24, 0x75}, 0, "f2 0f 11 44 24 XX : movsd QWORD PTR [rsp + XX], xmm0"},1020    { 6, {0xF2, 0x0f, 0x11, 0x4c, 0x24, 0x75}, 0, "f2 0f 11 4c 24 XX : movsd QWORD PTR [rsp + XX], xmm1"},1021    { 6, {0xF2, 0x0f, 0x11, 0x54, 0x24, 0x75}, 0, "f2 0f 11 54 24 XX : movsd QWORD PTR [rsp + XX], xmm2"},1022    { 6, {0xF2, 0x0f, 0x11, 0x5c, 0x24, 0x75}, 0, "f2 0f 11 5c 24 XX : movsd QWORD PTR [rsp + XX], xmm3"},1023    { 6, {0xF2, 0x0f, 0x11, 0x64, 0x24, 0x75}, 0, "f2 0f 11 64 24 XX : movsd QWORD PTR [rsp + XX], xmm4"},1024    { 7, {0x48, 0x81, 0xec, 0x73, 0x74, 0x75, 0x76}, 0, "48 81 EC XX XX XX XX : sub rsp, XXXXXXXX"},1025    { 7, {0x48, 0x89, 0x0d, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 0d XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rcx"},1026    { 7, {0x48, 0x89, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "48 89 15 XX XX XX XX : mov QWORD PTR [rip + XXXXXXXX], rdx"},1027    { 7, {0x48, 0x8b, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8b 05 XX XX XX XX : mov rax, QWORD PTR [rip + XXXXXXXX]"},1028    { 7, {0x48, 0x8d, 0x05, 0x73, 0x74, 0x75, 0x76}, 3, "48 8d 05 XX XX XX XX : lea rax, QWORD PTR [rip + XXXXXXXX]"},1029    { 7, {0x48, 0xc7, 0xc0, 0x73, 0x74, 0x75, 0x76}, 0, "48 C7 C0 XX XX XX XX : mov rax, XX XX XX XX"},1030    { 7, {0x48, 0xff, 0x25, 0x73, 0x74, 0x75, 0x76}, 3, "48 ff 25 XX XX XX XX : rex.W jmp QWORD PTR [rip + XXXXXXXX]"},1031    { 7, {0x4C, 0x8D, 0x15, 0x73, 0x74, 0x75, 0x76}, 3, "4c 8d 15 XX XX XX XX : lea r10, [rip + XX]"},1032    { 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"},1033    { 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"},1034    { 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"},1035    { 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"},1036    { 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"},1037    { 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"},1038    { 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"},1039    { 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"},1040    { 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"},1041    { 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"},1042    { 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"},1043    { 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"},1044    { 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"},1045    { 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]"},1046    { 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"},1047    { 8, {0xc7, 0x44, 0x24, 0x73, 0x74, 0x75, 0x76, 0x77}, 0, "C7 44 24 XX YY YY YY YY : mov dword ptr [rsp + XX], YYYYYYYY"},1048    { 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"},1049    { 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]"},1050    {10, {0x48, 0xb8, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79}, 0, "48 b8 XX XX XX XX XX XX XX XX : movabsq XX XX XX XX XX XX XX XX, rax"},1051    {10, {0x48, 0xba, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79}, 0, "48 ba XX XX XX XX XX XX XX XX : movabsq XX XX XX XX XX XX XX XX, rdx"},1052#else1053    // sorted list1054    { 3, {0x8B, 0x45, 0x72}, 0, "8B 45 XX : mov eax, dword ptr [ebp + XX]"},1055    { 3, {0x8B, 0x5D, 0x72}, 0, "8B 5D XX : mov ebx, dword ptr [ebp + XX]"},1056    { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov esi, dword ptr [ebp + XX]"},1057    { 3, {0x8B, 0x7D, 0x72}, 0, "8B 7D XX : mov edi, dword ptr [ebp + XX]"},1058    { 3, {0xFF, 0x75, 0x72}, 0, "FF 75 XX : push dword ptr [ebp + XX]"},1059    { 4, {0x83, 0x7D, 0x72, 0x73}, 0, "83 7D XX YY : cmp dword ptr [ebp + XX], YY"},1060    { 4, {0x8A, 0x44, 0x24, 0x73}, 0, "8A 44 24 XX : mov eal, dword ptr [esp + XX]"},1061    { 4, {0x8B, 0x44, 0x24, 0x73}, 0, "8B 44 24 XX : mov eax, dword ptr [esp + XX]"},1062    { 4, {0x8B, 0x4C, 0x24, 0x73}, 0, "8B 4C 24 XX : mov ecx, dword ptr [esp + XX]"},1063    { 4, {0x8B, 0x54, 0x24, 0x73}, 0, "8B 54 24 XX : mov edx, dword ptr [esp + XX]"},1064    { 4, {0x8B, 0x5C, 0x24, 0x73}, 0, "8B 5C 24 XX : mov ebx, dword ptr [esp + XX]"},1065    { 4, {0x8B, 0x6C, 0x24, 0x73}, 0, "8B 6C 24 XX : mov ebp, dword ptr [esp + XX]"},1066    { 4, {0x8B, 0x74, 0x24, 0x73}, 0, "8B 74 24 XX : mov esi, dword ptr [esp + XX]"},1067    { 4, {0x8B, 0x7C, 0x24, 0x73}, 0, "8B 7C 24 XX : mov edi, dword ptr [esp + XX]"},1068    { 5, {0x0F, 0xB6, 0x44, 0x24, 0x74}, 0, "0F B6 44 24 XX : movzx eax, byte ptr [esp + XX]"},1069    { 5, {0xA1, 0x71, 0x72, 0x73, 0x74}, 0, "A1 XX XX XX XX : mov eax, dword ptr ds:[XXXXXXXX]"},1070    { 6, {0xF7, 0xC1, 0x72, 0x73, 0x74, 0x75}, 0, "F7 C1 XX YY ZZ WW : test ecx, WWZZYYXX"},1071    { 7, {0x83, 0x3D, 0x72, 0x73, 0x74, 0x75, 0x76}, 0, "83 3D XX YY ZZ WW TT : cmp TT, WWZZYYXX"},1072#endif1073    // clang-format on1074};1075 1076std::string dumpInstruction(unsigned arrayIndex,1077                            const InstructionSizeData &data) {1078  std::stringstream ret;1079  ret << "  with arrayIndex=" << arrayIndex << " {";1080  for (size_t i = 0; i < data.size; i++) {1081    if (i > 0)1082      ret << ", ";1083    ret << "0x" << std::setfill('0') << std::setw(2) << std::right << std::hex1084        << (int)data.instr[i];1085  }1086  ret << "} " << data.comment;1087  return ret.str();1088}1089 1090TEST(Interception, GetInstructionSize) {1091  for (unsigned i = 0; i < sizeof(data) / sizeof(*data); i++) {1092    size_t rel_offset = ~0L;1093    size_t size = __interception::TestOnlyGetInstructionSize(1094        (uptr)data[i].instr, &rel_offset);1095    EXPECT_EQ(data[i].size, size) << dumpInstruction(i, data[i]);1096    EXPECT_EQ(data[i].rel_offset, rel_offset) << dumpInstruction(i, data[i]);1097  }1098}1099 1100}  // namespace __interception1101 1102#    endif  // !SANITIZER_WINDOWS_ARM641103#endif  // SANITIZER_WINDOWS1104#endif  // #if !SANITIZER_DEBUG1105