15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copyright (c) 2007, Google Inc. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modification, are permitted provided that the following conditions are 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * * Redistributions of source code must retain the above copyright 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * notice, this list of conditions and the following disclaimer. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * * Redistributions in binary form must reproduce the above 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in the documentation and/or other materials provided with the 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distribution. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * * Neither the name of Google Inc. nor the names of its 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * contributors may be used to endorse or promote products derived from 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this software without specific prior written permission. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * --- 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Author: Joi Sigurdsson 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Author: Scott Francis 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Implementation of PreamblePatcher 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "preamble_patcher.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "mini_disassembler.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// compatibility shims 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Definitions of assembly statements we need 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP32REL 0xE9 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_INT3 0xCC 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP32ABS_0 0xFF 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP32ABS_1 0x25 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP8REL 0xEB 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JCC32REL_0 0x0F 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JCC32REL_1_MASK 0x80 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_NOP 0x90 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// X64 opcodes 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_REXW 0x48 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_MOVRAX_IMM 0xB8 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP 0xFF 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP_RAX 0xE0 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sidestep { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PreamblePatcher::PreamblePage* PreamblePatcher::preamble_pages_ = NULL; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)long PreamblePatcher::granularity_ = 0; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)long PreamblePatcher::pagesize_ = 0; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::initialized_ = false; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const unsigned int kPreamblePageMagic = 0x4347414D; // "MAGC" 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handle a special case that we see with functions that point into an 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IAT table (including functions linked statically into the 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// application): these function already starts with ASM_JMP32*. For 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// instance, malloc() might be implemented as a JMP to __malloc(). 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function follows the initial JMPs for us, until we get to the 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// place where the actual code is defined. If we get to STOP_BEFORE, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we return the address before stop_before. The stop_before_trampoline 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// flag is used in 64-bit mode. If true, we will return the address 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before a trampoline is detected. Trampolines are defined as: 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// nop 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mov rax, <replacement_function> 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// jmp rax 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See PreamblePatcher::RawPatchWithStub for more information. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* PreamblePatcher::ResolveTargetImpl(unsigned char* target, 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* stop_before, 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool stop_before_trampoline) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target == NULL) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (1) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* new_target; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target[0] == ASM_JMP32REL) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // target[1-4] holds the place the jmp goes to, but it's 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // relative to the next instruction. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int relative_offset; // Windows guarantees int is 4 bytes 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(sizeof(relative_offset) == 4); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(&relative_offset), 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(target + 1), 4); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_target = target + 5 + relative_offset; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (target[0] == ASM_JMP8REL) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Visual Studio 7.1 implements new[] as an 8 bit jump to new 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signed char relative_offset; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(&relative_offset), 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(target + 1), 1); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_target = target + 2 + relative_offset; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (target[0] == ASM_JMP32ABS_0 && 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target[1] == ASM_JMP32ABS_1) { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Visual studio seems to sometimes do it this way instead of the 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // previous way. Not sure what the rules are, but it was happening 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with operator new in some binaries. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void** new_target_v; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (kIs64BitBinary) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In 64-bit mode JMPs are RIP-relative, not absolute 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int target_offset; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(&target_offset), 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(target + 2), 4); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_target_v = reinterpret_cast<void**>(target + target_offset + 6); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(sizeof(new_target) == 4); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&new_target_v, reinterpret_cast<void*>(target + 2), 4); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_target = reinterpret_cast<unsigned char*>(*new_target_v); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_target == stop_before) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stop_before_trampoline && *new_target == ASM_NOP 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) && new_target[1] == ASM_REXW && new_target[2] == ASM_MOVRAX_IMM) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target = new_target; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return target; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Special case scoped_ptr to avoid dependency on scoped_ptr below. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DeleteUnsignedCharArray { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeleteUnsignedCharArray(unsigned char* array) : array_(array) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~DeleteUnsignedCharArray() { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (array_) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreamblePatcher::FreePreambleBlock(array_); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* Release() { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* temp = array_; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) array_ = NULL; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return temp; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* array_; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::RawPatchWithStubAndProtections( 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* target_function, void *replacement_function, 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* preamble_stub, unsigned long stub_size, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned long* bytes_needed) { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to be able to write to a process-local copy of the first 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MAX_PREAMBLE_STUB_SIZE bytes of target_function 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD old_target_function_protect = 0; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function), 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAX_PREAMBLE_STUB_SIZE, 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PAGE_EXECUTE_READWRITE, 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &old_target_function_protect); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!succeeded) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && "Failed to make page containing target function " 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "copy-on-write."); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_ACCESS_DENIED; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SideStepError error_code = RawPatchWithStub(target_function, 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) replacement_function, 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preamble_stub, 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stub_size, 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes_needed); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pTargetFunction to what they were before we started goofing around. 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We do this regardless of whether the patch succeeded or not. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function), 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAX_PREAMBLE_STUB_SIZE, 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_target_function_protect, 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &old_target_function_protect); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!succeeded) { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to restore protection to target function."); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We must not return an error here because the function has 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // likely actually been patched, and returning an error might 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cause our client code not to unpatch it. So we just keep 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // going. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SIDESTEP_SUCCESS != error_code) { // Testing RawPatchWithStub, above 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error_code; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Flush the instruction cache to make sure the processor doesn't execute the 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // old version of the instructions (before our patch). 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // FlushInstructionCache is actually a no-op at least on 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // single-processor XP machines. I'm not sure why this is so, but 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it is, yet I want to keep the call to the API here for 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // correctness in case there is a difference in some variants of 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Windows/hardware. 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) succeeded = ::FlushInstructionCache(::GetCurrentProcess(), 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_function, 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAX_PREAMBLE_STUB_SIZE); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!succeeded) { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && "Failed to flush instruction cache."); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We must not return an error here because the function has actually 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // been patched, and returning an error would likely cause our client 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // code not to unpatch it. So we just keep going. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_SUCCESS; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::RawPatch(void* target_function, 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* replacement_function, 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void** original_function_stub) { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!target_function || !replacement_function || !original_function_stub || 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*original_function_stub) || target_function == replacement_function) { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && "Preconditions not met"); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_INVALID_PARAMETER; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL succeeded = FALSE; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First, deal with a special case that we see with functions that 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // point into an IAT table (including functions linked statically 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // into the application): these function already starts with 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ASM_JMP32REL. For instance, malloc() might be implemented as a 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // JMP to __malloc(). In that case, we replace the destination of 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the JMP (__malloc), rather than the JMP itself (malloc). This 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // way we get the correct behavior no matter how malloc gets called. 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* new_target = ResolveTarget(target_function); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_target != target_function) { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_function = new_target; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In 64-bit mode, preamble_stub must be within 2GB of target function 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so that if target contains a jump, we can translate it. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* preamble_stub = AllocPreambleBlockNear(target_function); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!preamble_stub) { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && "Unable to allocate preamble-stub."); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_INSUFFICIENT_BUFFER; 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Frees the array at end of scope. 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeleteUnsignedCharArray guard_preamble_stub(preamble_stub); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SideStepError error_code = RawPatchWithStubAndProtections( 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_function, replacement_function, preamble_stub, 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAX_PREAMBLE_STUB_SIZE, NULL); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SIDESTEP_SUCCESS != error_code) { 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error_code; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Flush the instruction cache to make sure the processor doesn't execute the 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // old version of the instructions (before our patch). 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // FlushInstructionCache is actually a no-op at least on 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // single-processor XP machines. I'm not sure why this is so, but 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it is, yet I want to keep the call to the API here for 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // correctness in case there is a difference in some variants of 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Windows/hardware. 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) succeeded = ::FlushInstructionCache(::GetCurrentProcess(), 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_function, 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAX_PREAMBLE_STUB_SIZE); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!succeeded) { 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && "Failed to flush instruction cache."); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We must not return an error here because the function has actually 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // been patched, and returning an error would likely cause our client 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // code not to unpatch it. So we just keep going. 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_LOG("PreamblePatcher::RawPatch successfully patched."); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // detach the scoped pointer so the memory is not freed 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *original_function_stub = 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(guard_preamble_stub.Release()); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_SUCCESS; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::Unpatch(void* target_function, 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* replacement_function, 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* original_function_stub) { 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(target_function && replacement_function && 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_function_stub); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!target_function || !replacement_function || 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !original_function_stub) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_INVALID_PARAMETER; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before unpatching, target_function should be a JMP to 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // replacement_function. If it's not, then either it's an error, or 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we're falling into the case where the original instruction was a 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // JMP, and we patched the jumped_to address rather than the JMP 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // itself. (For instance, if malloc() is just a JMP to __malloc(), 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we patched __malloc() and not malloc().) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target = reinterpret_cast<unsigned char*>(target_function); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target = reinterpret_cast<unsigned char*>( 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResolveTargetImpl( 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target, reinterpret_cast<unsigned char*>(replacement_function), 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) true)); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should end at the function we patched. When we patch, we insert 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a ASM_JMP32REL instruction, so look for that as a sanity check. 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target[0] != ASM_JMP32REL) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "target_function does not look like it was patched."); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_INVALID_PARAMETER; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const unsigned int kRequiredTargetPatchBytes = 5; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to be able to write to a process-local copy of the first 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // kRequiredTargetPatchBytes bytes of target_function 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD old_target_function_protect = 0; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target), 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kRequiredTargetPatchBytes, 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PAGE_EXECUTE_READWRITE, 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &old_target_function_protect); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!succeeded) { 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && "Failed to make page containing target function " 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "copy-on-write."); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_ACCESS_DENIED; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* preamble_stub = reinterpret_cast<unsigned char*>( 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_function_stub); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Disassemble the preamble of stub and copy the bytes back to target. 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we've done any conditional jumps in the preamble we need to convert 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // them back to the orignal REL8 jumps in the target. 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MiniDisassembler disassembler; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int preamble_bytes = 0; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int target_bytes = 0; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (target_bytes < kRequiredTargetPatchBytes) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int cur_bytes = 0; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstructionType instruction_type = 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disassembler.Disassemble(preamble_stub + preamble_bytes, cur_bytes); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IT_JUMP == instruction_type) { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int jump_bytes = 0; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsNearConditionalJump(preamble_stub + preamble_bytes, cur_bytes) || 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IsNearRelativeJump(preamble_stub + preamble_bytes, cur_bytes) || 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IsNearAbsoluteCall(preamble_stub + preamble_bytes, cur_bytes) || 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IsNearRelativeCall(preamble_stub + preamble_bytes, cur_bytes)) { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jump_ret = PatchNearJumpOrCall(preamble_stub + preamble_bytes, 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cur_bytes, target + target_bytes, 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &jump_bytes, MAX_PREAMBLE_STUB_SIZE); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (jump_ret == SIDESTEP_JUMP_INSTRUCTION) { 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Found unsupported jump instruction in stub!!"); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_UNSUPPORTED_INSTRUCTION; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_bytes += jump_bytes; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (IT_GENERIC == instruction_type) { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes)) { 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int mov_bytes = 0; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (PatchMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes, 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target + target_bytes, &mov_bytes, 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAX_PREAMBLE_STUB_SIZE) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) != SIDESTEP_SUCCESS) { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Found unsupported generic instruction in stub!!"); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_UNSUPPORTED_INSTRUCTION; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(target + target_bytes), 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(reinterpret_cast<unsigned char*>( 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) original_function_stub) + preamble_bytes), cur_bytes); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_bytes += cur_bytes; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Found unsupported instruction in stub!!"); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_UNSUPPORTED_INSTRUCTION; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preamble_bytes += cur_bytes; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FreePreambleBlock(reinterpret_cast<unsigned char*>(original_function_stub)); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Restore the protection of the first kRequiredTargetPatchBytes bytes of 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // target to what they were before we started goofing around. 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) succeeded = ::VirtualProtect(reinterpret_cast<void*>(target), 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kRequiredTargetPatchBytes, 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_target_function_protect, 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &old_target_function_protect); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Flush the instruction cache to make sure the processor doesn't execute the 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // old version of the instructions (before our patch). 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See comment on FlushInstructionCache elsewhere in this file. 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) succeeded = ::FlushInstructionCache(::GetCurrentProcess(), 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target, 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAX_PREAMBLE_STUB_SIZE); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!succeeded) { 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && "Failed to flush instruction cache."); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_UNEXPECTED; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_LOG("PreamblePatcher::Unpatch successfully unpatched."); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_SUCCESS; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PreamblePatcher::Initialize() { 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!initialized_) { 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SYSTEM_INFO si = { 0 }; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::GetSystemInfo(&si); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) granularity_ = si.dwAllocationGranularity; 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pagesize_ = si.dwPageSize; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) initialized_ = true; 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unsigned char* PreamblePatcher::AllocPreambleBlockNear(void* target) { 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreamblePage* preamble_page = preamble_pages_; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (preamble_page != NULL) { 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (preamble_page->free_ != NULL) { 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __int64 val = reinterpret_cast<__int64>(preamble_page) - 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<__int64>(target); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((val > 0 && val + pagesize_ <= INT_MAX) || 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (val < 0 && val >= INT_MIN)) { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preamble_page = preamble_page->next_; 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The free_ member of the page is used to store the next available block 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of memory to use or NULL if there are no chunks available, in which case 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we'll allocate a new page. 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (preamble_page == NULL || preamble_page->free_ == NULL) { 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a new preamble page and initialize the free list 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preamble_page = reinterpret_cast<PreamblePage*>(AllocPageNear(target)); 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(preamble_page != NULL && "Could not allocate page!"); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void** pp = &preamble_page->free_; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* ptr = reinterpret_cast<unsigned char*>(preamble_page) + 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAX_PREAMBLE_STUB_SIZE; 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* limit = reinterpret_cast<unsigned char*>(preamble_page) + 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pagesize_; 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ptr < limit) { 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pp = ptr; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pp = reinterpret_cast<void**>(ptr); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptr += MAX_PREAMBLE_STUB_SIZE; 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *pp = NULL; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Insert the new page into the list 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preamble_page->magic_ = kPreamblePageMagic; 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preamble_page->next_ = preamble_pages_; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preamble_pages_ = preamble_page; 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* ret = reinterpret_cast<unsigned char*>(preamble_page->free_); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preamble_page->free_ = *(reinterpret_cast<void**>(preamble_page->free_)); 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret; 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PreamblePatcher::FreePreambleBlock(unsigned char* block) { 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(block != NULL); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(granularity_ != 0); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uintptr_t ptr = reinterpret_cast<uintptr_t>(block); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ptr -= ptr & (granularity_ - 1); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreamblePage* preamble_page = reinterpret_cast<PreamblePage*>(ptr); 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(preamble_page->magic_ == kPreamblePageMagic); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *(reinterpret_cast<void**>(block)) = preamble_page->free_; 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) preamble_page->free_ = block; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* PreamblePatcher::AllocPageNear(void* target) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MEMORY_BASIC_INFORMATION mbi = { 0 }; 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!::VirtualQuery(target, &mbi, sizeof(mbi))) { 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && "VirtualQuery failed on target address"); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (initialized_ == false) { 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PreamblePatcher::Initialize(); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(initialized_); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* pv = NULL; 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* allocation_base = reinterpret_cast<unsigned char*>( 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mbi.AllocationBase); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __int64 i = 1; 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool high_target = reinterpret_cast<__int64>(target) > UINT_MAX; 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (pv == NULL) { 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __int64 val = reinterpret_cast<__int64>(allocation_base) - 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (i * granularity_); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (high_target && 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<__int64>(target) - val > INT_MAX) { 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're further than 2GB from the target 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (val <= NULL) { 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Less than 0 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pv = ::VirtualAlloc(reinterpret_cast<void*>(allocation_base - 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (i++ * granularity_)), 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pagesize_, MEM_COMMIT | MEM_RESERVE, 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PAGE_EXECUTE_READWRITE); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We couldn't allocate low, try to allocate high 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pv == NULL) { 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i = 1; 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Round up to the next multiple of page granularity 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) allocation_base = reinterpret_cast<unsigned char*>( 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (reinterpret_cast<__int64>(target) & 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (~(granularity_ - 1))) + granularity_); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (pv == NULL) { 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __int64 val = reinterpret_cast<__int64>(allocation_base) + 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (i * granularity_) - reinterpret_cast<__int64>(target); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (val > INT_MAX || val < 0) { 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're too far or we overflowed 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pv = ::VirtualAlloc(reinterpret_cast<void*>(allocation_base + 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (i++ * granularity_)), 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pagesize_, MEM_COMMIT | MEM_RESERVE, 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PAGE_EXECUTE_READWRITE); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return pv; 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsShortConditionalJump( 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target, 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int instruction_size) { 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (*(target) & 0x70) == 0x70 && instruction_size == 2; 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsNearConditionalJump( 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target, 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int instruction_size) { 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *(target) == 0xf && (*(target + 1) & 0x80) == 0x80 && 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) instruction_size == 6; 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsNearRelativeJump( 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target, 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int instruction_size) { 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *(target) == 0xe9 && instruction_size == 5; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsNearAbsoluteCall( 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target, 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int instruction_size) { 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *(target) == 0xff && (*(target + 1) & 0x10) == 0x10 && 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) instruction_size == 6; 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsNearRelativeCall( 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target, 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int instruction_size) { 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *(target) == 0xe8 && instruction_size == 5; 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsMovWithDisplacement( 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target, 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int instruction_size) { 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In this case, the ModRM byte's mod field will be 0 and r/m will be 101b (5) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return instruction_size == 7 && *target == 0x48 && *(target + 1) == 0x8b && 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*(target + 2) >> 6) == 0 && (*(target + 2) & 0x7) == 5; 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::PatchShortConditionalJump( 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* source, 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int instruction_size, 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target, 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int* target_bytes, 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int target_size) { 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* original_jump_dest = (source + 2) + source[1]; 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* stub_jump_from = target + 6; 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __int64 fixup_jump_offset = original_jump_dest - stub_jump_from; 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) { 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Unable to fix up short jump because target" 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " is too far away."); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_JUMP_INSTRUCTION; 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_bytes = 6; 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target_size > *target_bytes) { 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convert the short jump to a near jump. 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 0f 8x xx xx xx xx = Jcc rel32off 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned short jmpcode = ((0x80 | (source[0] & 0xf)) << 8) | 0x0f; 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(target), 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(&jmpcode), 2); 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(target + 2), 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(&fixup_jump_offset), 4); 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_SUCCESS; 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::PatchNearJumpOrCall( 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* source, 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int instruction_size, 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target, 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int* target_bytes, 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int target_size) { 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(instruction_size == 5 || instruction_size == 6); 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int jmp_offset_in_instruction = instruction_size == 5 ? 1 : 2; 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* original_jump_dest = reinterpret_cast<unsigned char *>( 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<__int64>(source + instruction_size) + 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *(reinterpret_cast<int*>(source + jmp_offset_in_instruction))); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* stub_jump_from = target + instruction_size; 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __int64 fixup_jump_offset = original_jump_dest - stub_jump_from; 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) { 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Unable to fix up near jump because target" 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " is too far away."); 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_JUMP_INSTRUCTION; 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fixup_jump_offset < SCHAR_MAX && fixup_jump_offset > SCHAR_MIN)) { 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_bytes = 2; 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target_size > *target_bytes) { 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the new offset is in range, use a short jump instead of a near jump. 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (source[0] == ASM_JCC32REL_0 && 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (source[1] & ASM_JCC32REL_1_MASK) == ASM_JCC32REL_1_MASK) { 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned short jmpcode = (static_cast<unsigned char>( 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fixup_jump_offset) << 8) | (0x70 | (source[1] & 0xf)); 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(target), 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(&jmpcode), 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2); 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target[0] = ASM_JMP8REL; 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target[1] = static_cast<unsigned char>(fixup_jump_offset); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_bytes = instruction_size; 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target_size > *target_bytes) { 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(target), 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(source), 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmp_offset_in_instruction); 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(target + jmp_offset_in_instruction), 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(&fixup_jump_offset), 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4); 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_SUCCESS; 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::PatchMovWithDisplacement( 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* source, 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int instruction_size, 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* target, 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int* target_bytes, 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int target_size) { 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(instruction_size == 7); 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int mov_offset_in_instruction = 3; // 0x48 0x8b 0x0d <offset> 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* original_mov_dest = reinterpret_cast<unsigned char*>( 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<__int64>(source + instruction_size) + 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *(reinterpret_cast<int*>(source + mov_offset_in_instruction))); 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char* stub_mov_from = target + instruction_size; 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __int64 fixup_mov_offset = original_mov_dest - stub_mov_from; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fixup_mov_offset > INT_MAX || fixup_mov_offset < INT_MIN) { 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SIDESTEP_ASSERT(false && 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Unable to fix up near MOV because target is too far away."); 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_UNEXPECTED; 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *target_bytes = instruction_size; 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target_size > *target_bytes) { 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(target), 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(source), 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mov_offset_in_instruction); 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(reinterpret_cast<void*>(target + mov_offset_in_instruction), 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void*>(&fixup_mov_offset), 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4); 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SIDESTEP_SUCCESS; 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; // namespace sidestep 685