1*68d75effSDimitry Andric //===-- interception_linux.cpp ----------------------------------*- C++ -*-===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 8*68d75effSDimitry Andric // 9*68d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 10*68d75effSDimitry Andric // 11*68d75effSDimitry Andric // Windows-specific interception methods. 12*68d75effSDimitry Andric // 13*68d75effSDimitry Andric // This file is implementing several hooking techniques to intercept calls 14*68d75effSDimitry Andric // to functions. The hooks are dynamically installed by modifying the assembly 15*68d75effSDimitry Andric // code. 16*68d75effSDimitry Andric // 17*68d75effSDimitry Andric // The hooking techniques are making assumptions on the way the code is 18*68d75effSDimitry Andric // generated and are safe under these assumptions. 19*68d75effSDimitry Andric // 20*68d75effSDimitry Andric // On 64-bit architecture, there is no direct 64-bit jump instruction. To allow 21*68d75effSDimitry Andric // arbitrary branching on the whole memory space, the notion of trampoline 22*68d75effSDimitry Andric // region is used. A trampoline region is a memory space withing 2G boundary 23*68d75effSDimitry Andric // where it is safe to add custom assembly code to build 64-bit jumps. 24*68d75effSDimitry Andric // 25*68d75effSDimitry Andric // Hooking techniques 26*68d75effSDimitry Andric // ================== 27*68d75effSDimitry Andric // 28*68d75effSDimitry Andric // 1) Detour 29*68d75effSDimitry Andric // 30*68d75effSDimitry Andric // The Detour hooking technique is assuming the presence of an header with 31*68d75effSDimitry Andric // padding and an overridable 2-bytes nop instruction (mov edi, edi). The 32*68d75effSDimitry Andric // nop instruction can safely be replaced by a 2-bytes jump without any need 33*68d75effSDimitry Andric // to save the instruction. A jump to the target is encoded in the function 34*68d75effSDimitry Andric // header and the nop instruction is replaced by a short jump to the header. 35*68d75effSDimitry Andric // 36*68d75effSDimitry Andric // head: 5 x nop head: jmp <hook> 37*68d75effSDimitry Andric // func: mov edi, edi --> func: jmp short <head> 38*68d75effSDimitry Andric // [...] real: [...] 39*68d75effSDimitry Andric // 40*68d75effSDimitry Andric // This technique is only implemented on 32-bit architecture. 41*68d75effSDimitry Andric // Most of the time, Windows API are hookable with the detour technique. 42*68d75effSDimitry Andric // 43*68d75effSDimitry Andric // 2) Redirect Jump 44*68d75effSDimitry Andric // 45*68d75effSDimitry Andric // The redirect jump is applicable when the first instruction is a direct 46*68d75effSDimitry Andric // jump. The instruction is replaced by jump to the hook. 47*68d75effSDimitry Andric // 48*68d75effSDimitry Andric // func: jmp <label> --> func: jmp <hook> 49*68d75effSDimitry Andric // 50*68d75effSDimitry Andric // On an 64-bit architecture, a trampoline is inserted. 51*68d75effSDimitry Andric // 52*68d75effSDimitry Andric // func: jmp <label> --> func: jmp <tramp> 53*68d75effSDimitry Andric // [...] 54*68d75effSDimitry Andric // 55*68d75effSDimitry Andric // [trampoline] 56*68d75effSDimitry Andric // tramp: jmp QWORD [addr] 57*68d75effSDimitry Andric // addr: .bytes <hook> 58*68d75effSDimitry Andric // 59*68d75effSDimitry Andric // Note: <real> is equilavent to <label>. 60*68d75effSDimitry Andric // 61*68d75effSDimitry Andric // 3) HotPatch 62*68d75effSDimitry Andric // 63*68d75effSDimitry Andric // The HotPatch hooking is assuming the presence of an header with padding 64*68d75effSDimitry Andric // and a first instruction with at least 2-bytes. 65*68d75effSDimitry Andric // 66*68d75effSDimitry Andric // The reason to enforce the 2-bytes limitation is to provide the minimal 67*68d75effSDimitry Andric // space to encode a short jump. HotPatch technique is only rewriting one 68*68d75effSDimitry Andric // instruction to avoid breaking a sequence of instructions containing a 69*68d75effSDimitry Andric // branching target. 70*68d75effSDimitry Andric // 71*68d75effSDimitry Andric // Assumptions are enforced by MSVC compiler by using the /HOTPATCH flag. 72*68d75effSDimitry Andric // see: https://msdn.microsoft.com/en-us/library/ms173507.aspx 73*68d75effSDimitry Andric // Default padding length is 5 bytes in 32-bits and 6 bytes in 64-bits. 74*68d75effSDimitry Andric // 75*68d75effSDimitry Andric // head: 5 x nop head: jmp <hook> 76*68d75effSDimitry Andric // func: <instr> --> func: jmp short <head> 77*68d75effSDimitry Andric // [...] body: [...] 78*68d75effSDimitry Andric // 79*68d75effSDimitry Andric // [trampoline] 80*68d75effSDimitry Andric // real: <instr> 81*68d75effSDimitry Andric // jmp <body> 82*68d75effSDimitry Andric // 83*68d75effSDimitry Andric // On an 64-bit architecture: 84*68d75effSDimitry Andric // 85*68d75effSDimitry Andric // head: 6 x nop head: jmp QWORD [addr1] 86*68d75effSDimitry Andric // func: <instr> --> func: jmp short <head> 87*68d75effSDimitry Andric // [...] body: [...] 88*68d75effSDimitry Andric // 89*68d75effSDimitry Andric // [trampoline] 90*68d75effSDimitry Andric // addr1: .bytes <hook> 91*68d75effSDimitry Andric // real: <instr> 92*68d75effSDimitry Andric // jmp QWORD [addr2] 93*68d75effSDimitry Andric // addr2: .bytes <body> 94*68d75effSDimitry Andric // 95*68d75effSDimitry Andric // 4) Trampoline 96*68d75effSDimitry Andric // 97*68d75effSDimitry Andric // The Trampoline hooking technique is the most aggressive one. It is 98*68d75effSDimitry Andric // assuming that there is a sequence of instructions that can be safely 99*68d75effSDimitry Andric // replaced by a jump (enough room and no incoming branches). 100*68d75effSDimitry Andric // 101*68d75effSDimitry Andric // Unfortunately, these assumptions can't be safely presumed and code may 102*68d75effSDimitry Andric // be broken after hooking. 103*68d75effSDimitry Andric // 104*68d75effSDimitry Andric // func: <instr> --> func: jmp <hook> 105*68d75effSDimitry Andric // <instr> 106*68d75effSDimitry Andric // [...] body: [...] 107*68d75effSDimitry Andric // 108*68d75effSDimitry Andric // [trampoline] 109*68d75effSDimitry Andric // real: <instr> 110*68d75effSDimitry Andric // <instr> 111*68d75effSDimitry Andric // jmp <body> 112*68d75effSDimitry Andric // 113*68d75effSDimitry Andric // On an 64-bit architecture: 114*68d75effSDimitry Andric // 115*68d75effSDimitry Andric // func: <instr> --> func: jmp QWORD [addr1] 116*68d75effSDimitry Andric // <instr> 117*68d75effSDimitry Andric // [...] body: [...] 118*68d75effSDimitry Andric // 119*68d75effSDimitry Andric // [trampoline] 120*68d75effSDimitry Andric // addr1: .bytes <hook> 121*68d75effSDimitry Andric // real: <instr> 122*68d75effSDimitry Andric // <instr> 123*68d75effSDimitry Andric // jmp QWORD [addr2] 124*68d75effSDimitry Andric // addr2: .bytes <body> 125*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 126*68d75effSDimitry Andric 127*68d75effSDimitry Andric #include "interception.h" 128*68d75effSDimitry Andric 129*68d75effSDimitry Andric #if SANITIZER_WINDOWS 130*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h" 131*68d75effSDimitry Andric #define WIN32_LEAN_AND_MEAN 132*68d75effSDimitry Andric #include <windows.h> 133*68d75effSDimitry Andric 134*68d75effSDimitry Andric namespace __interception { 135*68d75effSDimitry Andric 136*68d75effSDimitry Andric static const int kAddressLength = FIRST_32_SECOND_64(4, 8); 137*68d75effSDimitry Andric static const int kJumpInstructionLength = 5; 138*68d75effSDimitry Andric static const int kShortJumpInstructionLength = 2; 139*68d75effSDimitry Andric static const int kIndirectJumpInstructionLength = 6; 140*68d75effSDimitry Andric static const int kBranchLength = 141*68d75effSDimitry Andric FIRST_32_SECOND_64(kJumpInstructionLength, kIndirectJumpInstructionLength); 142*68d75effSDimitry Andric static const int kDirectBranchLength = kBranchLength + kAddressLength; 143*68d75effSDimitry Andric 144*68d75effSDimitry Andric static void InterceptionFailed() { 145*68d75effSDimitry Andric // Do we have a good way to abort with an error message here? 146*68d75effSDimitry Andric __debugbreak(); 147*68d75effSDimitry Andric } 148*68d75effSDimitry Andric 149*68d75effSDimitry Andric static bool DistanceIsWithin2Gig(uptr from, uptr target) { 150*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 151*68d75effSDimitry Andric if (from < target) 152*68d75effSDimitry Andric return target - from <= (uptr)0x7FFFFFFFU; 153*68d75effSDimitry Andric else 154*68d75effSDimitry Andric return from - target <= (uptr)0x80000000U; 155*68d75effSDimitry Andric #else 156*68d75effSDimitry Andric // In a 32-bit address space, the address calculation will wrap, so this check 157*68d75effSDimitry Andric // is unnecessary. 158*68d75effSDimitry Andric return true; 159*68d75effSDimitry Andric #endif 160*68d75effSDimitry Andric } 161*68d75effSDimitry Andric 162*68d75effSDimitry Andric static uptr GetMmapGranularity() { 163*68d75effSDimitry Andric SYSTEM_INFO si; 164*68d75effSDimitry Andric GetSystemInfo(&si); 165*68d75effSDimitry Andric return si.dwAllocationGranularity; 166*68d75effSDimitry Andric } 167*68d75effSDimitry Andric 168*68d75effSDimitry Andric static uptr RoundUpTo(uptr size, uptr boundary) { 169*68d75effSDimitry Andric return (size + boundary - 1) & ~(boundary - 1); 170*68d75effSDimitry Andric } 171*68d75effSDimitry Andric 172*68d75effSDimitry Andric // FIXME: internal_str* and internal_mem* functions should be moved from the 173*68d75effSDimitry Andric // ASan sources into interception/. 174*68d75effSDimitry Andric 175*68d75effSDimitry Andric static size_t _strlen(const char *str) { 176*68d75effSDimitry Andric const char* p = str; 177*68d75effSDimitry Andric while (*p != '\0') ++p; 178*68d75effSDimitry Andric return p - str; 179*68d75effSDimitry Andric } 180*68d75effSDimitry Andric 181*68d75effSDimitry Andric static char* _strchr(char* str, char c) { 182*68d75effSDimitry Andric while (*str) { 183*68d75effSDimitry Andric if (*str == c) 184*68d75effSDimitry Andric return str; 185*68d75effSDimitry Andric ++str; 186*68d75effSDimitry Andric } 187*68d75effSDimitry Andric return nullptr; 188*68d75effSDimitry Andric } 189*68d75effSDimitry Andric 190*68d75effSDimitry Andric static void _memset(void *p, int value, size_t sz) { 191*68d75effSDimitry Andric for (size_t i = 0; i < sz; ++i) 192*68d75effSDimitry Andric ((char*)p)[i] = (char)value; 193*68d75effSDimitry Andric } 194*68d75effSDimitry Andric 195*68d75effSDimitry Andric static void _memcpy(void *dst, void *src, size_t sz) { 196*68d75effSDimitry Andric char *dst_c = (char*)dst, 197*68d75effSDimitry Andric *src_c = (char*)src; 198*68d75effSDimitry Andric for (size_t i = 0; i < sz; ++i) 199*68d75effSDimitry Andric dst_c[i] = src_c[i]; 200*68d75effSDimitry Andric } 201*68d75effSDimitry Andric 202*68d75effSDimitry Andric static bool ChangeMemoryProtection( 203*68d75effSDimitry Andric uptr address, uptr size, DWORD *old_protection) { 204*68d75effSDimitry Andric return ::VirtualProtect((void*)address, size, 205*68d75effSDimitry Andric PAGE_EXECUTE_READWRITE, 206*68d75effSDimitry Andric old_protection) != FALSE; 207*68d75effSDimitry Andric } 208*68d75effSDimitry Andric 209*68d75effSDimitry Andric static bool RestoreMemoryProtection( 210*68d75effSDimitry Andric uptr address, uptr size, DWORD old_protection) { 211*68d75effSDimitry Andric DWORD unused; 212*68d75effSDimitry Andric return ::VirtualProtect((void*)address, size, 213*68d75effSDimitry Andric old_protection, 214*68d75effSDimitry Andric &unused) != FALSE; 215*68d75effSDimitry Andric } 216*68d75effSDimitry Andric 217*68d75effSDimitry Andric static bool IsMemoryPadding(uptr address, uptr size) { 218*68d75effSDimitry Andric u8* function = (u8*)address; 219*68d75effSDimitry Andric for (size_t i = 0; i < size; ++i) 220*68d75effSDimitry Andric if (function[i] != 0x90 && function[i] != 0xCC) 221*68d75effSDimitry Andric return false; 222*68d75effSDimitry Andric return true; 223*68d75effSDimitry Andric } 224*68d75effSDimitry Andric 225*68d75effSDimitry Andric static const u8 kHintNop8Bytes[] = { 226*68d75effSDimitry Andric 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 227*68d75effSDimitry Andric }; 228*68d75effSDimitry Andric 229*68d75effSDimitry Andric template<class T> 230*68d75effSDimitry Andric static bool FunctionHasPrefix(uptr address, const T &pattern) { 231*68d75effSDimitry Andric u8* function = (u8*)address - sizeof(pattern); 232*68d75effSDimitry Andric for (size_t i = 0; i < sizeof(pattern); ++i) 233*68d75effSDimitry Andric if (function[i] != pattern[i]) 234*68d75effSDimitry Andric return false; 235*68d75effSDimitry Andric return true; 236*68d75effSDimitry Andric } 237*68d75effSDimitry Andric 238*68d75effSDimitry Andric static bool FunctionHasPadding(uptr address, uptr size) { 239*68d75effSDimitry Andric if (IsMemoryPadding(address - size, size)) 240*68d75effSDimitry Andric return true; 241*68d75effSDimitry Andric if (size <= sizeof(kHintNop8Bytes) && 242*68d75effSDimitry Andric FunctionHasPrefix(address, kHintNop8Bytes)) 243*68d75effSDimitry Andric return true; 244*68d75effSDimitry Andric return false; 245*68d75effSDimitry Andric } 246*68d75effSDimitry Andric 247*68d75effSDimitry Andric static void WritePadding(uptr from, uptr size) { 248*68d75effSDimitry Andric _memset((void*)from, 0xCC, (size_t)size); 249*68d75effSDimitry Andric } 250*68d75effSDimitry Andric 251*68d75effSDimitry Andric static void WriteJumpInstruction(uptr from, uptr target) { 252*68d75effSDimitry Andric if (!DistanceIsWithin2Gig(from + kJumpInstructionLength, target)) 253*68d75effSDimitry Andric InterceptionFailed(); 254*68d75effSDimitry Andric ptrdiff_t offset = target - from - kJumpInstructionLength; 255*68d75effSDimitry Andric *(u8*)from = 0xE9; 256*68d75effSDimitry Andric *(u32*)(from + 1) = offset; 257*68d75effSDimitry Andric } 258*68d75effSDimitry Andric 259*68d75effSDimitry Andric static void WriteShortJumpInstruction(uptr from, uptr target) { 260*68d75effSDimitry Andric sptr offset = target - from - kShortJumpInstructionLength; 261*68d75effSDimitry Andric if (offset < -128 || offset > 127) 262*68d75effSDimitry Andric InterceptionFailed(); 263*68d75effSDimitry Andric *(u8*)from = 0xEB; 264*68d75effSDimitry Andric *(u8*)(from + 1) = (u8)offset; 265*68d75effSDimitry Andric } 266*68d75effSDimitry Andric 267*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 268*68d75effSDimitry Andric static void WriteIndirectJumpInstruction(uptr from, uptr indirect_target) { 269*68d75effSDimitry Andric // jmp [rip + <offset>] = FF 25 <offset> where <offset> is a relative 270*68d75effSDimitry Andric // offset. 271*68d75effSDimitry Andric // The offset is the distance from then end of the jump instruction to the 272*68d75effSDimitry Andric // memory location containing the targeted address. The displacement is still 273*68d75effSDimitry Andric // 32-bit in x64, so indirect_target must be located within +/- 2GB range. 274*68d75effSDimitry Andric int offset = indirect_target - from - kIndirectJumpInstructionLength; 275*68d75effSDimitry Andric if (!DistanceIsWithin2Gig(from + kIndirectJumpInstructionLength, 276*68d75effSDimitry Andric indirect_target)) { 277*68d75effSDimitry Andric InterceptionFailed(); 278*68d75effSDimitry Andric } 279*68d75effSDimitry Andric *(u16*)from = 0x25FF; 280*68d75effSDimitry Andric *(u32*)(from + 2) = offset; 281*68d75effSDimitry Andric } 282*68d75effSDimitry Andric #endif 283*68d75effSDimitry Andric 284*68d75effSDimitry Andric static void WriteBranch( 285*68d75effSDimitry Andric uptr from, uptr indirect_target, uptr target) { 286*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 287*68d75effSDimitry Andric WriteIndirectJumpInstruction(from, indirect_target); 288*68d75effSDimitry Andric *(u64*)indirect_target = target; 289*68d75effSDimitry Andric #else 290*68d75effSDimitry Andric (void)indirect_target; 291*68d75effSDimitry Andric WriteJumpInstruction(from, target); 292*68d75effSDimitry Andric #endif 293*68d75effSDimitry Andric } 294*68d75effSDimitry Andric 295*68d75effSDimitry Andric static void WriteDirectBranch(uptr from, uptr target) { 296*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 297*68d75effSDimitry Andric // Emit an indirect jump through immediately following bytes: 298*68d75effSDimitry Andric // jmp [rip + kBranchLength] 299*68d75effSDimitry Andric // .quad <target> 300*68d75effSDimitry Andric WriteBranch(from, from + kBranchLength, target); 301*68d75effSDimitry Andric #else 302*68d75effSDimitry Andric WriteJumpInstruction(from, target); 303*68d75effSDimitry Andric #endif 304*68d75effSDimitry Andric } 305*68d75effSDimitry Andric 306*68d75effSDimitry Andric struct TrampolineMemoryRegion { 307*68d75effSDimitry Andric uptr content; 308*68d75effSDimitry Andric uptr allocated_size; 309*68d75effSDimitry Andric uptr max_size; 310*68d75effSDimitry Andric }; 311*68d75effSDimitry Andric 312*68d75effSDimitry Andric static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig 313*68d75effSDimitry Andric static const int kMaxTrampolineRegion = 1024; 314*68d75effSDimitry Andric static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion]; 315*68d75effSDimitry Andric 316*68d75effSDimitry Andric static void *AllocateTrampolineRegion(uptr image_address, size_t granularity) { 317*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 318*68d75effSDimitry Andric uptr address = image_address; 319*68d75effSDimitry Andric uptr scanned = 0; 320*68d75effSDimitry Andric while (scanned < kTrampolineScanLimitRange) { 321*68d75effSDimitry Andric MEMORY_BASIC_INFORMATION info; 322*68d75effSDimitry Andric if (!::VirtualQuery((void*)address, &info, sizeof(info))) 323*68d75effSDimitry Andric return nullptr; 324*68d75effSDimitry Andric 325*68d75effSDimitry Andric // Check whether a region can be allocated at |address|. 326*68d75effSDimitry Andric if (info.State == MEM_FREE && info.RegionSize >= granularity) { 327*68d75effSDimitry Andric void *page = ::VirtualAlloc((void*)RoundUpTo(address, granularity), 328*68d75effSDimitry Andric granularity, 329*68d75effSDimitry Andric MEM_RESERVE | MEM_COMMIT, 330*68d75effSDimitry Andric PAGE_EXECUTE_READWRITE); 331*68d75effSDimitry Andric return page; 332*68d75effSDimitry Andric } 333*68d75effSDimitry Andric 334*68d75effSDimitry Andric // Move to the next region. 335*68d75effSDimitry Andric address = (uptr)info.BaseAddress + info.RegionSize; 336*68d75effSDimitry Andric scanned += info.RegionSize; 337*68d75effSDimitry Andric } 338*68d75effSDimitry Andric return nullptr; 339*68d75effSDimitry Andric #else 340*68d75effSDimitry Andric return ::VirtualAlloc(nullptr, 341*68d75effSDimitry Andric granularity, 342*68d75effSDimitry Andric MEM_RESERVE | MEM_COMMIT, 343*68d75effSDimitry Andric PAGE_EXECUTE_READWRITE); 344*68d75effSDimitry Andric #endif 345*68d75effSDimitry Andric } 346*68d75effSDimitry Andric 347*68d75effSDimitry Andric // Used by unittests to release mapped memory space. 348*68d75effSDimitry Andric void TestOnlyReleaseTrampolineRegions() { 349*68d75effSDimitry Andric for (size_t bucket = 0; bucket < kMaxTrampolineRegion; ++bucket) { 350*68d75effSDimitry Andric TrampolineMemoryRegion *current = &TrampolineRegions[bucket]; 351*68d75effSDimitry Andric if (current->content == 0) 352*68d75effSDimitry Andric return; 353*68d75effSDimitry Andric ::VirtualFree((void*)current->content, 0, MEM_RELEASE); 354*68d75effSDimitry Andric current->content = 0; 355*68d75effSDimitry Andric } 356*68d75effSDimitry Andric } 357*68d75effSDimitry Andric 358*68d75effSDimitry Andric static uptr AllocateMemoryForTrampoline(uptr image_address, size_t size) { 359*68d75effSDimitry Andric // Find a region within 2G with enough space to allocate |size| bytes. 360*68d75effSDimitry Andric TrampolineMemoryRegion *region = nullptr; 361*68d75effSDimitry Andric for (size_t bucket = 0; bucket < kMaxTrampolineRegion; ++bucket) { 362*68d75effSDimitry Andric TrampolineMemoryRegion* current = &TrampolineRegions[bucket]; 363*68d75effSDimitry Andric if (current->content == 0) { 364*68d75effSDimitry Andric // No valid region found, allocate a new region. 365*68d75effSDimitry Andric size_t bucket_size = GetMmapGranularity(); 366*68d75effSDimitry Andric void *content = AllocateTrampolineRegion(image_address, bucket_size); 367*68d75effSDimitry Andric if (content == nullptr) 368*68d75effSDimitry Andric return 0U; 369*68d75effSDimitry Andric 370*68d75effSDimitry Andric current->content = (uptr)content; 371*68d75effSDimitry Andric current->allocated_size = 0; 372*68d75effSDimitry Andric current->max_size = bucket_size; 373*68d75effSDimitry Andric region = current; 374*68d75effSDimitry Andric break; 375*68d75effSDimitry Andric } else if (current->max_size - current->allocated_size > size) { 376*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 377*68d75effSDimitry Andric // In 64-bits, the memory space must be allocated within 2G boundary. 378*68d75effSDimitry Andric uptr next_address = current->content + current->allocated_size; 379*68d75effSDimitry Andric if (next_address < image_address || 380*68d75effSDimitry Andric next_address - image_address >= 0x7FFF0000) 381*68d75effSDimitry Andric continue; 382*68d75effSDimitry Andric #endif 383*68d75effSDimitry Andric // The space can be allocated in the current region. 384*68d75effSDimitry Andric region = current; 385*68d75effSDimitry Andric break; 386*68d75effSDimitry Andric } 387*68d75effSDimitry Andric } 388*68d75effSDimitry Andric 389*68d75effSDimitry Andric // Failed to find a region. 390*68d75effSDimitry Andric if (region == nullptr) 391*68d75effSDimitry Andric return 0U; 392*68d75effSDimitry Andric 393*68d75effSDimitry Andric // Allocate the space in the current region. 394*68d75effSDimitry Andric uptr allocated_space = region->content + region->allocated_size; 395*68d75effSDimitry Andric region->allocated_size += size; 396*68d75effSDimitry Andric WritePadding(allocated_space, size); 397*68d75effSDimitry Andric 398*68d75effSDimitry Andric return allocated_space; 399*68d75effSDimitry Andric } 400*68d75effSDimitry Andric 401*68d75effSDimitry Andric // Returns 0 on error. 402*68d75effSDimitry Andric static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { 403*68d75effSDimitry Andric switch (*(u64*)address) { 404*68d75effSDimitry Andric case 0x90909090909006EB: // stub: jmp over 6 x nop. 405*68d75effSDimitry Andric return 8; 406*68d75effSDimitry Andric } 407*68d75effSDimitry Andric 408*68d75effSDimitry Andric switch (*(u8*)address) { 409*68d75effSDimitry Andric case 0x90: // 90 : nop 410*68d75effSDimitry Andric return 1; 411*68d75effSDimitry Andric 412*68d75effSDimitry Andric case 0x50: // push eax / rax 413*68d75effSDimitry Andric case 0x51: // push ecx / rcx 414*68d75effSDimitry Andric case 0x52: // push edx / rdx 415*68d75effSDimitry Andric case 0x53: // push ebx / rbx 416*68d75effSDimitry Andric case 0x54: // push esp / rsp 417*68d75effSDimitry Andric case 0x55: // push ebp / rbp 418*68d75effSDimitry Andric case 0x56: // push esi / rsi 419*68d75effSDimitry Andric case 0x57: // push edi / rdi 420*68d75effSDimitry Andric case 0x5D: // pop ebp / rbp 421*68d75effSDimitry Andric return 1; 422*68d75effSDimitry Andric 423*68d75effSDimitry Andric case 0x6A: // 6A XX = push XX 424*68d75effSDimitry Andric return 2; 425*68d75effSDimitry Andric 426*68d75effSDimitry Andric case 0xb8: // b8 XX XX XX XX : mov eax, XX XX XX XX 427*68d75effSDimitry Andric case 0xB9: // b9 XX XX XX XX : mov ecx, XX XX XX XX 428*68d75effSDimitry Andric return 5; 429*68d75effSDimitry Andric 430*68d75effSDimitry Andric // Cannot overwrite control-instruction. Return 0 to indicate failure. 431*68d75effSDimitry Andric case 0xE9: // E9 XX XX XX XX : jmp <label> 432*68d75effSDimitry Andric case 0xE8: // E8 XX XX XX XX : call <func> 433*68d75effSDimitry Andric case 0xC3: // C3 : ret 434*68d75effSDimitry Andric case 0xEB: // EB XX : jmp XX (short jump) 435*68d75effSDimitry Andric case 0x70: // 7Y YY : jy XX (short conditional jump) 436*68d75effSDimitry Andric case 0x71: 437*68d75effSDimitry Andric case 0x72: 438*68d75effSDimitry Andric case 0x73: 439*68d75effSDimitry Andric case 0x74: 440*68d75effSDimitry Andric case 0x75: 441*68d75effSDimitry Andric case 0x76: 442*68d75effSDimitry Andric case 0x77: 443*68d75effSDimitry Andric case 0x78: 444*68d75effSDimitry Andric case 0x79: 445*68d75effSDimitry Andric case 0x7A: 446*68d75effSDimitry Andric case 0x7B: 447*68d75effSDimitry Andric case 0x7C: 448*68d75effSDimitry Andric case 0x7D: 449*68d75effSDimitry Andric case 0x7E: 450*68d75effSDimitry Andric case 0x7F: 451*68d75effSDimitry Andric return 0; 452*68d75effSDimitry Andric } 453*68d75effSDimitry Andric 454*68d75effSDimitry Andric switch (*(u16*)(address)) { 455*68d75effSDimitry Andric case 0x018A: // 8A 01 : mov al, byte ptr [ecx] 456*68d75effSDimitry Andric case 0xFF8B: // 8B FF : mov edi, edi 457*68d75effSDimitry Andric case 0xEC8B: // 8B EC : mov ebp, esp 458*68d75effSDimitry Andric case 0xc889: // 89 C8 : mov eax, ecx 459*68d75effSDimitry Andric case 0xC18B: // 8B C1 : mov eax, ecx 460*68d75effSDimitry Andric case 0xC033: // 33 C0 : xor eax, eax 461*68d75effSDimitry Andric case 0xC933: // 33 C9 : xor ecx, ecx 462*68d75effSDimitry Andric case 0xD233: // 33 D2 : xor edx, edx 463*68d75effSDimitry Andric return 2; 464*68d75effSDimitry Andric 465*68d75effSDimitry Andric // Cannot overwrite control-instruction. Return 0 to indicate failure. 466*68d75effSDimitry Andric case 0x25FF: // FF 25 XX XX XX XX : jmp [XXXXXXXX] 467*68d75effSDimitry Andric return 0; 468*68d75effSDimitry Andric } 469*68d75effSDimitry Andric 470*68d75effSDimitry Andric switch (0x00FFFFFF & *(u32*)address) { 471*68d75effSDimitry Andric case 0x24A48D: // 8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX] 472*68d75effSDimitry Andric return 7; 473*68d75effSDimitry Andric } 474*68d75effSDimitry Andric 475*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 476*68d75effSDimitry Andric switch (*(u8*)address) { 477*68d75effSDimitry Andric case 0xA1: // A1 XX XX XX XX XX XX XX XX : 478*68d75effSDimitry Andric // movabs eax, dword ptr ds:[XXXXXXXX] 479*68d75effSDimitry Andric return 9; 480*68d75effSDimitry Andric } 481*68d75effSDimitry Andric 482*68d75effSDimitry Andric switch (*(u16*)address) { 483*68d75effSDimitry Andric case 0x5040: // push rax 484*68d75effSDimitry Andric case 0x5140: // push rcx 485*68d75effSDimitry Andric case 0x5240: // push rdx 486*68d75effSDimitry Andric case 0x5340: // push rbx 487*68d75effSDimitry Andric case 0x5440: // push rsp 488*68d75effSDimitry Andric case 0x5540: // push rbp 489*68d75effSDimitry Andric case 0x5640: // push rsi 490*68d75effSDimitry Andric case 0x5740: // push rdi 491*68d75effSDimitry Andric case 0x5441: // push r12 492*68d75effSDimitry Andric case 0x5541: // push r13 493*68d75effSDimitry Andric case 0x5641: // push r14 494*68d75effSDimitry Andric case 0x5741: // push r15 495*68d75effSDimitry Andric case 0x9066: // Two-byte NOP 496*68d75effSDimitry Andric return 2; 497*68d75effSDimitry Andric 498*68d75effSDimitry Andric case 0x058B: // 8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX] 499*68d75effSDimitry Andric if (rel_offset) 500*68d75effSDimitry Andric *rel_offset = 2; 501*68d75effSDimitry Andric return 6; 502*68d75effSDimitry Andric } 503*68d75effSDimitry Andric 504*68d75effSDimitry Andric switch (0x00FFFFFF & *(u32*)address) { 505*68d75effSDimitry Andric case 0xe58948: // 48 8b c4 : mov rbp, rsp 506*68d75effSDimitry Andric case 0xc18b48: // 48 8b c1 : mov rax, rcx 507*68d75effSDimitry Andric case 0xc48b48: // 48 8b c4 : mov rax, rsp 508*68d75effSDimitry Andric case 0xd9f748: // 48 f7 d9 : neg rcx 509*68d75effSDimitry Andric case 0xd12b48: // 48 2b d1 : sub rdx, rcx 510*68d75effSDimitry Andric case 0x07c1f6: // f6 c1 07 : test cl, 0x7 511*68d75effSDimitry Andric case 0xc98548: // 48 85 C9 : test rcx, rcx 512*68d75effSDimitry Andric case 0xc0854d: // 4d 85 c0 : test r8, r8 513*68d75effSDimitry Andric case 0xc2b60f: // 0f b6 c2 : movzx eax, dl 514*68d75effSDimitry Andric case 0xc03345: // 45 33 c0 : xor r8d, r8d 515*68d75effSDimitry Andric case 0xc93345: // 45 33 c9 : xor r9d, r9d 516*68d75effSDimitry Andric case 0xdb3345: // 45 33 DB : xor r11d, r11d 517*68d75effSDimitry Andric case 0xd98b4c: // 4c 8b d9 : mov r11, rcx 518*68d75effSDimitry Andric case 0xd28b4c: // 4c 8b d2 : mov r10, rdx 519*68d75effSDimitry Andric case 0xc98b4c: // 4C 8B C9 : mov r9, rcx 520*68d75effSDimitry Andric case 0xc18b4c: // 4C 8B C1 : mov r8, rcx 521*68d75effSDimitry Andric case 0xd2b60f: // 0f b6 d2 : movzx edx, dl 522*68d75effSDimitry Andric case 0xca2b48: // 48 2b ca : sub rcx, rdx 523*68d75effSDimitry Andric case 0x10b70f: // 0f b7 10 : movzx edx, WORD PTR [rax] 524*68d75effSDimitry Andric case 0xc00b4d: // 3d 0b c0 : or r8, r8 525*68d75effSDimitry Andric case 0xd18b48: // 48 8b d1 : mov rdx, rcx 526*68d75effSDimitry Andric case 0xdc8b4c: // 4c 8b dc : mov r11, rsp 527*68d75effSDimitry Andric case 0xd18b4c: // 4c 8b d1 : mov r10, rcx 528*68d75effSDimitry Andric case 0xE0E483: // 83 E4 E0 : and esp, 0xFFFFFFE0 529*68d75effSDimitry Andric return 3; 530*68d75effSDimitry Andric 531*68d75effSDimitry Andric case 0xec8348: // 48 83 ec XX : sub rsp, XX 532*68d75effSDimitry Andric case 0xf88349: // 49 83 f8 XX : cmp r8, XX 533*68d75effSDimitry Andric case 0x588948: // 48 89 58 XX : mov QWORD PTR[rax + XX], rbx 534*68d75effSDimitry Andric return 4; 535*68d75effSDimitry Andric 536*68d75effSDimitry Andric case 0xec8148: // 48 81 EC XX XX XX XX : sub rsp, XXXXXXXX 537*68d75effSDimitry Andric return 7; 538*68d75effSDimitry Andric 539*68d75effSDimitry Andric case 0x058b48: // 48 8b 05 XX XX XX XX : 540*68d75effSDimitry Andric // mov rax, QWORD PTR [rip + XXXXXXXX] 541*68d75effSDimitry Andric case 0x25ff48: // 48 ff 25 XX XX XX XX : 542*68d75effSDimitry Andric // rex.W jmp QWORD PTR [rip + XXXXXXXX] 543*68d75effSDimitry Andric 544*68d75effSDimitry Andric // Instructions having offset relative to 'rip' need offset adjustment. 545*68d75effSDimitry Andric if (rel_offset) 546*68d75effSDimitry Andric *rel_offset = 3; 547*68d75effSDimitry Andric return 7; 548*68d75effSDimitry Andric 549*68d75effSDimitry Andric case 0x2444c7: // C7 44 24 XX YY YY YY YY 550*68d75effSDimitry Andric // mov dword ptr [rsp + XX], YYYYYYYY 551*68d75effSDimitry Andric return 8; 552*68d75effSDimitry Andric } 553*68d75effSDimitry Andric 554*68d75effSDimitry Andric switch (*(u32*)(address)) { 555*68d75effSDimitry Andric case 0x24448b48: // 48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX] 556*68d75effSDimitry Andric case 0x246c8948: // 48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp 557*68d75effSDimitry Andric case 0x245c8948: // 48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx 558*68d75effSDimitry Andric case 0x24748948: // 48 89 74 24 XX : mov QWORD PTR [rsp + XX], rsi 559*68d75effSDimitry Andric case 0x244C8948: // 48 89 4C 24 XX : mov QWORD PTR [rsp + XX], rcx 560*68d75effSDimitry Andric case 0x24548948: // 48 89 54 24 XX : mov QWORD PTR [rsp + XX], rdx 561*68d75effSDimitry Andric case 0x244c894c: // 4c 89 4c 24 XX : mov QWORD PTR [rsp + XX], r9 562*68d75effSDimitry Andric case 0x2444894c: // 4c 89 44 24 XX : mov QWORD PTR [rsp + XX], r8 563*68d75effSDimitry Andric return 5; 564*68d75effSDimitry Andric case 0x24648348: // 48 83 64 24 XX : and QWORD PTR [rsp + XX], YY 565*68d75effSDimitry Andric return 6; 566*68d75effSDimitry Andric } 567*68d75effSDimitry Andric 568*68d75effSDimitry Andric #else 569*68d75effSDimitry Andric 570*68d75effSDimitry Andric switch (*(u8*)address) { 571*68d75effSDimitry Andric case 0xA1: // A1 XX XX XX XX : mov eax, dword ptr ds:[XXXXXXXX] 572*68d75effSDimitry Andric return 5; 573*68d75effSDimitry Andric } 574*68d75effSDimitry Andric switch (*(u16*)address) { 575*68d75effSDimitry Andric case 0x458B: // 8B 45 XX : mov eax, dword ptr [ebp + XX] 576*68d75effSDimitry Andric case 0x5D8B: // 8B 5D XX : mov ebx, dword ptr [ebp + XX] 577*68d75effSDimitry Andric case 0x7D8B: // 8B 7D XX : mov edi, dword ptr [ebp + XX] 578*68d75effSDimitry Andric case 0xEC83: // 83 EC XX : sub esp, XX 579*68d75effSDimitry Andric case 0x75FF: // FF 75 XX : push dword ptr [ebp + XX] 580*68d75effSDimitry Andric return 3; 581*68d75effSDimitry Andric case 0xC1F7: // F7 C1 XX YY ZZ WW : test ecx, WWZZYYXX 582*68d75effSDimitry Andric case 0x25FF: // FF 25 XX YY ZZ WW : jmp dword ptr ds:[WWZZYYXX] 583*68d75effSDimitry Andric return 6; 584*68d75effSDimitry Andric case 0x3D83: // 83 3D XX YY ZZ WW TT : cmp TT, WWZZYYXX 585*68d75effSDimitry Andric return 7; 586*68d75effSDimitry Andric case 0x7D83: // 83 7D XX YY : cmp dword ptr [ebp + XX], YY 587*68d75effSDimitry Andric return 4; 588*68d75effSDimitry Andric } 589*68d75effSDimitry Andric 590*68d75effSDimitry Andric switch (0x00FFFFFF & *(u32*)address) { 591*68d75effSDimitry Andric case 0x24448A: // 8A 44 24 XX : mov eal, dword ptr [esp + XX] 592*68d75effSDimitry Andric case 0x24448B: // 8B 44 24 XX : mov eax, dword ptr [esp + XX] 593*68d75effSDimitry Andric case 0x244C8B: // 8B 4C 24 XX : mov ecx, dword ptr [esp + XX] 594*68d75effSDimitry Andric case 0x24548B: // 8B 54 24 XX : mov edx, dword ptr [esp + XX] 595*68d75effSDimitry Andric case 0x24748B: // 8B 74 24 XX : mov esi, dword ptr [esp + XX] 596*68d75effSDimitry Andric case 0x247C8B: // 8B 7C 24 XX : mov edi, dword ptr [esp + XX] 597*68d75effSDimitry Andric return 4; 598*68d75effSDimitry Andric } 599*68d75effSDimitry Andric 600*68d75effSDimitry Andric switch (*(u32*)address) { 601*68d75effSDimitry Andric case 0x2444B60F: // 0F B6 44 24 XX : movzx eax, byte ptr [esp + XX] 602*68d75effSDimitry Andric return 5; 603*68d75effSDimitry Andric } 604*68d75effSDimitry Andric #endif 605*68d75effSDimitry Andric 606*68d75effSDimitry Andric // Unknown instruction! 607*68d75effSDimitry Andric // FIXME: Unknown instruction failures might happen when we add a new 608*68d75effSDimitry Andric // interceptor or a new compiler version. In either case, they should result 609*68d75effSDimitry Andric // in visible and readable error messages. However, merely calling abort() 610*68d75effSDimitry Andric // leads to an infinite recursion in CheckFailed. 611*68d75effSDimitry Andric InterceptionFailed(); 612*68d75effSDimitry Andric return 0; 613*68d75effSDimitry Andric } 614*68d75effSDimitry Andric 615*68d75effSDimitry Andric // Returns 0 on error. 616*68d75effSDimitry Andric static size_t RoundUpToInstrBoundary(size_t size, uptr address) { 617*68d75effSDimitry Andric size_t cursor = 0; 618*68d75effSDimitry Andric while (cursor < size) { 619*68d75effSDimitry Andric size_t instruction_size = GetInstructionSize(address + cursor); 620*68d75effSDimitry Andric if (!instruction_size) 621*68d75effSDimitry Andric return 0; 622*68d75effSDimitry Andric cursor += instruction_size; 623*68d75effSDimitry Andric } 624*68d75effSDimitry Andric return cursor; 625*68d75effSDimitry Andric } 626*68d75effSDimitry Andric 627*68d75effSDimitry Andric static bool CopyInstructions(uptr to, uptr from, size_t size) { 628*68d75effSDimitry Andric size_t cursor = 0; 629*68d75effSDimitry Andric while (cursor != size) { 630*68d75effSDimitry Andric size_t rel_offset = 0; 631*68d75effSDimitry Andric size_t instruction_size = GetInstructionSize(from + cursor, &rel_offset); 632*68d75effSDimitry Andric _memcpy((void*)(to + cursor), (void*)(from + cursor), 633*68d75effSDimitry Andric (size_t)instruction_size); 634*68d75effSDimitry Andric if (rel_offset) { 635*68d75effSDimitry Andric uptr delta = to - from; 636*68d75effSDimitry Andric uptr relocated_offset = *(u32*)(to + cursor + rel_offset) - delta; 637*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 638*68d75effSDimitry Andric if (relocated_offset + 0x80000000U >= 0xFFFFFFFFU) 639*68d75effSDimitry Andric return false; 640*68d75effSDimitry Andric #endif 641*68d75effSDimitry Andric *(u32*)(to + cursor + rel_offset) = relocated_offset; 642*68d75effSDimitry Andric } 643*68d75effSDimitry Andric cursor += instruction_size; 644*68d75effSDimitry Andric } 645*68d75effSDimitry Andric return true; 646*68d75effSDimitry Andric } 647*68d75effSDimitry Andric 648*68d75effSDimitry Andric 649*68d75effSDimitry Andric #if !SANITIZER_WINDOWS64 650*68d75effSDimitry Andric bool OverrideFunctionWithDetour( 651*68d75effSDimitry Andric uptr old_func, uptr new_func, uptr *orig_old_func) { 652*68d75effSDimitry Andric const int kDetourHeaderLen = 5; 653*68d75effSDimitry Andric const u16 kDetourInstruction = 0xFF8B; 654*68d75effSDimitry Andric 655*68d75effSDimitry Andric uptr header = (uptr)old_func - kDetourHeaderLen; 656*68d75effSDimitry Andric uptr patch_length = kDetourHeaderLen + kShortJumpInstructionLength; 657*68d75effSDimitry Andric 658*68d75effSDimitry Andric // Validate that the function is hookable. 659*68d75effSDimitry Andric if (*(u16*)old_func != kDetourInstruction || 660*68d75effSDimitry Andric !IsMemoryPadding(header, kDetourHeaderLen)) 661*68d75effSDimitry Andric return false; 662*68d75effSDimitry Andric 663*68d75effSDimitry Andric // Change memory protection to writable. 664*68d75effSDimitry Andric DWORD protection = 0; 665*68d75effSDimitry Andric if (!ChangeMemoryProtection(header, patch_length, &protection)) 666*68d75effSDimitry Andric return false; 667*68d75effSDimitry Andric 668*68d75effSDimitry Andric // Write a relative jump to the redirected function. 669*68d75effSDimitry Andric WriteJumpInstruction(header, new_func); 670*68d75effSDimitry Andric 671*68d75effSDimitry Andric // Write the short jump to the function prefix. 672*68d75effSDimitry Andric WriteShortJumpInstruction(old_func, header); 673*68d75effSDimitry Andric 674*68d75effSDimitry Andric // Restore previous memory protection. 675*68d75effSDimitry Andric if (!RestoreMemoryProtection(header, patch_length, protection)) 676*68d75effSDimitry Andric return false; 677*68d75effSDimitry Andric 678*68d75effSDimitry Andric if (orig_old_func) 679*68d75effSDimitry Andric *orig_old_func = old_func + kShortJumpInstructionLength; 680*68d75effSDimitry Andric 681*68d75effSDimitry Andric return true; 682*68d75effSDimitry Andric } 683*68d75effSDimitry Andric #endif 684*68d75effSDimitry Andric 685*68d75effSDimitry Andric bool OverrideFunctionWithRedirectJump( 686*68d75effSDimitry Andric uptr old_func, uptr new_func, uptr *orig_old_func) { 687*68d75effSDimitry Andric // Check whether the first instruction is a relative jump. 688*68d75effSDimitry Andric if (*(u8*)old_func != 0xE9) 689*68d75effSDimitry Andric return false; 690*68d75effSDimitry Andric 691*68d75effSDimitry Andric if (orig_old_func) { 692*68d75effSDimitry Andric uptr relative_offset = *(u32*)(old_func + 1); 693*68d75effSDimitry Andric uptr absolute_target = old_func + relative_offset + kJumpInstructionLength; 694*68d75effSDimitry Andric *orig_old_func = absolute_target; 695*68d75effSDimitry Andric } 696*68d75effSDimitry Andric 697*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 698*68d75effSDimitry Andric // If needed, get memory space for a trampoline jump. 699*68d75effSDimitry Andric uptr trampoline = AllocateMemoryForTrampoline(old_func, kDirectBranchLength); 700*68d75effSDimitry Andric if (!trampoline) 701*68d75effSDimitry Andric return false; 702*68d75effSDimitry Andric WriteDirectBranch(trampoline, new_func); 703*68d75effSDimitry Andric #endif 704*68d75effSDimitry Andric 705*68d75effSDimitry Andric // Change memory protection to writable. 706*68d75effSDimitry Andric DWORD protection = 0; 707*68d75effSDimitry Andric if (!ChangeMemoryProtection(old_func, kJumpInstructionLength, &protection)) 708*68d75effSDimitry Andric return false; 709*68d75effSDimitry Andric 710*68d75effSDimitry Andric // Write a relative jump to the redirected function. 711*68d75effSDimitry Andric WriteJumpInstruction(old_func, FIRST_32_SECOND_64(new_func, trampoline)); 712*68d75effSDimitry Andric 713*68d75effSDimitry Andric // Restore previous memory protection. 714*68d75effSDimitry Andric if (!RestoreMemoryProtection(old_func, kJumpInstructionLength, protection)) 715*68d75effSDimitry Andric return false; 716*68d75effSDimitry Andric 717*68d75effSDimitry Andric return true; 718*68d75effSDimitry Andric } 719*68d75effSDimitry Andric 720*68d75effSDimitry Andric bool OverrideFunctionWithHotPatch( 721*68d75effSDimitry Andric uptr old_func, uptr new_func, uptr *orig_old_func) { 722*68d75effSDimitry Andric const int kHotPatchHeaderLen = kBranchLength; 723*68d75effSDimitry Andric 724*68d75effSDimitry Andric uptr header = (uptr)old_func - kHotPatchHeaderLen; 725*68d75effSDimitry Andric uptr patch_length = kHotPatchHeaderLen + kShortJumpInstructionLength; 726*68d75effSDimitry Andric 727*68d75effSDimitry Andric // Validate that the function is hot patchable. 728*68d75effSDimitry Andric size_t instruction_size = GetInstructionSize(old_func); 729*68d75effSDimitry Andric if (instruction_size < kShortJumpInstructionLength || 730*68d75effSDimitry Andric !FunctionHasPadding(old_func, kHotPatchHeaderLen)) 731*68d75effSDimitry Andric return false; 732*68d75effSDimitry Andric 733*68d75effSDimitry Andric if (orig_old_func) { 734*68d75effSDimitry Andric // Put the needed instructions into the trampoline bytes. 735*68d75effSDimitry Andric uptr trampoline_length = instruction_size + kDirectBranchLength; 736*68d75effSDimitry Andric uptr trampoline = AllocateMemoryForTrampoline(old_func, trampoline_length); 737*68d75effSDimitry Andric if (!trampoline) 738*68d75effSDimitry Andric return false; 739*68d75effSDimitry Andric if (!CopyInstructions(trampoline, old_func, instruction_size)) 740*68d75effSDimitry Andric return false; 741*68d75effSDimitry Andric WriteDirectBranch(trampoline + instruction_size, 742*68d75effSDimitry Andric old_func + instruction_size); 743*68d75effSDimitry Andric *orig_old_func = trampoline; 744*68d75effSDimitry Andric } 745*68d75effSDimitry Andric 746*68d75effSDimitry Andric // If needed, get memory space for indirect address. 747*68d75effSDimitry Andric uptr indirect_address = 0; 748*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 749*68d75effSDimitry Andric indirect_address = AllocateMemoryForTrampoline(old_func, kAddressLength); 750*68d75effSDimitry Andric if (!indirect_address) 751*68d75effSDimitry Andric return false; 752*68d75effSDimitry Andric #endif 753*68d75effSDimitry Andric 754*68d75effSDimitry Andric // Change memory protection to writable. 755*68d75effSDimitry Andric DWORD protection = 0; 756*68d75effSDimitry Andric if (!ChangeMemoryProtection(header, patch_length, &protection)) 757*68d75effSDimitry Andric return false; 758*68d75effSDimitry Andric 759*68d75effSDimitry Andric // Write jumps to the redirected function. 760*68d75effSDimitry Andric WriteBranch(header, indirect_address, new_func); 761*68d75effSDimitry Andric WriteShortJumpInstruction(old_func, header); 762*68d75effSDimitry Andric 763*68d75effSDimitry Andric // Restore previous memory protection. 764*68d75effSDimitry Andric if (!RestoreMemoryProtection(header, patch_length, protection)) 765*68d75effSDimitry Andric return false; 766*68d75effSDimitry Andric 767*68d75effSDimitry Andric return true; 768*68d75effSDimitry Andric } 769*68d75effSDimitry Andric 770*68d75effSDimitry Andric bool OverrideFunctionWithTrampoline( 771*68d75effSDimitry Andric uptr old_func, uptr new_func, uptr *orig_old_func) { 772*68d75effSDimitry Andric 773*68d75effSDimitry Andric size_t instructions_length = kBranchLength; 774*68d75effSDimitry Andric size_t padding_length = 0; 775*68d75effSDimitry Andric uptr indirect_address = 0; 776*68d75effSDimitry Andric 777*68d75effSDimitry Andric if (orig_old_func) { 778*68d75effSDimitry Andric // Find out the number of bytes of the instructions we need to copy 779*68d75effSDimitry Andric // to the trampoline. 780*68d75effSDimitry Andric instructions_length = RoundUpToInstrBoundary(kBranchLength, old_func); 781*68d75effSDimitry Andric if (!instructions_length) 782*68d75effSDimitry Andric return false; 783*68d75effSDimitry Andric 784*68d75effSDimitry Andric // Put the needed instructions into the trampoline bytes. 785*68d75effSDimitry Andric uptr trampoline_length = instructions_length + kDirectBranchLength; 786*68d75effSDimitry Andric uptr trampoline = AllocateMemoryForTrampoline(old_func, trampoline_length); 787*68d75effSDimitry Andric if (!trampoline) 788*68d75effSDimitry Andric return false; 789*68d75effSDimitry Andric if (!CopyInstructions(trampoline, old_func, instructions_length)) 790*68d75effSDimitry Andric return false; 791*68d75effSDimitry Andric WriteDirectBranch(trampoline + instructions_length, 792*68d75effSDimitry Andric old_func + instructions_length); 793*68d75effSDimitry Andric *orig_old_func = trampoline; 794*68d75effSDimitry Andric } 795*68d75effSDimitry Andric 796*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 797*68d75effSDimitry Andric // Check if the targeted address can be encoded in the function padding. 798*68d75effSDimitry Andric // Otherwise, allocate it in the trampoline region. 799*68d75effSDimitry Andric if (IsMemoryPadding(old_func - kAddressLength, kAddressLength)) { 800*68d75effSDimitry Andric indirect_address = old_func - kAddressLength; 801*68d75effSDimitry Andric padding_length = kAddressLength; 802*68d75effSDimitry Andric } else { 803*68d75effSDimitry Andric indirect_address = AllocateMemoryForTrampoline(old_func, kAddressLength); 804*68d75effSDimitry Andric if (!indirect_address) 805*68d75effSDimitry Andric return false; 806*68d75effSDimitry Andric } 807*68d75effSDimitry Andric #endif 808*68d75effSDimitry Andric 809*68d75effSDimitry Andric // Change memory protection to writable. 810*68d75effSDimitry Andric uptr patch_address = old_func - padding_length; 811*68d75effSDimitry Andric uptr patch_length = instructions_length + padding_length; 812*68d75effSDimitry Andric DWORD protection = 0; 813*68d75effSDimitry Andric if (!ChangeMemoryProtection(patch_address, patch_length, &protection)) 814*68d75effSDimitry Andric return false; 815*68d75effSDimitry Andric 816*68d75effSDimitry Andric // Patch the original function. 817*68d75effSDimitry Andric WriteBranch(old_func, indirect_address, new_func); 818*68d75effSDimitry Andric 819*68d75effSDimitry Andric // Restore previous memory protection. 820*68d75effSDimitry Andric if (!RestoreMemoryProtection(patch_address, patch_length, protection)) 821*68d75effSDimitry Andric return false; 822*68d75effSDimitry Andric 823*68d75effSDimitry Andric return true; 824*68d75effSDimitry Andric } 825*68d75effSDimitry Andric 826*68d75effSDimitry Andric bool OverrideFunction( 827*68d75effSDimitry Andric uptr old_func, uptr new_func, uptr *orig_old_func) { 828*68d75effSDimitry Andric #if !SANITIZER_WINDOWS64 829*68d75effSDimitry Andric if (OverrideFunctionWithDetour(old_func, new_func, orig_old_func)) 830*68d75effSDimitry Andric return true; 831*68d75effSDimitry Andric #endif 832*68d75effSDimitry Andric if (OverrideFunctionWithRedirectJump(old_func, new_func, orig_old_func)) 833*68d75effSDimitry Andric return true; 834*68d75effSDimitry Andric if (OverrideFunctionWithHotPatch(old_func, new_func, orig_old_func)) 835*68d75effSDimitry Andric return true; 836*68d75effSDimitry Andric if (OverrideFunctionWithTrampoline(old_func, new_func, orig_old_func)) 837*68d75effSDimitry Andric return true; 838*68d75effSDimitry Andric return false; 839*68d75effSDimitry Andric } 840*68d75effSDimitry Andric 841*68d75effSDimitry Andric static void **InterestingDLLsAvailable() { 842*68d75effSDimitry Andric static const char *InterestingDLLs[] = { 843*68d75effSDimitry Andric "kernel32.dll", 844*68d75effSDimitry Andric "msvcr100.dll", // VS2010 845*68d75effSDimitry Andric "msvcr110.dll", // VS2012 846*68d75effSDimitry Andric "msvcr120.dll", // VS2013 847*68d75effSDimitry Andric "vcruntime140.dll", // VS2015 848*68d75effSDimitry Andric "ucrtbase.dll", // Universal CRT 849*68d75effSDimitry Andric // NTDLL should go last as it exports some functions that we should 850*68d75effSDimitry Andric // override in the CRT [presumably only used internally]. 851*68d75effSDimitry Andric "ntdll.dll", NULL}; 852*68d75effSDimitry Andric static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 }; 853*68d75effSDimitry Andric if (!result[0]) { 854*68d75effSDimitry Andric for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) { 855*68d75effSDimitry Andric if (HMODULE h = GetModuleHandleA(InterestingDLLs[i])) 856*68d75effSDimitry Andric result[j++] = (void *)h; 857*68d75effSDimitry Andric } 858*68d75effSDimitry Andric } 859*68d75effSDimitry Andric return &result[0]; 860*68d75effSDimitry Andric } 861*68d75effSDimitry Andric 862*68d75effSDimitry Andric namespace { 863*68d75effSDimitry Andric // Utility for reading loaded PE images. 864*68d75effSDimitry Andric template <typename T> class RVAPtr { 865*68d75effSDimitry Andric public: 866*68d75effSDimitry Andric RVAPtr(void *module, uptr rva) 867*68d75effSDimitry Andric : ptr_(reinterpret_cast<T *>(reinterpret_cast<char *>(module) + rva)) {} 868*68d75effSDimitry Andric operator T *() { return ptr_; } 869*68d75effSDimitry Andric T *operator->() { return ptr_; } 870*68d75effSDimitry Andric T *operator++() { return ++ptr_; } 871*68d75effSDimitry Andric 872*68d75effSDimitry Andric private: 873*68d75effSDimitry Andric T *ptr_; 874*68d75effSDimitry Andric }; 875*68d75effSDimitry Andric } // namespace 876*68d75effSDimitry Andric 877*68d75effSDimitry Andric // Internal implementation of GetProcAddress. At least since Windows 8, 878*68d75effSDimitry Andric // GetProcAddress appears to initialize DLLs before returning function pointers 879*68d75effSDimitry Andric // into them. This is problematic for the sanitizers, because they typically 880*68d75effSDimitry Andric // want to intercept malloc *before* MSVCRT initializes. Our internal 881*68d75effSDimitry Andric // implementation walks the export list manually without doing initialization. 882*68d75effSDimitry Andric uptr InternalGetProcAddress(void *module, const char *func_name) { 883*68d75effSDimitry Andric // Check that the module header is full and present. 884*68d75effSDimitry Andric RVAPtr<IMAGE_DOS_HEADER> dos_stub(module, 0); 885*68d75effSDimitry Andric RVAPtr<IMAGE_NT_HEADERS> headers(module, dos_stub->e_lfanew); 886*68d75effSDimitry Andric if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ" 887*68d75effSDimitry Andric headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0" 888*68d75effSDimitry Andric headers->FileHeader.SizeOfOptionalHeader < 889*68d75effSDimitry Andric sizeof(IMAGE_OPTIONAL_HEADER)) { 890*68d75effSDimitry Andric return 0; 891*68d75effSDimitry Andric } 892*68d75effSDimitry Andric 893*68d75effSDimitry Andric IMAGE_DATA_DIRECTORY *export_directory = 894*68d75effSDimitry Andric &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 895*68d75effSDimitry Andric if (export_directory->Size == 0) 896*68d75effSDimitry Andric return 0; 897*68d75effSDimitry Andric RVAPtr<IMAGE_EXPORT_DIRECTORY> exports(module, 898*68d75effSDimitry Andric export_directory->VirtualAddress); 899*68d75effSDimitry Andric RVAPtr<DWORD> functions(module, exports->AddressOfFunctions); 900*68d75effSDimitry Andric RVAPtr<DWORD> names(module, exports->AddressOfNames); 901*68d75effSDimitry Andric RVAPtr<WORD> ordinals(module, exports->AddressOfNameOrdinals); 902*68d75effSDimitry Andric 903*68d75effSDimitry Andric for (DWORD i = 0; i < exports->NumberOfNames; i++) { 904*68d75effSDimitry Andric RVAPtr<char> name(module, names[i]); 905*68d75effSDimitry Andric if (!strcmp(func_name, name)) { 906*68d75effSDimitry Andric DWORD index = ordinals[i]; 907*68d75effSDimitry Andric RVAPtr<char> func(module, functions[index]); 908*68d75effSDimitry Andric 909*68d75effSDimitry Andric // Handle forwarded functions. 910*68d75effSDimitry Andric DWORD offset = functions[index]; 911*68d75effSDimitry Andric if (offset >= export_directory->VirtualAddress && 912*68d75effSDimitry Andric offset < export_directory->VirtualAddress + export_directory->Size) { 913*68d75effSDimitry Andric // An entry for a forwarded function is a string with the following 914*68d75effSDimitry Andric // format: "<module> . <function_name>" that is stored into the 915*68d75effSDimitry Andric // exported directory. 916*68d75effSDimitry Andric char function_name[256]; 917*68d75effSDimitry Andric size_t funtion_name_length = _strlen(func); 918*68d75effSDimitry Andric if (funtion_name_length >= sizeof(function_name) - 1) 919*68d75effSDimitry Andric InterceptionFailed(); 920*68d75effSDimitry Andric 921*68d75effSDimitry Andric _memcpy(function_name, func, funtion_name_length); 922*68d75effSDimitry Andric function_name[funtion_name_length] = '\0'; 923*68d75effSDimitry Andric char* separator = _strchr(function_name, '.'); 924*68d75effSDimitry Andric if (!separator) 925*68d75effSDimitry Andric InterceptionFailed(); 926*68d75effSDimitry Andric *separator = '\0'; 927*68d75effSDimitry Andric 928*68d75effSDimitry Andric void* redirected_module = GetModuleHandleA(function_name); 929*68d75effSDimitry Andric if (!redirected_module) 930*68d75effSDimitry Andric InterceptionFailed(); 931*68d75effSDimitry Andric return InternalGetProcAddress(redirected_module, separator + 1); 932*68d75effSDimitry Andric } 933*68d75effSDimitry Andric 934*68d75effSDimitry Andric return (uptr)(char *)func; 935*68d75effSDimitry Andric } 936*68d75effSDimitry Andric } 937*68d75effSDimitry Andric 938*68d75effSDimitry Andric return 0; 939*68d75effSDimitry Andric } 940*68d75effSDimitry Andric 941*68d75effSDimitry Andric bool OverrideFunction( 942*68d75effSDimitry Andric const char *func_name, uptr new_func, uptr *orig_old_func) { 943*68d75effSDimitry Andric bool hooked = false; 944*68d75effSDimitry Andric void **DLLs = InterestingDLLsAvailable(); 945*68d75effSDimitry Andric for (size_t i = 0; DLLs[i]; ++i) { 946*68d75effSDimitry Andric uptr func_addr = InternalGetProcAddress(DLLs[i], func_name); 947*68d75effSDimitry Andric if (func_addr && 948*68d75effSDimitry Andric OverrideFunction(func_addr, new_func, orig_old_func)) { 949*68d75effSDimitry Andric hooked = true; 950*68d75effSDimitry Andric } 951*68d75effSDimitry Andric } 952*68d75effSDimitry Andric return hooked; 953*68d75effSDimitry Andric } 954*68d75effSDimitry Andric 955*68d75effSDimitry Andric bool OverrideImportedFunction(const char *module_to_patch, 956*68d75effSDimitry Andric const char *imported_module, 957*68d75effSDimitry Andric const char *function_name, uptr new_function, 958*68d75effSDimitry Andric uptr *orig_old_func) { 959*68d75effSDimitry Andric HMODULE module = GetModuleHandleA(module_to_patch); 960*68d75effSDimitry Andric if (!module) 961*68d75effSDimitry Andric return false; 962*68d75effSDimitry Andric 963*68d75effSDimitry Andric // Check that the module header is full and present. 964*68d75effSDimitry Andric RVAPtr<IMAGE_DOS_HEADER> dos_stub(module, 0); 965*68d75effSDimitry Andric RVAPtr<IMAGE_NT_HEADERS> headers(module, dos_stub->e_lfanew); 966*68d75effSDimitry Andric if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ" 967*68d75effSDimitry Andric headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0" 968*68d75effSDimitry Andric headers->FileHeader.SizeOfOptionalHeader < 969*68d75effSDimitry Andric sizeof(IMAGE_OPTIONAL_HEADER)) { 970*68d75effSDimitry Andric return false; 971*68d75effSDimitry Andric } 972*68d75effSDimitry Andric 973*68d75effSDimitry Andric IMAGE_DATA_DIRECTORY *import_directory = 974*68d75effSDimitry Andric &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 975*68d75effSDimitry Andric 976*68d75effSDimitry Andric // Iterate the list of imported DLLs. FirstThunk will be null for the last 977*68d75effSDimitry Andric // entry. 978*68d75effSDimitry Andric RVAPtr<IMAGE_IMPORT_DESCRIPTOR> imports(module, 979*68d75effSDimitry Andric import_directory->VirtualAddress); 980*68d75effSDimitry Andric for (; imports->FirstThunk != 0; ++imports) { 981*68d75effSDimitry Andric RVAPtr<const char> modname(module, imports->Name); 982*68d75effSDimitry Andric if (_stricmp(&*modname, imported_module) == 0) 983*68d75effSDimitry Andric break; 984*68d75effSDimitry Andric } 985*68d75effSDimitry Andric if (imports->FirstThunk == 0) 986*68d75effSDimitry Andric return false; 987*68d75effSDimitry Andric 988*68d75effSDimitry Andric // We have two parallel arrays: the import address table (IAT) and the table 989*68d75effSDimitry Andric // of names. They start out containing the same data, but the loader rewrites 990*68d75effSDimitry Andric // the IAT to hold imported addresses and leaves the name table in 991*68d75effSDimitry Andric // OriginalFirstThunk alone. 992*68d75effSDimitry Andric RVAPtr<IMAGE_THUNK_DATA> name_table(module, imports->OriginalFirstThunk); 993*68d75effSDimitry Andric RVAPtr<IMAGE_THUNK_DATA> iat(module, imports->FirstThunk); 994*68d75effSDimitry Andric for (; name_table->u1.Ordinal != 0; ++name_table, ++iat) { 995*68d75effSDimitry Andric if (!IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) { 996*68d75effSDimitry Andric RVAPtr<IMAGE_IMPORT_BY_NAME> import_by_name( 997*68d75effSDimitry Andric module, name_table->u1.ForwarderString); 998*68d75effSDimitry Andric const char *funcname = &import_by_name->Name[0]; 999*68d75effSDimitry Andric if (strcmp(funcname, function_name) == 0) 1000*68d75effSDimitry Andric break; 1001*68d75effSDimitry Andric } 1002*68d75effSDimitry Andric } 1003*68d75effSDimitry Andric if (name_table->u1.Ordinal == 0) 1004*68d75effSDimitry Andric return false; 1005*68d75effSDimitry Andric 1006*68d75effSDimitry Andric // Now we have the correct IAT entry. Do the swap. We have to make the page 1007*68d75effSDimitry Andric // read/write first. 1008*68d75effSDimitry Andric if (orig_old_func) 1009*68d75effSDimitry Andric *orig_old_func = iat->u1.AddressOfData; 1010*68d75effSDimitry Andric DWORD old_prot, unused_prot; 1011*68d75effSDimitry Andric if (!VirtualProtect(&iat->u1.AddressOfData, 4, PAGE_EXECUTE_READWRITE, 1012*68d75effSDimitry Andric &old_prot)) 1013*68d75effSDimitry Andric return false; 1014*68d75effSDimitry Andric iat->u1.AddressOfData = new_function; 1015*68d75effSDimitry Andric if (!VirtualProtect(&iat->u1.AddressOfData, 4, old_prot, &unused_prot)) 1016*68d75effSDimitry Andric return false; // Not clear if this failure bothers us. 1017*68d75effSDimitry Andric return true; 1018*68d75effSDimitry Andric } 1019*68d75effSDimitry Andric 1020*68d75effSDimitry Andric } // namespace __interception 1021*68d75effSDimitry Andric 1022*68d75effSDimitry Andric #endif // SANITIZER_MAC 1023