| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 /* | |
| 6 * Implementation of PreamblePatcher | |
| 7 */ | |
| 8 | |
| 9 #include "preamble_patcher.h" | |
| 10 | |
| 11 #include "mini_disassembler.h" | |
| 12 | |
| 13 // Definitions of assembly statements we need | |
| 14 #define ASM_JMP32REL 0xE9 | |
| 15 #define ASM_INT3 0xCC | |
| 16 | |
| 17 namespace sidestep { | |
| 18 | |
| 19 SideStepError PreamblePatcher::RawPatchWithStub( | |
| 20 void* target_function, | |
| 21 void *replacement_function, | |
| 22 unsigned char* preamble_stub, | |
| 23 unsigned long stub_size, | |
| 24 unsigned long* bytes_needed) { | |
| 25 if ((NULL == target_function) || | |
| 26 (NULL == replacement_function) || | |
| 27 (NULL == preamble_stub)) { | |
| 28 ASSERT(false, "Invalid parameters - either pTargetFunction or " | |
| 29 "pReplacementFunction or pPreambleStub were NULL."); | |
| 30 return SIDESTEP_INVALID_PARAMETER; | |
| 31 } | |
| 32 | |
| 33 // TODO(V7:joi) Siggi and I just had a discussion and decided that both | |
| 34 // patching and unpatching are actually unsafe. We also discussed a | |
| 35 // method of making it safe, which is to freeze all other threads in the | |
| 36 // process, check their thread context to see if their eip is currently | |
| 37 // inside the block of instructions we need to copy to the stub, and if so | |
| 38 // wait a bit and try again, then unfreeze all threads once we've patched. | |
| 39 // Not implementing this for now since we're only using SideStep for unit | |
| 40 // testing, but if we ever use it for production code this is what we | |
| 41 // should do. | |
| 42 // | |
| 43 // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using | |
| 44 // FPU instructions, and on newer processors we could use cmpxchg8b or | |
| 45 // cmpxchg16b. So it might be possible to do the patching/unpatching | |
| 46 // atomically and avoid having to freeze other threads. Note though, that | |
| 47 // doing it atomically does not help if one of the other threads happens | |
| 48 // to have its eip in the middle of the bytes you change while you change | |
| 49 // them. | |
| 50 unsigned char* target = reinterpret_cast<unsigned char*>(target_function); | |
| 51 | |
| 52 // First, deal with a special case that we see with functions that | |
| 53 // point into an IAT table (including functions linked statically | |
| 54 // into the application): these function already starts with | |
| 55 // ASM_JMP32REL. For instance, malloc() might be implemented as a | |
| 56 // JMP to __malloc(). In that case, we replace the destination of | |
| 57 // the JMP (__malloc), rather than the JMP itself (malloc). This | |
| 58 // way we get the correct behavior no matter how malloc gets called. | |
| 59 if (target[0] == ASM_JMP32REL) { | |
| 60 // target[1-4] holds the place the jmp goes to, but it's | |
| 61 // relative to the next instruction. | |
| 62 int relative_offset; // Windows guarantees int is 4 bytes | |
| 63 ASSERT1(sizeof(relative_offset) == 4); | |
| 64 memcpy(reinterpret_cast<void*>(&relative_offset), | |
| 65 reinterpret_cast<void*>(target + 1), 4); | |
| 66 // I'd like to just say "target = target + 5 + relative_offset" here, but | |
| 67 // I can't, because the new target will need to have its protections set. | |
| 68 return RawPatchWithStubAndProtections(target + 5 + relative_offset, | |
| 69 replacement_function, preamble_stub, | |
| 70 stub_size, bytes_needed); | |
| 71 } | |
| 72 | |
| 73 // Let's disassemble the preamble of the target function to see if we can | |
| 74 // patch, and to see how much of the preamble we need to take. We need 5 | |
| 75 // bytes for our jmp instruction, so let's find the minimum number of | |
| 76 // instructions to get 5 bytes. | |
| 77 MiniDisassembler disassembler; | |
| 78 unsigned int preamble_bytes = 0; | |
| 79 while (preamble_bytes < 5) { | |
| 80 InstructionType instruction_type = | |
| 81 disassembler.Disassemble(target + preamble_bytes, preamble_bytes); | |
| 82 if (IT_JUMP == instruction_type) { | |
| 83 ASSERT(false, "Unable to patch because there is a jump instruction " | |
| 84 "in the first 5 bytes."); | |
| 85 return SIDESTEP_JUMP_INSTRUCTION; | |
| 86 } else if (IT_RETURN == instruction_type) { | |
| 87 ASSERT(false, "Unable to patch because function is too short"); | |
| 88 return SIDESTEP_FUNCTION_TOO_SMALL; | |
| 89 } else if (IT_GENERIC != instruction_type) { | |
| 90 ASSERT(false, "Disassembler encountered unsupported instruction " | |
| 91 "(either unused or unknown)"); | |
| 92 return SIDESTEP_UNSUPPORTED_INSTRUCTION; | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 if (NULL != bytes_needed) | |
| 97 *bytes_needed = preamble_bytes + 5; | |
| 98 | |
| 99 // Inv: cbPreamble is the number of bytes (at least 5) that we need to take | |
| 100 // from the preamble to have whole instructions that are 5 bytes or more | |
| 101 // in size total. The size of the stub required is cbPreamble + size of | |
| 102 // jmp (5) | |
| 103 if (preamble_bytes + 5 > stub_size) { | |
| 104 ASSERT1(false); | |
| 105 return SIDESTEP_INSUFFICIENT_BUFFER; | |
| 106 } | |
| 107 | |
| 108 // First, copy the preamble that we will overwrite. | |
| 109 memcpy(reinterpret_cast<void*>(preamble_stub), | |
| 110 reinterpret_cast<void*>(target), preamble_bytes); | |
| 111 | |
| 112 // Now, make a jmp instruction to the rest of the target function (minus the | |
| 113 // preamble bytes we moved into the stub) and copy it into our preamble-stub. | |
| 114 // find address to jump to, relative to next address after jmp instruction | |
| 115 #ifdef _MSC_VER | |
| 116 #pragma warning(push) | |
| 117 #pragma warning(disable:4244) | |
| 118 #endif | |
| 119 int relative_offset_to_target_rest | |
| 120 = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) - | |
| 121 (preamble_stub + preamble_bytes + 5)); | |
| 122 #ifdef _MSC_VER | |
| 123 #pragma warning(pop) | |
| 124 #endif | |
| 125 // jmp (Jump near, relative, displacement relative to next instruction) | |
| 126 preamble_stub[preamble_bytes] = ASM_JMP32REL; | |
| 127 // copy the address | |
| 128 memcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1), | |
| 129 reinterpret_cast<void*>(&relative_offset_to_target_rest), 4); | |
| 130 | |
| 131 // Inv: preamble_stub points to assembly code that will execute the | |
| 132 // original function by first executing the first cbPreamble bytes of the | |
| 133 // preamble, then jumping to the rest of the function. | |
| 134 | |
| 135 // Overwrite the first 5 bytes of the target function with a jump to our | |
| 136 // replacement function. | |
| 137 // (Jump near, relative, displacement relative to next instruction) | |
| 138 target[0] = ASM_JMP32REL; | |
| 139 | |
| 140 // Find offset from instruction after jmp, to the replacement function. | |
| 141 #ifdef _MSC_VER | |
| 142 #pragma warning(push) | |
| 143 #pragma warning(disable:4244) | |
| 144 #endif | |
| 145 int offset_to_replacement_function = | |
| 146 reinterpret_cast<unsigned char*>(replacement_function) - | |
| 147 reinterpret_cast<unsigned char*>(target) - 5; | |
| 148 #ifdef _MSC_VER | |
| 149 #pragma warning(pop) | |
| 150 #endif | |
| 151 // complete the jmp instruction | |
| 152 memcpy(reinterpret_cast<void*>(target + 1), | |
| 153 reinterpret_cast<void*>(&offset_to_replacement_function), 4); | |
| 154 // Set any remaining bytes that were moved to the preamble-stub to INT3 so | |
| 155 // as not to cause confusion (otherwise you might see some strange | |
| 156 // instructions if you look at the disassembly, or even invalid | |
| 157 // instructions). Also, by doing this, we will break into the debugger if | |
| 158 // some code calls into this portion of the code. If this happens, it | |
| 159 // means that this function cannot be patched using this patcher without | |
| 160 // further thought. | |
| 161 if (preamble_bytes > 5) { | |
| 162 memset(reinterpret_cast<void*>(target + 5), ASM_INT3, preamble_bytes - 5); | |
| 163 } | |
| 164 | |
| 165 // Inv: The memory pointed to by target_function now points to a relative | |
| 166 // jump instruction that jumps over to the preamble_stub. The preamble | |
| 167 // stub contains the first stub_size bytes of the original target | |
| 168 // function's preamble code, followed by a relative jump back to the next | |
| 169 // instruction after the first cbPreamble bytes. | |
| 170 | |
| 171 return SIDESTEP_SUCCESS; | |
| 172 } | |
| 173 | |
| 174 }; // namespace sidestep | |
| OLD | NEW |