diff options
Diffstat (limited to 'lib/interception/interception_win.cc')
-rw-r--r-- | lib/interception/interception_win.cc | 138 |
1 files changed, 116 insertions, 22 deletions
diff --git a/lib/interception/interception_win.cc b/lib/interception/interception_win.cc index 8977d59ac4f17..91abecf6de5f0 100644 --- a/lib/interception/interception_win.cc +++ b/lib/interception/interception_win.cc @@ -148,10 +148,16 @@ static void InterceptionFailed() { } static bool DistanceIsWithin2Gig(uptr from, uptr target) { +#if SANITIZER_WINDOWS64 if (from < target) return target - from <= (uptr)0x7FFFFFFFU; else return from - target <= (uptr)0x80000000U; +#else + // In a 32-bit address space, the address calculation will wrap, so this check + // is unnecessary. + return true; +#endif } static uptr GetMmapGranularity() { @@ -167,6 +173,21 @@ static uptr RoundUpTo(uptr size, uptr boundary) { // FIXME: internal_str* and internal_mem* functions should be moved from the // ASan sources into interception/. +static size_t _strlen(const char *str) { + const char* p = str; + while (*p != '\0') ++p; + return p - str; +} + +static char* _strchr(char* str, char c) { + while (*str) { + if (*str == c) + return str; + ++str; + } + return nullptr; +} + static void _memset(void *p, int value, size_t sz) { for (size_t i = 0; i < sz; ++i) ((char*)p)[i] = (char)value; @@ -229,10 +250,6 @@ static void WritePadding(uptr from, uptr size) { _memset((void*)from, 0xCC, (size_t)size); } -static void CopyInstructions(uptr from, uptr to, uptr size) { - _memcpy((void*)from, (void*)to, (size_t)size); -} - static void WriteJumpInstruction(uptr from, uptr target) { if (!DistanceIsWithin2Gig(from + kJumpInstructionLength, target)) InterceptionFailed(); @@ -294,7 +311,7 @@ struct TrampolineMemoryRegion { uptr max_size; }; -static const uptr kTrampolineScanLimitRange = 1 << 30; // 1 gig +static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig static const int kMaxTrampolineRegion = 1024; static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion]; @@ -384,7 +401,7 @@ static uptr AllocateMemoryForTrampoline(uptr image_address, size_t size) { } // Returns 0 on error. -static size_t GetInstructionSize(uptr address) { +static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { switch (*(u64*)address) { case 0x90909090909006EB: // stub: jmp over 6 x nop. return 8; @@ -410,7 +427,6 @@ static size_t GetInstructionSize(uptr address) { case 0xb8: // b8 XX XX XX XX : mov eax, XX XX XX XX case 0xB9: // b9 XX XX XX XX : mov ecx, XX XX XX XX - case 0xA1: // A1 XX XX XX XX : mov eax, dword ptr ds:[XXXXXXXX] return 5; // Cannot overwrite control-instruction. Return 0 to indicate failure. @@ -452,7 +468,18 @@ static size_t GetInstructionSize(uptr address) { return 0; } + switch (0x00FFFFFF & *(u32*)address) { + case 0x24A48D: // 8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX] + return 7; + } + #if SANITIZER_WINDOWS64 + switch (*(u8*)address) { + case 0xA1: // A1 XX XX XX XX XX XX XX XX : + // movabs eax, dword ptr ds:[XXXXXXXX] + return 8; + } + switch (*(u16*)address) { case 0x5040: // push rax case 0x5140: // push rcx @@ -477,17 +504,20 @@ static size_t GetInstructionSize(uptr address) { case 0xd9f748: // 48 f7 d9 : neg rcx case 0xd12b48: // 48 2b d1 : sub rdx, rcx case 0x07c1f6: // f6 c1 07 : test cl, 0x7 + case 0xc98548: // 48 85 C9 : test rcx, rcx case 0xc0854d: // 4d 85 c0 : test r8, r8 case 0xc2b60f: // 0f b6 c2 : movzx eax, dl case 0xc03345: // 45 33 c0 : xor r8d, r8d + case 0xdb3345: // 45 33 DB : xor r11d, r11d case 0xd98b4c: // 4c 8b d9 : mov r11, rcx case 0xd28b4c: // 4c 8b d2 : mov r10, rdx + case 0xc98b4c: // 4C 8B C9 : mov r9, rcx case 0xd2b60f: // 0f b6 d2 : movzx edx, dl case 0xca2b48: // 48 2b ca : sub rcx, rdx case 0x10b70f: // 0f b7 10 : movzx edx, WORD PTR [rax] case 0xc00b4d: // 3d 0b c0 : or r8, r8 case 0xd18b48: // 48 8b d1 : mov rdx, rcx - case 0xdc8b4c: // 4c 8b dc : mov r11,rsp + case 0xdc8b4c: // 4c 8b dc : mov r11, rsp case 0xd18b4c: // 4c 8b d1 : mov r10, rcx return 3; @@ -496,11 +526,22 @@ static size_t GetInstructionSize(uptr address) { case 0x588948: // 48 89 58 XX : mov QWORD PTR[rax + XX], rbx return 4; + case 0xec8148: // 48 81 EC XX XX XX XX : sub rsp, XXXXXXXX + return 7; + case 0x058b48: // 48 8b 05 XX XX XX XX : // mov rax, QWORD PTR [rip + XXXXXXXX] case 0x25ff48: // 48 ff 25 XX XX XX XX : // rex.W jmp QWORD PTR [rip + XXXXXXXX] + + // Instructions having offset relative to 'rip' need offset adjustment. + if (rel_offset) + *rel_offset = 3; return 7; + + case 0x2444c7: // C7 44 24 XX YY YY YY YY + // mov dword ptr [rsp + XX], YYYYYYYY + return 8; } switch (*(u32*)(address)) { @@ -513,6 +554,10 @@ static size_t GetInstructionSize(uptr address) { #else + switch (*(u8*)address) { + case 0xA1: // A1 XX XX XX XX : mov eax, dword ptr ds:[XXXXXXXX] + return 5; + } switch (*(u16*)address) { case 0x458B: // 8B 45 XX : mov eax, dword ptr [ebp + XX] case 0x5D8B: // 8B 5D XX : mov ebx, dword ptr [ebp + XX] @@ -566,6 +611,28 @@ static size_t RoundUpToInstrBoundary(size_t size, uptr address) { return cursor; } +static bool CopyInstructions(uptr to, uptr from, size_t size) { + size_t cursor = 0; + while (cursor != size) { + size_t rel_offset = 0; + size_t instruction_size = GetInstructionSize(from + cursor, &rel_offset); + _memcpy((void*)(to + cursor), (void*)(from + cursor), + (size_t)instruction_size); + if (rel_offset) { + uptr delta = to - from; + uptr relocated_offset = *(u32*)(to + cursor + rel_offset) - delta; +#if SANITIZER_WINDOWS64 + if (relocated_offset + 0x80000000U >= 0xFFFFFFFFU) + return false; +#endif + *(u32*)(to + cursor + rel_offset) = relocated_offset; + } + cursor += instruction_size; + } + return true; +} + + #if !SANITIZER_WINDOWS64 bool OverrideFunctionWithDetour( uptr old_func, uptr new_func, uptr *orig_old_func) { @@ -656,7 +723,8 @@ bool OverrideFunctionWithHotPatch( uptr trampoline = AllocateMemoryForTrampoline(old_func, trampoline_length); if (!trampoline) return false; - CopyInstructions(trampoline, old_func, instruction_size); + if (!CopyInstructions(trampoline, old_func, instruction_size)) + return false; WriteDirectBranch(trampoline + instruction_size, old_func + instruction_size); *orig_old_func = trampoline; @@ -705,7 +773,8 @@ bool OverrideFunctionWithTrampoline( uptr trampoline = AllocateMemoryForTrampoline(old_func, trampoline_length); if (!trampoline) return false; - CopyInstructions(trampoline, old_func, instructions_length); + if (!CopyInstructions(trampoline, old_func, instructions_length)) + return false; WriteDirectBranch(trampoline + instructions_length, old_func + instructions_length); *orig_old_func = trampoline; @@ -820,6 +889,32 @@ uptr InternalGetProcAddress(void *module, const char *func_name) { if (!strcmp(func_name, name)) { DWORD index = ordinals[i]; RVAPtr<char> func(module, functions[index]); + + // Handle forwarded functions. + DWORD offset = functions[index]; + if (offset >= export_directory->VirtualAddress && + offset < export_directory->VirtualAddress + export_directory->Size) { + // An entry for a forwarded function is a string with the following + // format: "<module> . <function_name>" that is stored into the + // exported directory. + char function_name[256]; + size_t funtion_name_length = _strlen(func); + if (funtion_name_length >= sizeof(function_name) - 1) + InterceptionFailed(); + + _memcpy(function_name, func, funtion_name_length); + function_name[funtion_name_length] = '\0'; + char* separator = _strchr(function_name, '.'); + if (!separator) + InterceptionFailed(); + *separator = '\0'; + + void* redirected_module = GetModuleHandleA(function_name); + if (!redirected_module) + InterceptionFailed(); + return InternalGetProcAddress(redirected_module, separator + 1); + } + return (uptr)(char *)func; } } @@ -827,19 +922,18 @@ uptr InternalGetProcAddress(void *module, const char *func_name) { return 0; } -static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) { - *func_addr = 0; +bool OverrideFunction( + const char *func_name, uptr new_func, uptr *orig_old_func) { + bool hooked = false; void **DLLs = InterestingDLLsAvailable(); - for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i) - *func_addr = InternalGetProcAddress(DLLs[i], func_name); - return (*func_addr != 0); -} - -bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func) { - uptr orig_func; - if (!GetFunctionAddressInDLLs(name, &orig_func)) - return false; - return OverrideFunction(orig_func, new_func, orig_old_func); + for (size_t i = 0; DLLs[i]; ++i) { + uptr func_addr = InternalGetProcAddress(DLLs[i], func_name); + if (func_addr && + OverrideFunction(func_addr, new_func, orig_old_func)) { + hooked = true; + } + } + return hooked; } bool OverrideImportedFunction(const char *module_to_patch, |