1/* Copyright (c) 2007, Google Inc. 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * --- 31 * Author: Joi Sigurdsson 32 * Author: Scott Francis 33 * 34 * Implementation of PreamblePatcher 35 */ 36 37#include "preamble_patcher.h" 38 39#include "mini_disassembler.h" 40 41// Definitions of assembly statements we need 42#define ASM_JMP32REL 0xE9 43#define ASM_INT3 0xCC 44#define ASM_NOP 0x90 45// X64 opcodes 46#define ASM_MOVRAX_IMM 0xB8 47#define ASM_REXW 0x48 48#define ASM_JMP 0xFF 49#define ASM_JMP_RAX 0xE0 50#define ASM_PUSH 0x68 51#define ASM_RET 0xC3 52 53namespace sidestep { 54 55SideStepError PreamblePatcher::RawPatchWithStub( 56 void* target_function, 57 void* replacement_function, 58 unsigned char* preamble_stub, 59 unsigned long stub_size, 60 unsigned long* bytes_needed) { 61 if ((NULL == target_function) || 62 (NULL == replacement_function) || 63 (NULL == preamble_stub)) { 64 SIDESTEP_ASSERT(false && 65 "Invalid parameters - either pTargetFunction or " 66 "pReplacementFunction or pPreambleStub were NULL."); 67 return SIDESTEP_INVALID_PARAMETER; 68 } 69 70 // TODO(V7:joi) Siggi and I just had a discussion and decided that both 71 // patching and unpatching are actually unsafe. We also discussed a 72 // method of making it safe, which is to freeze all other threads in the 73 // process, check their thread context to see if their eip is currently 74 // inside the block of instructions we need to copy to the stub, and if so 75 // wait a bit and try again, then unfreeze all threads once we've patched. 76 // Not implementing this for now since we're only using SideStep for unit 77 // testing, but if we ever use it for production code this is what we 78 // should do. 79 // 80 // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using 81 // FPU instructions, and on newer processors we could use cmpxchg8b or 82 // cmpxchg16b. So it might be possible to do the patching/unpatching 83 // atomically and avoid having to freeze other threads. Note though, that 84 // doing it atomically does not help if one of the other threads happens 85 // to have its eip in the middle of the bytes you change while you change 86 // them. 87 unsigned char* target = reinterpret_cast<unsigned char*>(target_function); 88 unsigned int required_trampoline_bytes = 0; 89 const unsigned int kRequiredStubJumpBytes = 5; 90 const unsigned int kRequiredTargetPatchBytes = 5; 91 92 // Initialize the stub with INT3's just in case. 93 if (stub_size) { 94 memset(preamble_stub, 0xcc, stub_size); 95 } 96 if (kIs64BitBinary) { 97 // In 64-bit mode JMP instructions are always relative to RIP. If the 98 // replacement - target offset is > 2GB, we can't JMP to the replacement 99 // function. In this case, we're going to use a trampoline - that is, 100 // we're going to do a relative jump to a small chunk of code in the stub 101 // that will then do the absolute jump to the replacement function. By 102 // doing this, we only need to patch 5 bytes in the target function, as 103 // opposed to patching 12 bytes if we were to do an absolute jump. 104 // 105 // Note that the first byte of the trampoline is a NOP instruction. This 106 // is used as a trampoline signature that will be detected when unpatching 107 // the function. 108 // 109 // jmp <trampoline> 110 // 111 // trampoline: 112 // nop 113 // mov rax, <replacement_function> 114 // jmp rax 115 // 116 __int64 replacement_target_offset = reinterpret_cast<__int64>( 117 replacement_function) - reinterpret_cast<__int64>(target) - 5; 118 if (replacement_target_offset > INT_MAX 119 || replacement_target_offset < INT_MIN) { 120 // The stub needs to be within 2GB of the target for the trampoline to 121 // work! 122 __int64 trampoline_offset = reinterpret_cast<__int64>(preamble_stub) 123 - reinterpret_cast<__int64>(target) - 5; 124 if (trampoline_offset > INT_MAX || trampoline_offset < INT_MIN) { 125 // We're screwed. 126 SIDESTEP_ASSERT(false 127 && "Preamble stub is too far from target to patch."); 128 return SIDESTEP_UNEXPECTED; 129 } 130 required_trampoline_bytes = 13; 131 } 132 } 133 134 // Let's disassemble the preamble of the target function to see if we can 135 // patch, and to see how much of the preamble we need to take. We need 5 136 // bytes for our jmp instruction, so let's find the minimum number of 137 // instructions to get 5 bytes. 138 MiniDisassembler disassembler; 139 unsigned int preamble_bytes = 0; 140 unsigned int stub_bytes = 0; 141 while (preamble_bytes < kRequiredTargetPatchBytes) { 142 unsigned int cur_bytes = 0; 143 InstructionType instruction_type = 144 disassembler.Disassemble(target + preamble_bytes, cur_bytes); 145 if (IT_JUMP == instruction_type) { 146 unsigned int jump_bytes = 0; 147 SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION; 148 if (IsShortConditionalJump(target + preamble_bytes, cur_bytes)) { 149 jump_ret = PatchShortConditionalJump(target + preamble_bytes, cur_bytes, 150 preamble_stub + stub_bytes, 151 &jump_bytes, 152 stub_size - stub_bytes); 153 } else if (IsNearConditionalJump(target + preamble_bytes, cur_bytes) || 154 IsNearRelativeJump(target + preamble_bytes, cur_bytes) || 155 IsNearAbsoluteCall(target + preamble_bytes, cur_bytes) || 156 IsNearRelativeCall(target + preamble_bytes, cur_bytes)) { 157 jump_ret = PatchNearJumpOrCall(target + preamble_bytes, cur_bytes, 158 preamble_stub + stub_bytes, &jump_bytes, 159 stub_size - stub_bytes); 160 } 161 if (jump_ret != SIDESTEP_SUCCESS) { 162 SIDESTEP_ASSERT(false && 163 "Unable to patch because there is an unhandled branch " 164 "instruction in the initial preamble bytes."); 165 return SIDESTEP_JUMP_INSTRUCTION; 166 } 167 stub_bytes += jump_bytes; 168 } else if (IT_RETURN == instruction_type) { 169 SIDESTEP_ASSERT(false && 170 "Unable to patch because function is too short"); 171 return SIDESTEP_FUNCTION_TOO_SMALL; 172 } else if (IT_GENERIC == instruction_type) { 173 if (IsMovWithDisplacement(target + preamble_bytes, cur_bytes)) { 174 unsigned int mov_bytes = 0; 175 if (PatchMovWithDisplacement(target + preamble_bytes, cur_bytes, 176 preamble_stub + stub_bytes, &mov_bytes, 177 stub_size - stub_bytes) 178 != SIDESTEP_SUCCESS) { 179 return SIDESTEP_UNSUPPORTED_INSTRUCTION; 180 } 181 stub_bytes += mov_bytes; 182 } else { 183 memcpy(reinterpret_cast<void*>(preamble_stub + stub_bytes), 184 reinterpret_cast<void*>(target + preamble_bytes), cur_bytes); 185 stub_bytes += cur_bytes; 186 } 187 } else { 188 SIDESTEP_ASSERT(false && 189 "Disassembler encountered unsupported instruction " 190 "(either unused or unknown"); 191 return SIDESTEP_UNSUPPORTED_INSTRUCTION; 192 } 193 preamble_bytes += cur_bytes; 194 } 195 196 if (NULL != bytes_needed) 197 *bytes_needed = stub_bytes + kRequiredStubJumpBytes 198 + required_trampoline_bytes; 199 200 // Inv: cbPreamble is the number of bytes (at least 5) that we need to take 201 // from the preamble to have whole instructions that are 5 bytes or more 202 // in size total. The size of the stub required is cbPreamble + 203 // kRequiredStubJumpBytes (5) + required_trampoline_bytes (0 or 13) 204 if (stub_bytes + kRequiredStubJumpBytes + required_trampoline_bytes 205 > stub_size) { 206 SIDESTEP_ASSERT(false); 207 return SIDESTEP_INSUFFICIENT_BUFFER; 208 } 209 210 // Now, make a jmp instruction to the rest of the target function (minus the 211 // preamble bytes we moved into the stub) and copy it into our preamble-stub. 212 // find address to jump to, relative to next address after jmp instruction 213#ifdef _MSC_VER 214#pragma warning(push) 215#pragma warning(disable:4244) 216#endif 217 int relative_offset_to_target_rest 218 = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) - 219 (preamble_stub + stub_bytes + kRequiredStubJumpBytes)); 220#ifdef _MSC_VER 221#pragma warning(pop) 222#endif 223 // jmp (Jump near, relative, displacement relative to next instruction) 224 preamble_stub[stub_bytes] = ASM_JMP32REL; 225 // copy the address 226 memcpy(reinterpret_cast<void*>(preamble_stub + stub_bytes + 1), 227 reinterpret_cast<void*>(&relative_offset_to_target_rest), 4); 228 229 if (kIs64BitBinary && required_trampoline_bytes != 0) { 230 // Construct the trampoline 231 unsigned int trampoline_pos = stub_bytes + kRequiredStubJumpBytes; 232 preamble_stub[trampoline_pos] = ASM_NOP; 233 preamble_stub[trampoline_pos + 1] = ASM_REXW; 234 preamble_stub[trampoline_pos + 2] = ASM_MOVRAX_IMM; 235 memcpy(reinterpret_cast<void*>(preamble_stub + trampoline_pos + 3), 236 reinterpret_cast<void*>(&replacement_function), 237 sizeof(void *)); 238 preamble_stub[trampoline_pos + 11] = ASM_JMP; 239 preamble_stub[trampoline_pos + 12] = ASM_JMP_RAX; 240 241 // Now update replacement_function to point to the trampoline 242 replacement_function = preamble_stub + trampoline_pos; 243 } 244 245 // Inv: preamble_stub points to assembly code that will execute the 246 // original function by first executing the first cbPreamble bytes of the 247 // preamble, then jumping to the rest of the function. 248 249 // Overwrite the first 5 bytes of the target function with a jump to our 250 // replacement function. 251 // (Jump near, relative, displacement relative to next instruction) 252 target[0] = ASM_JMP32REL; 253 254 // Find offset from instruction after jmp, to the replacement function. 255#ifdef _MSC_VER 256#pragma warning(push) 257#pragma warning(disable:4244) 258#endif 259 int offset_to_replacement_function = 260 reinterpret_cast<unsigned char*>(replacement_function) - 261 reinterpret_cast<unsigned char*>(target) - 5; 262#ifdef _MSC_VER 263#pragma warning(pop) 264#endif 265 // complete the jmp instruction 266 memcpy(reinterpret_cast<void*>(target + 1), 267 reinterpret_cast<void*>(&offset_to_replacement_function), 4); 268 269 // Set any remaining bytes that were moved to the preamble-stub to INT3 so 270 // as not to cause confusion (otherwise you might see some strange 271 // instructions if you look at the disassembly, or even invalid 272 // instructions). Also, by doing this, we will break into the debugger if 273 // some code calls into this portion of the code. If this happens, it 274 // means that this function cannot be patched using this patcher without 275 // further thought. 276 if (preamble_bytes > kRequiredTargetPatchBytes) { 277 memset(reinterpret_cast<void*>(target + kRequiredTargetPatchBytes), 278 ASM_INT3, preamble_bytes - kRequiredTargetPatchBytes); 279 } 280 281 // Inv: The memory pointed to by target_function now points to a relative 282 // jump instruction that jumps over to the preamble_stub. The preamble 283 // stub contains the first stub_size bytes of the original target 284 // function's preamble code, followed by a relative jump back to the next 285 // instruction after the first cbPreamble bytes. 286 // 287 // In 64-bit mode the memory pointed to by target_function *may* point to a 288 // relative jump instruction that jumps to a trampoline which will then 289 // perform an absolute jump to the replacement function. The preamble stub 290 // still contains the original target function's preamble code, followed by a 291 // jump back to the instructions after the first preamble bytes. 292 // 293 return SIDESTEP_SUCCESS; 294} 295 296}; // namespace sidestep 297