| OLD | NEW |
| 1 /* Copyright (c) 2007, Google Inc. | 1 /* Copyright (c) 2007, Google Inc. |
| 2 * All rights reserved. | 2 * All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 * | 29 * |
| 30 * --- | 30 * --- |
| 31 * Author: Joi Sigurdsson | 31 * Author: Joi Sigurdsson |
| 32 * Author: Scott Francis | |
| 33 * | 32 * |
| 34 * Implementation of PreamblePatcher | 33 * Implementation of PreamblePatcher |
| 35 */ | 34 */ |
| 36 | 35 |
| 37 #include "preamble_patcher.h" | 36 #include "preamble_patcher.h" |
| 38 | 37 |
| 39 #include "mini_disassembler.h" | 38 #include "mini_disassembler.h" |
| 40 | 39 |
| 41 // compatibility shims | 40 // compatibility shims |
| 42 #include "base/logging.h" | 41 #include "base/logging.h" |
| 43 | 42 |
| 44 // Definitions of assembly statements we need | 43 // Definitions of assembly statements we need |
| 45 #define ASM_JMP32REL 0xE9 | 44 #define ASM_JMP32REL 0xE9 |
| 46 #define ASM_INT3 0xCC | 45 #define ASM_INT3 0xCC |
| 47 #define ASM_JMP32ABS_0 0xFF | 46 #define ASM_JMP32ABS_0 0xFF |
| 48 #define ASM_JMP32ABS_1 0x25 | 47 #define ASM_JMP32ABS_1 0x25 |
| 49 #define ASM_JMP8REL 0xEB | 48 #define ASM_JMP8REL 0xEB |
| 50 #define ASM_JCC32REL_0 0x0F | |
| 51 #define ASM_JCC32REL_1_MASK 0x80 | |
| 52 #define ASM_NOP 0x90 | |
| 53 // X64 opcodes | |
| 54 #define ASM_REXW 0x48 | |
| 55 #define ASM_MOVRAX_IMM 0xB8 | |
| 56 #define ASM_JMP 0xFF | |
| 57 #define ASM_JMP_RAX 0xE0 | |
| 58 | 49 |
| 59 namespace sidestep { | 50 namespace sidestep { |
| 60 | 51 |
| 61 PreamblePatcher::PreamblePage* PreamblePatcher::preamble_pages_ = NULL; | |
| 62 long PreamblePatcher::granularity_ = 0; | |
| 63 long PreamblePatcher::pagesize_ = 0; | |
| 64 bool PreamblePatcher::initialized_ = false; | |
| 65 | |
| 66 static const unsigned int kPreamblePageMagic = 0x4347414D; // "MAGC" | |
| 67 | |
| 68 // Handle a special case that we see with functions that point into an | 52 // Handle a special case that we see with functions that point into an |
| 69 // IAT table (including functions linked statically into the | 53 // IAT table (including functions linked statically into the |
| 70 // application): these function already starts with ASM_JMP32*. For | 54 // application): these function already starts with ASM_JMP32*. For |
| 71 // instance, malloc() might be implemented as a JMP to __malloc(). | 55 // instance, malloc() might be implemented as a JMP to __malloc(). |
| 72 // This function follows the initial JMPs for us, until we get to the | 56 // This function follows the initial JMPs for us, until we get to the |
| 73 // place where the actual code is defined. If we get to STOP_BEFORE, | 57 // place where the actual code is defined. If we get to STOP_BEFORE, |
| 74 // we return the address before stop_before. The stop_before_trampoline | 58 // we return the address before stop_before. |
| 75 // flag is used in 64-bit mode. If true, we will return the address | |
| 76 // before a trampoline is detected. Trampolines are defined as: | |
| 77 // | |
| 78 // nop | |
| 79 // mov rax, <replacement_function> | |
| 80 // jmp rax | |
| 81 // | |
| 82 // See PreamblePatcher::RawPatchWithStub for more information. | |
| 83 void* PreamblePatcher::ResolveTargetImpl(unsigned char* target, | 59 void* PreamblePatcher::ResolveTargetImpl(unsigned char* target, |
| 84 unsigned char* stop_before, | 60 unsigned char* stop_before) { |
| 85 bool stop_before_trampoline) { | |
| 86 if (target == NULL) | 61 if (target == NULL) |
| 87 return NULL; | 62 return NULL; |
| 88 while (1) { | 63 while (1) { |
| 89 unsigned char* new_target; | 64 unsigned char* new_target; |
| 90 if (target[0] == ASM_JMP32REL) { | 65 if (target[0] == ASM_JMP32REL) { |
| 91 // target[1-4] holds the place the jmp goes to, but it's | 66 // target[1-4] holds the place the jmp goes to, but it's |
| 92 // relative to the next instruction. | 67 // relative to the next instruction. |
| 93 int relative_offset; // Windows guarantees int is 4 bytes | 68 int relative_offset; // Windows guarantees int is 4 bytes |
| 94 SIDESTEP_ASSERT(sizeof(relative_offset) == 4); | 69 SIDESTEP_ASSERT(sizeof(relative_offset) == 4); |
| 95 memcpy(reinterpret_cast<void*>(&relative_offset), | 70 memcpy(reinterpret_cast<void*>(&relative_offset), |
| 96 reinterpret_cast<void*>(target + 1), 4); | 71 reinterpret_cast<void*>(target + 1), 4); |
| 97 new_target = target + 5 + relative_offset; | 72 new_target = target + 5 + relative_offset; |
| 98 } else if (target[0] == ASM_JMP8REL) { | 73 } else if (target[0] == ASM_JMP8REL) { |
| 99 // Visual Studio 7.1 implements new[] as an 8 bit jump to new | 74 // Visual Studio 7.1 implements new[] as an 8 bit jump to new |
| 100 signed char relative_offset; | 75 signed char relative_offset; |
| 101 memcpy(reinterpret_cast<void*>(&relative_offset), | 76 memcpy(reinterpret_cast<void*>(&relative_offset), |
| 102 reinterpret_cast<void*>(target + 1), 1); | 77 reinterpret_cast<void*>(target + 1), 1); |
| 103 new_target = target + 2 + relative_offset; | 78 new_target = target + 2 + relative_offset; |
| 104 } else if (target[0] == ASM_JMP32ABS_0 && | 79 } else if (target[0] == ASM_JMP32ABS_0 && |
| 105 target[1] == ASM_JMP32ABS_1) { | 80 target[1] == ASM_JMP32ABS_1) { |
| 106 // Visual studio seems to sometimes do it this way instead of the | 81 // Visual studio seems to sometimes do it this way instead of the |
| 107 // previous way. Not sure what the rules are, but it was happening | 82 // previous way. Not sure what the rules are, but it was happening |
| 108 // with operator new in some binaries. | 83 // with operator new in some binaries. |
| 109 void** new_target_v; | 84 void **new_target_v; |
| 110 if (kIs64BitBinary) { | 85 SIDESTEP_ASSERT(sizeof(new_target) == 4); |
| 111 // In 64-bit mode JMPs are RIP-relative, not absolute | 86 memcpy(&new_target_v, reinterpret_cast<void*>(target + 2), 4); |
| 112 int target_offset; | |
| 113 memcpy(reinterpret_cast<void*>(&target_offset), | |
| 114 reinterpret_cast<void*>(target + 2), 4); | |
| 115 new_target_v = reinterpret_cast<void**>(target + target_offset + 6); | |
| 116 } else { | |
| 117 SIDESTEP_ASSERT(sizeof(new_target) == 4); | |
| 118 memcpy(&new_target_v, reinterpret_cast<void*>(target + 2), 4); | |
| 119 } | |
| 120 new_target = reinterpret_cast<unsigned char*>(*new_target_v); | 87 new_target = reinterpret_cast<unsigned char*>(*new_target_v); |
| 121 } else { | 88 } else { |
| 122 break; | 89 break; |
| 123 } | 90 } |
| 124 if (new_target == stop_before) | 91 if (new_target == stop_before) |
| 125 break; | 92 break; |
| 126 if (stop_before_trampoline && *new_target == ASM_NOP | |
| 127 && new_target[1] == ASM_REXW && new_target[2] == ASM_MOVRAX_IMM) | |
| 128 break; | |
| 129 target = new_target; | 93 target = new_target; |
| 130 } | 94 } |
| 131 return target; | 95 return target; |
| 132 } | 96 } |
| 133 | 97 |
| 134 // Special case scoped_ptr to avoid dependency on scoped_ptr below. | 98 // Special case scoped_ptr to avoid dependency on scoped_ptr below. |
| 135 class DeleteUnsignedCharArray { | 99 class DeleteUnsignedCharArray { |
| 136 public: | 100 public: |
| 137 DeleteUnsignedCharArray(unsigned char* array) : array_(array) { | 101 DeleteUnsignedCharArray(unsigned char* array) : array_(array) { |
| 138 } | 102 } |
| 139 | 103 |
| 140 ~DeleteUnsignedCharArray() { | 104 ~DeleteUnsignedCharArray() { |
| 141 if (array_) { | 105 if (array_) { |
| 142 PreamblePatcher::FreePreambleBlock(array_); | 106 delete [] array_; |
| 143 } | 107 } |
| 144 } | 108 } |
| 145 | 109 |
| 146 unsigned char* Release() { | 110 unsigned char* Release() { |
| 147 unsigned char* temp = array_; | 111 unsigned char* temp = array_; |
| 148 array_ = NULL; | 112 array_ = NULL; |
| 149 return temp; | 113 return temp; |
| 150 } | 114 } |
| 151 | 115 |
| 152 private: | 116 private: |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 | 184 |
| 221 SideStepError PreamblePatcher::RawPatch(void* target_function, | 185 SideStepError PreamblePatcher::RawPatch(void* target_function, |
| 222 void* replacement_function, | 186 void* replacement_function, |
| 223 void** original_function_stub) { | 187 void** original_function_stub) { |
| 224 if (!target_function || !replacement_function || !original_function_stub || | 188 if (!target_function || !replacement_function || !original_function_stub || |
| 225 (*original_function_stub) || target_function == replacement_function) { | 189 (*original_function_stub) || target_function == replacement_function) { |
| 226 SIDESTEP_ASSERT(false && "Preconditions not met"); | 190 SIDESTEP_ASSERT(false && "Preconditions not met"); |
| 227 return SIDESTEP_INVALID_PARAMETER; | 191 return SIDESTEP_INVALID_PARAMETER; |
| 228 } | 192 } |
| 229 | 193 |
| 230 BOOL succeeded = FALSE; | 194 // @see MAX_PREAMBLE_STUB_SIZE for an explanation of how we arrives at |
| 231 | 195 // this size |
| 232 // First, deal with a special case that we see with functions that | 196 unsigned char* preamble_stub = new unsigned char[MAX_PREAMBLE_STUB_SIZE]; |
| 233 // point into an IAT table (including functions linked statically | |
| 234 // into the application): these function already starts with | |
| 235 // ASM_JMP32REL. For instance, malloc() might be implemented as a | |
| 236 // JMP to __malloc(). In that case, we replace the destination of | |
| 237 // the JMP (__malloc), rather than the JMP itself (malloc). This | |
| 238 // way we get the correct behavior no matter how malloc gets called. | |
| 239 void* new_target = ResolveTarget(target_function); | |
| 240 if (new_target != target_function) { | |
| 241 target_function = new_target; | |
| 242 } | |
| 243 | |
| 244 // In 64-bit mode, preamble_stub must be within 2GB of target function | |
| 245 // so that if target contains a jump, we can translate it. | |
| 246 unsigned char* preamble_stub = AllocPreambleBlockNear(target_function); | |
| 247 if (!preamble_stub) { | 197 if (!preamble_stub) { |
| 248 SIDESTEP_ASSERT(false && "Unable to allocate preamble-stub."); | 198 SIDESTEP_ASSERT(false && "Unable to allocate preamble-stub."); |
| 249 return SIDESTEP_INSUFFICIENT_BUFFER; | 199 return SIDESTEP_INSUFFICIENT_BUFFER; |
| 250 } | 200 } |
| 251 | 201 |
| 252 // Frees the array at end of scope. | 202 // Frees the array at end of scope. |
| 253 DeleteUnsignedCharArray guard_preamble_stub(preamble_stub); | 203 DeleteUnsignedCharArray guard_preamble_stub(preamble_stub); |
| 254 | 204 |
| 205 // Change the protection of the newly allocated preamble stub to |
| 206 // PAGE_EXECUTE_READWRITE. This is required to work with DEP (Data |
| 207 // Execution Prevention) which will cause an exception if code is executed |
| 208 // from a page on which you do not have read access. |
| 209 DWORD old_stub_protect = 0; |
| 210 BOOL succeeded = ::VirtualProtect(preamble_stub, MAX_PREAMBLE_STUB_SIZE, |
| 211 PAGE_EXECUTE_READWRITE, &old_stub_protect); |
| 212 if (!succeeded) { |
| 213 SIDESTEP_ASSERT(false && |
| 214 "Failed to make page preamble stub read-write-execute."); |
| 215 return SIDESTEP_ACCESS_DENIED; |
| 216 } |
| 217 |
| 255 SideStepError error_code = RawPatchWithStubAndProtections( | 218 SideStepError error_code = RawPatchWithStubAndProtections( |
| 256 target_function, replacement_function, preamble_stub, | 219 target_function, replacement_function, preamble_stub, |
| 257 MAX_PREAMBLE_STUB_SIZE, NULL); | 220 MAX_PREAMBLE_STUB_SIZE, NULL); |
| 258 | 221 |
| 259 if (SIDESTEP_SUCCESS != error_code) { | 222 if (SIDESTEP_SUCCESS != error_code) { |
| 260 SIDESTEP_ASSERT(false); | 223 SIDESTEP_ASSERT(false); |
| 261 return error_code; | 224 return error_code; |
| 262 } | 225 } |
| 263 | 226 |
| 264 // Flush the instruction cache to make sure the processor doesn't execute the | 227 // Flush the instruction cache to make sure the processor doesn't execute the |
| (...skipping 25 matching lines...) Expand all Loading... |
| 290 SideStepError PreamblePatcher::Unpatch(void* target_function, | 253 SideStepError PreamblePatcher::Unpatch(void* target_function, |
| 291 void* replacement_function, | 254 void* replacement_function, |
| 292 void* original_function_stub) { | 255 void* original_function_stub) { |
| 293 SIDESTEP_ASSERT(target_function && replacement_function && | 256 SIDESTEP_ASSERT(target_function && replacement_function && |
| 294 original_function_stub); | 257 original_function_stub); |
| 295 if (!target_function || !replacement_function || | 258 if (!target_function || !replacement_function || |
| 296 !original_function_stub) { | 259 !original_function_stub) { |
| 297 return SIDESTEP_INVALID_PARAMETER; | 260 return SIDESTEP_INVALID_PARAMETER; |
| 298 } | 261 } |
| 299 | 262 |
| 263 // We disassemble the preamble of the _stub_ to see how many bytes we |
| 264 // originally copied to the stub. |
| 265 MiniDisassembler disassembler; |
| 266 unsigned int preamble_bytes = 0; |
| 267 while (preamble_bytes < 5) { |
| 268 InstructionType instruction_type = |
| 269 disassembler.Disassemble( |
| 270 reinterpret_cast<unsigned char*>(original_function_stub) + |
| 271 preamble_bytes, |
| 272 preamble_bytes); |
| 273 if (IT_GENERIC != instruction_type) { |
| 274 SIDESTEP_ASSERT(false && |
| 275 "Should only have generic instructions in stub!!"); |
| 276 return SIDESTEP_UNSUPPORTED_INSTRUCTION; |
| 277 } |
| 278 } |
| 279 |
| 300 // Before unpatching, target_function should be a JMP to | 280 // Before unpatching, target_function should be a JMP to |
| 301 // replacement_function. If it's not, then either it's an error, or | 281 // replacement_function. If it's not, then either it's an error, or |
| 302 // we're falling into the case where the original instruction was a | 282 // we're falling into the case where the original instruction was a |
| 303 // JMP, and we patched the jumped_to address rather than the JMP | 283 // JMP, and we patched the jumped_to address rather than the JMP |
| 304 // itself. (For instance, if malloc() is just a JMP to __malloc(), | 284 // itself. (For instance, if malloc() is just a JMP to __malloc(), |
| 305 // we patched __malloc() and not malloc().) | 285 // we patched __malloc() and not malloc().) |
| 306 unsigned char* target = reinterpret_cast<unsigned char*>(target_function); | 286 unsigned char* target = reinterpret_cast<unsigned char*>(target_function); |
| 307 target = reinterpret_cast<unsigned char*>( | 287 target = reinterpret_cast<unsigned char*>( |
| 308 ResolveTargetImpl( | 288 ResolveTargetImpl( |
| 309 target, reinterpret_cast<unsigned char*>(replacement_function), | 289 target, reinterpret_cast<unsigned char*>(replacement_function))); |
| 310 true)); | |
| 311 // We should end at the function we patched. When we patch, we insert | 290 // We should end at the function we patched. When we patch, we insert |
| 312 // a ASM_JMP32REL instruction, so look for that as a sanity check. | 291 // a ASM_JMP32REL instruction, so look for that as a sanity check. |
| 313 if (target[0] != ASM_JMP32REL) { | 292 if (target[0] != ASM_JMP32REL) { |
| 314 SIDESTEP_ASSERT(false && | 293 SIDESTEP_ASSERT(false && |
| 315 "target_function does not look like it was patched."); | 294 "target_function does not look like it was patched."); |
| 316 return SIDESTEP_INVALID_PARAMETER; | 295 return SIDESTEP_INVALID_PARAMETER; |
| 317 } | 296 } |
| 318 | 297 |
| 319 const unsigned int kRequiredTargetPatchBytes = 5; | |
| 320 | |
| 321 // We need to be able to write to a process-local copy of the first | 298 // We need to be able to write to a process-local copy of the first |
| 322 // kRequiredTargetPatchBytes bytes of target_function | 299 // MAX_PREAMBLE_STUB_SIZE bytes of target_function |
| 323 DWORD old_target_function_protect = 0; | 300 DWORD old_target_function_protect = 0; |
| 324 BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target), | 301 BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function), |
| 325 kRequiredTargetPatchBytes, | 302 MAX_PREAMBLE_STUB_SIZE, |
| 326 PAGE_EXECUTE_READWRITE, | 303 PAGE_EXECUTE_READWRITE, |
| 327 &old_target_function_protect); | 304 &old_target_function_protect); |
| 328 if (!succeeded) { | 305 if (!succeeded) { |
| 329 SIDESTEP_ASSERT(false && "Failed to make page containing target function " | 306 SIDESTEP_ASSERT(false && "Failed to make page containing target function " |
| 330 "copy-on-write."); | 307 "copy-on-write."); |
| 331 return SIDESTEP_ACCESS_DENIED; | 308 return SIDESTEP_ACCESS_DENIED; |
| 332 } | 309 } |
| 333 | 310 |
| 334 unsigned char* preamble_stub = reinterpret_cast<unsigned char*>( | 311 // Replace the first few bytes of the original function with the bytes we |
| 335 original_function_stub); | 312 // previously moved to the preamble stub. |
| 313 memcpy(reinterpret_cast<void*>(target), |
| 314 original_function_stub, preamble_bytes); |
| 336 | 315 |
| 337 // Disassemble the preamble of stub and copy the bytes back to target. | 316 // Stub is now useless so delete it. |
| 338 // If we've done any conditional jumps in the preamble we need to convert | 317 // [csilvers: Commented out for perftools because it causes big problems |
| 339 // them back to the orignal REL8 jumps in the target. | 318 // when we're unpatching malloc. We just let this live on as a leak.] |
| 340 MiniDisassembler disassembler; | 319 //delete [] reinterpret_cast<unsigned char*>(original_function_stub); |
| 341 unsigned int preamble_bytes = 0; | |
| 342 unsigned int target_bytes = 0; | |
| 343 while (target_bytes < kRequiredTargetPatchBytes) { | |
| 344 unsigned int cur_bytes = 0; | |
| 345 InstructionType instruction_type = | |
| 346 disassembler.Disassemble(preamble_stub + preamble_bytes, cur_bytes); | |
| 347 if (IT_JUMP == instruction_type) { | |
| 348 unsigned int jump_bytes = 0; | |
| 349 SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION; | |
| 350 if (IsNearConditionalJump(preamble_stub + preamble_bytes, cur_bytes) || | |
| 351 IsNearRelativeJump(preamble_stub + preamble_bytes, cur_bytes) || | |
| 352 IsNearAbsoluteCall(preamble_stub + preamble_bytes, cur_bytes) || | |
| 353 IsNearRelativeCall(preamble_stub + preamble_bytes, cur_bytes)) { | |
| 354 jump_ret = PatchNearJumpOrCall(preamble_stub + preamble_bytes, | |
| 355 cur_bytes, target + target_bytes, | |
| 356 &jump_bytes, MAX_PREAMBLE_STUB_SIZE); | |
| 357 } | |
| 358 if (jump_ret == SIDESTEP_JUMP_INSTRUCTION) { | |
| 359 SIDESTEP_ASSERT(false && | |
| 360 "Found unsupported jump instruction in stub!!"); | |
| 361 return SIDESTEP_UNSUPPORTED_INSTRUCTION; | |
| 362 } | |
| 363 target_bytes += jump_bytes; | |
| 364 } else if (IT_GENERIC == instruction_type) { | |
| 365 if (IsMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes)) { | |
| 366 unsigned int mov_bytes = 0; | |
| 367 if (PatchMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes, | |
| 368 target + target_bytes, &mov_bytes, | |
| 369 MAX_PREAMBLE_STUB_SIZE) | |
| 370 != SIDESTEP_SUCCESS) { | |
| 371 SIDESTEP_ASSERT(false && | |
| 372 "Found unsupported generic instruction in stub!!"); | |
| 373 return SIDESTEP_UNSUPPORTED_INSTRUCTION; | |
| 374 } | |
| 375 } else { | |
| 376 memcpy(reinterpret_cast<void*>(target + target_bytes), | |
| 377 reinterpret_cast<void*>(reinterpret_cast<unsigned char*>( | |
| 378 original_function_stub) + preamble_bytes), cur_bytes); | |
| 379 target_bytes += cur_bytes; | |
| 380 } | |
| 381 } else { | |
| 382 SIDESTEP_ASSERT(false && | |
| 383 "Found unsupported instruction in stub!!"); | |
| 384 return SIDESTEP_UNSUPPORTED_INSTRUCTION; | |
| 385 } | |
| 386 preamble_bytes += cur_bytes; | |
| 387 } | |
| 388 | 320 |
| 389 FreePreambleBlock(reinterpret_cast<unsigned char*>(original_function_stub)); | 321 // Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of |
| 390 | |
| 391 // Restore the protection of the first kRequiredTargetPatchBytes bytes of | |
| 392 // target to what they were before we started goofing around. | 322 // target to what they were before we started goofing around. |
| 393 succeeded = ::VirtualProtect(reinterpret_cast<void*>(target), | 323 succeeded = ::VirtualProtect(reinterpret_cast<void*>(target), |
| 394 kRequiredTargetPatchBytes, | 324 MAX_PREAMBLE_STUB_SIZE, |
| 395 old_target_function_protect, | 325 old_target_function_protect, |
| 396 &old_target_function_protect); | 326 &old_target_function_protect); |
| 397 | 327 |
| 398 // Flush the instruction cache to make sure the processor doesn't execute the | 328 // Flush the instruction cache to make sure the processor doesn't execute the |
| 399 // old version of the instructions (before our patch). | 329 // old version of the instructions (before our patch). |
| 400 // | 330 // |
| 401 // See comment on FlushInstructionCache elsewhere in this file. | 331 // See comment on FlushInstructionCache elsewhere in this file. |
| 402 succeeded = ::FlushInstructionCache(::GetCurrentProcess(), | 332 succeeded = ::FlushInstructionCache(::GetCurrentProcess(), |
| 403 target, | 333 target, |
| 404 MAX_PREAMBLE_STUB_SIZE); | 334 MAX_PREAMBLE_STUB_SIZE); |
| 405 if (!succeeded) { | 335 if (!succeeded) { |
| 406 SIDESTEP_ASSERT(false && "Failed to flush instruction cache."); | 336 SIDESTEP_ASSERT(false && "Failed to flush instruction cache."); |
| 407 return SIDESTEP_UNEXPECTED; | 337 return SIDESTEP_UNEXPECTED; |
| 408 } | 338 } |
| 409 | 339 |
| 410 SIDESTEP_LOG("PreamblePatcher::Unpatch successfully unpatched."); | 340 SIDESTEP_LOG("PreamblePatcher::Unpatch successfully unpatched."); |
| 411 return SIDESTEP_SUCCESS; | 341 return SIDESTEP_SUCCESS; |
| 412 } | 342 } |
| 413 | 343 |
| 414 void PreamblePatcher::Initialize() { | |
| 415 if (!initialized_) { | |
| 416 SYSTEM_INFO si = { 0 }; | |
| 417 ::GetSystemInfo(&si); | |
| 418 granularity_ = si.dwAllocationGranularity; | |
| 419 pagesize_ = si.dwPageSize; | |
| 420 initialized_ = true; | |
| 421 } | |
| 422 } | |
| 423 | |
| 424 unsigned char* PreamblePatcher::AllocPreambleBlockNear(void* target) { | |
| 425 PreamblePage* preamble_page = preamble_pages_; | |
| 426 while (preamble_page != NULL) { | |
| 427 if (preamble_page->free_ != NULL) { | |
| 428 __int64 val = reinterpret_cast<__int64>(preamble_page) - | |
| 429 reinterpret_cast<__int64>(target); | |
| 430 if ((val > 0 && val + pagesize_ <= INT_MAX) || | |
| 431 (val < 0 && val >= INT_MIN)) { | |
| 432 break; | |
| 433 } | |
| 434 } | |
| 435 preamble_page = preamble_page->next_; | |
| 436 } | |
| 437 | |
| 438 // The free_ member of the page is used to store the next available block | |
| 439 // of memory to use or NULL if there are no chunks available, in which case | |
| 440 // we'll allocate a new page. | |
| 441 if (preamble_page == NULL || preamble_page->free_ == NULL) { | |
| 442 // Create a new preamble page and initialize the free list | |
| 443 preamble_page = reinterpret_cast<PreamblePage*>(AllocPageNear(target)); | |
| 444 SIDESTEP_ASSERT(preamble_page != NULL && "Could not allocate page!"); | |
| 445 void** pp = &preamble_page->free_; | |
| 446 unsigned char* ptr = reinterpret_cast<unsigned char*>(preamble_page) + | |
| 447 MAX_PREAMBLE_STUB_SIZE; | |
| 448 unsigned char* limit = reinterpret_cast<unsigned char*>(preamble_page) + | |
| 449 pagesize_; | |
| 450 while (ptr < limit) { | |
| 451 *pp = ptr; | |
| 452 pp = reinterpret_cast<void**>(ptr); | |
| 453 ptr += MAX_PREAMBLE_STUB_SIZE; | |
| 454 } | |
| 455 *pp = NULL; | |
| 456 // Insert the new page into the list | |
| 457 preamble_page->magic_ = kPreamblePageMagic; | |
| 458 preamble_page->next_ = preamble_pages_; | |
| 459 preamble_pages_ = preamble_page; | |
| 460 } | |
| 461 unsigned char* ret = reinterpret_cast<unsigned char*>(preamble_page->free_); | |
| 462 preamble_page->free_ = *(reinterpret_cast<void**>(preamble_page->free_)); | |
| 463 return ret; | |
| 464 } | |
| 465 | |
| 466 void PreamblePatcher::FreePreambleBlock(unsigned char* block) { | |
| 467 SIDESTEP_ASSERT(block != NULL); | |
| 468 SIDESTEP_ASSERT(granularity_ != 0); | |
| 469 uintptr_t ptr = reinterpret_cast<uintptr_t>(block); | |
| 470 ptr -= ptr & (granularity_ - 1); | |
| 471 PreamblePage* preamble_page = reinterpret_cast<PreamblePage*>(ptr); | |
| 472 SIDESTEP_ASSERT(preamble_page->magic_ == kPreamblePageMagic); | |
| 473 *(reinterpret_cast<void**>(block)) = preamble_page->free_; | |
| 474 preamble_page->free_ = block; | |
| 475 } | |
| 476 | |
| 477 void* PreamblePatcher::AllocPageNear(void* target) { | |
| 478 MEMORY_BASIC_INFORMATION mbi = { 0 }; | |
| 479 if (!::VirtualQuery(target, &mbi, sizeof(mbi))) { | |
| 480 SIDESTEP_ASSERT(false && "VirtualQuery failed on target address"); | |
| 481 return 0; | |
| 482 } | |
| 483 if (initialized_ == false) { | |
| 484 PreamblePatcher::Initialize(); | |
| 485 SIDESTEP_ASSERT(initialized_); | |
| 486 } | |
| 487 void* pv = NULL; | |
| 488 unsigned char* allocation_base = reinterpret_cast<unsigned char*>( | |
| 489 mbi.AllocationBase); | |
| 490 __int64 i = 1; | |
| 491 bool high_target = reinterpret_cast<__int64>(target) > UINT_MAX; | |
| 492 while (pv == NULL) { | |
| 493 __int64 val = reinterpret_cast<__int64>(allocation_base) - | |
| 494 (i * granularity_); | |
| 495 if (high_target && | |
| 496 reinterpret_cast<__int64>(target) - val > INT_MAX) { | |
| 497 // We're further than 2GB from the target | |
| 498 break; | |
| 499 } else if (val <= NULL) { | |
| 500 // Less than 0 | |
| 501 break; | |
| 502 } | |
| 503 pv = ::VirtualAlloc(reinterpret_cast<void*>(allocation_base - | |
| 504 (i++ * granularity_)), | |
| 505 pagesize_, MEM_COMMIT | MEM_RESERVE, | |
| 506 PAGE_EXECUTE_READWRITE); | |
| 507 } | |
| 508 | |
| 509 // We couldn't allocate low, try to allocate high | |
| 510 if (pv == NULL) { | |
| 511 i = 1; | |
| 512 // Round up to the next multiple of page granularity | |
| 513 allocation_base = reinterpret_cast<unsigned char*>( | |
| 514 (reinterpret_cast<__int64>(target) & | |
| 515 (~(granularity_ - 1))) + granularity_); | |
| 516 while (pv == NULL) { | |
| 517 __int64 val = reinterpret_cast<__int64>(allocation_base) + | |
| 518 (i * granularity_) - reinterpret_cast<__int64>(target); | |
| 519 if (val > INT_MAX || val < 0) { | |
| 520 // We're too far or we overflowed | |
| 521 break; | |
| 522 } | |
| 523 pv = ::VirtualAlloc(reinterpret_cast<void*>(allocation_base + | |
| 524 (i++ * granularity_)), | |
| 525 pagesize_, MEM_COMMIT | MEM_RESERVE, | |
| 526 PAGE_EXECUTE_READWRITE); | |
| 527 } | |
| 528 } | |
| 529 return pv; | |
| 530 } | |
| 531 | |
| 532 bool PreamblePatcher::IsShortConditionalJump( | |
| 533 unsigned char* target, | |
| 534 unsigned int instruction_size) { | |
| 535 return (*(target) & 0x70) == 0x70 && instruction_size == 2; | |
| 536 } | |
| 537 | |
| 538 bool PreamblePatcher::IsNearConditionalJump( | |
| 539 unsigned char* target, | |
| 540 unsigned int instruction_size) { | |
| 541 return *(target) == 0xf && (*(target + 1) & 0x80) == 0x80 && | |
| 542 instruction_size == 6; | |
| 543 } | |
| 544 | |
| 545 bool PreamblePatcher::IsNearRelativeJump( | |
| 546 unsigned char* target, | |
| 547 unsigned int instruction_size) { | |
| 548 return *(target) == 0xe9 && instruction_size == 5; | |
| 549 } | |
| 550 | |
| 551 bool PreamblePatcher::IsNearAbsoluteCall( | |
| 552 unsigned char* target, | |
| 553 unsigned int instruction_size) { | |
| 554 return *(target) == 0xff && (*(target + 1) & 0x10) == 0x10 && | |
| 555 instruction_size == 6; | |
| 556 } | |
| 557 | |
| 558 bool PreamblePatcher::IsNearRelativeCall( | |
| 559 unsigned char* target, | |
| 560 unsigned int instruction_size) { | |
| 561 return *(target) == 0xe8 && instruction_size == 5; | |
| 562 } | |
| 563 | |
| 564 bool PreamblePatcher::IsMovWithDisplacement( | |
| 565 unsigned char* target, | |
| 566 unsigned int instruction_size) { | |
| 567 // In this case, the ModRM byte's mod field will be 0 and r/m will be 101b (5) | |
| 568 return instruction_size == 7 && *target == 0x48 && *(target + 1) == 0x8b && | |
| 569 (*(target + 2) >> 6) == 0 && (*(target + 2) & 0x7) == 5; | |
| 570 } | |
| 571 | |
| 572 SideStepError PreamblePatcher::PatchShortConditionalJump( | |
| 573 unsigned char* source, | |
| 574 unsigned int instruction_size, | |
| 575 unsigned char* target, | |
| 576 unsigned int* target_bytes, | |
| 577 unsigned int target_size) { | |
| 578 unsigned char* original_jump_dest = (source + 2) + source[1]; | |
| 579 unsigned char* stub_jump_from = target + 6; | |
| 580 __int64 fixup_jump_offset = original_jump_dest - stub_jump_from; | |
| 581 if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) { | |
| 582 SIDESTEP_ASSERT(false && | |
| 583 "Unable to fix up short jump because target" | |
| 584 " is too far away."); | |
| 585 return SIDESTEP_JUMP_INSTRUCTION; | |
| 586 } | |
| 587 | |
| 588 *target_bytes = 6; | |
| 589 if (target_size > *target_bytes) { | |
| 590 // Convert the short jump to a near jump. | |
| 591 // | |
| 592 // 0f 8x xx xx xx xx = Jcc rel32off | |
| 593 unsigned short jmpcode = ((0x80 | (source[0] & 0xf)) << 8) | 0x0f; | |
| 594 memcpy(reinterpret_cast<void*>(target), | |
| 595 reinterpret_cast<void*>(&jmpcode), 2); | |
| 596 memcpy(reinterpret_cast<void*>(target + 2), | |
| 597 reinterpret_cast<void*>(&fixup_jump_offset), 4); | |
| 598 } | |
| 599 | |
| 600 return SIDESTEP_SUCCESS; | |
| 601 } | |
| 602 | |
| 603 SideStepError PreamblePatcher::PatchNearJumpOrCall( | |
| 604 unsigned char* source, | |
| 605 unsigned int instruction_size, | |
| 606 unsigned char* target, | |
| 607 unsigned int* target_bytes, | |
| 608 unsigned int target_size) { | |
| 609 SIDESTEP_ASSERT(instruction_size == 5 || instruction_size == 6); | |
| 610 unsigned int jmp_offset_in_instruction = instruction_size == 5 ? 1 : 2; | |
| 611 unsigned char* original_jump_dest = reinterpret_cast<unsigned char *>( | |
| 612 reinterpret_cast<__int64>(source + instruction_size) + | |
| 613 *(reinterpret_cast<int*>(source + jmp_offset_in_instruction))); | |
| 614 unsigned char* stub_jump_from = target + instruction_size; | |
| 615 __int64 fixup_jump_offset = original_jump_dest - stub_jump_from; | |
| 616 if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) { | |
| 617 SIDESTEP_ASSERT(false && | |
| 618 "Unable to fix up near jump because target" | |
| 619 " is too far away."); | |
| 620 return SIDESTEP_JUMP_INSTRUCTION; | |
| 621 } | |
| 622 | |
| 623 if ((fixup_jump_offset < SCHAR_MAX && fixup_jump_offset > SCHAR_MIN)) { | |
| 624 *target_bytes = 2; | |
| 625 if (target_size > *target_bytes) { | |
| 626 // If the new offset is in range, use a short jump instead of a near jump. | |
| 627 if (source[0] == ASM_JCC32REL_0 && | |
| 628 (source[1] & ASM_JCC32REL_1_MASK) == ASM_JCC32REL_1_MASK) { | |
| 629 unsigned short jmpcode = (static_cast<unsigned char>( | |
| 630 fixup_jump_offset) << 8) | (0x70 | (source[1] & 0xf)); | |
| 631 memcpy(reinterpret_cast<void*>(target), | |
| 632 reinterpret_cast<void*>(&jmpcode), | |
| 633 2); | |
| 634 } else { | |
| 635 target[0] = ASM_JMP8REL; | |
| 636 target[1] = static_cast<unsigned char>(fixup_jump_offset); | |
| 637 } | |
| 638 } | |
| 639 } else { | |
| 640 *target_bytes = instruction_size; | |
| 641 if (target_size > *target_bytes) { | |
| 642 memcpy(reinterpret_cast<void*>(target), | |
| 643 reinterpret_cast<void*>(source), | |
| 644 jmp_offset_in_instruction); | |
| 645 memcpy(reinterpret_cast<void*>(target + jmp_offset_in_instruction), | |
| 646 reinterpret_cast<void*>(&fixup_jump_offset), | |
| 647 4); | |
| 648 } | |
| 649 } | |
| 650 | |
| 651 return SIDESTEP_SUCCESS; | |
| 652 } | |
| 653 | |
| 654 SideStepError PreamblePatcher::PatchMovWithDisplacement( | |
| 655 unsigned char* source, | |
| 656 unsigned int instruction_size, | |
| 657 unsigned char* target, | |
| 658 unsigned int* target_bytes, | |
| 659 unsigned int target_size) { | |
| 660 SIDESTEP_ASSERT(instruction_size == 7); | |
| 661 const int mov_offset_in_instruction = 3; // 0x48 0x8b 0x0d <offset> | |
| 662 unsigned char* original_mov_dest = reinterpret_cast<unsigned char*>( | |
| 663 reinterpret_cast<__int64>(source + instruction_size) + | |
| 664 *(reinterpret_cast<int*>(source + mov_offset_in_instruction))); | |
| 665 unsigned char* stub_mov_from = target + instruction_size; | |
| 666 __int64 fixup_mov_offset = original_mov_dest - stub_mov_from; | |
| 667 if (fixup_mov_offset > INT_MAX || fixup_mov_offset < INT_MIN) { | |
| 668 SIDESTEP_ASSERT(false && | |
| 669 "Unable to fix up near MOV because target is too far away."); | |
| 670 return SIDESTEP_UNEXPECTED; | |
| 671 } | |
| 672 *target_bytes = instruction_size; | |
| 673 if (target_size > *target_bytes) { | |
| 674 memcpy(reinterpret_cast<void*>(target), | |
| 675 reinterpret_cast<void*>(source), | |
| 676 mov_offset_in_instruction); | |
| 677 memcpy(reinterpret_cast<void*>(target + mov_offset_in_instruction), | |
| 678 reinterpret_cast<void*>(&fixup_mov_offset), | |
| 679 4); | |
| 680 } | |
| 681 return SIDESTEP_SUCCESS; | |
| 682 } | |
| 683 | |
| 684 }; // namespace sidestep | 344 }; // namespace sidestep |
| OLD | NEW |