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 |
32 * | 33 * |
33 * Implementation of PreamblePatcher | 34 * Implementation of PreamblePatcher |
34 */ | 35 */ |
35 | 36 |
36 #include "preamble_patcher.h" | 37 #include "preamble_patcher.h" |
37 | 38 |
38 #include "mini_disassembler.h" | 39 #include "mini_disassembler.h" |
39 | 40 |
40 // Definitions of assembly statements we need | 41 // Definitions of assembly statements we need |
41 #define ASM_JMP32REL 0xE9 | 42 #define ASM_JMP32REL 0xE9 |
42 #define ASM_INT3 0xCC | 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 |
43 | 52 |
44 namespace sidestep { | 53 namespace sidestep { |
45 | 54 |
46 SideStepError PreamblePatcher::RawPatchWithStub( | 55 SideStepError PreamblePatcher::RawPatchWithStub( |
47 void* target_function, | 56 void* target_function, |
48 void *replacement_function, | 57 void* replacement_function, |
49 unsigned char* preamble_stub, | 58 unsigned char* preamble_stub, |
50 unsigned long stub_size, | 59 unsigned long stub_size, |
51 unsigned long* bytes_needed) { | 60 unsigned long* bytes_needed) { |
52 if ((NULL == target_function) || | 61 if ((NULL == target_function) || |
53 (NULL == replacement_function) || | 62 (NULL == replacement_function) || |
54 (NULL == preamble_stub)) { | 63 (NULL == preamble_stub)) { |
55 SIDESTEP_ASSERT(false && | 64 SIDESTEP_ASSERT(false && |
56 "Invalid parameters - either pTargetFunction or " | 65 "Invalid parameters - either pTargetFunction or " |
57 "pReplacementFunction or pPreambleStub were NULL."); | 66 "pReplacementFunction or pPreambleStub were NULL."); |
58 return SIDESTEP_INVALID_PARAMETER; | 67 return SIDESTEP_INVALID_PARAMETER; |
59 } | 68 } |
60 | 69 |
61 // TODO(V7:joi) Siggi and I just had a discussion and decided that both | 70 // TODO(V7:joi) Siggi and I just had a discussion and decided that both |
62 // patching and unpatching are actually unsafe. We also discussed a | 71 // patching and unpatching are actually unsafe. We also discussed a |
63 // method of making it safe, which is to freeze all other threads in the | 72 // method of making it safe, which is to freeze all other threads in the |
64 // process, check their thread context to see if their eip is currently | 73 // process, check their thread context to see if their eip is currently |
65 // inside the block of instructions we need to copy to the stub, and if so | 74 // inside the block of instructions we need to copy to the stub, and if so |
66 // wait a bit and try again, then unfreeze all threads once we've patched. | 75 // wait a bit and try again, then unfreeze all threads once we've patched. |
67 // Not implementing this for now since we're only using SideStep for unit | 76 // Not implementing this for now since we're only using SideStep for unit |
68 // testing, but if we ever use it for production code this is what we | 77 // testing, but if we ever use it for production code this is what we |
69 // should do. | 78 // should do. |
70 // | 79 // |
71 // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using | 80 // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using |
72 // FPU instructions, and on newer processors we could use cmpxchg8b or | 81 // FPU instructions, and on newer processors we could use cmpxchg8b or |
73 // cmpxchg16b. So it might be possible to do the patching/unpatching | 82 // cmpxchg16b. So it might be possible to do the patching/unpatching |
74 // atomically and avoid having to freeze other threads. Note though, that | 83 // atomically and avoid having to freeze other threads. Note though, that |
75 // doing it atomically does not help if one of the other threads happens | 84 // doing it atomically does not help if one of the other threads happens |
76 // to have its eip in the middle of the bytes you change while you change | 85 // to have its eip in the middle of the bytes you change while you change |
77 // them. | 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; |
78 | 91 |
79 // First, deal with a special case that we see with functions that | 92 // Initialize the stub with INT3's just in case. |
80 // point into an IAT table (including functions linked statically | 93 if (stub_size) { |
81 // into the application): these function already starts with | 94 memset(preamble_stub, 0xcc, stub_size); |
82 // ASM_JMP32REL. For instance, malloc() might be implemented as a | |
83 // JMP to __malloc(). In that case, we replace the destination of | |
84 // the JMP (__malloc), rather than the JMP itself (malloc). This | |
85 // way we get the correct behavior no matter how malloc gets called. | |
86 void *new_target = ResolveTarget(target_function); | |
87 if (new_target != target_function) { // we're in the IAT case | |
88 // I'd like to just say "target = new_target", but I can't, | |
89 // because the new target will need to have its protections set. | |
90 return RawPatchWithStubAndProtections(new_target, replacement_function, | |
91 preamble_stub, stub_size, | |
92 bytes_needed); | |
93 } | 95 } |
94 unsigned char* target = reinterpret_cast<unsigned char*>(new_target); | 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 } |
95 | 133 |
96 // Let's disassemble the preamble of the target function to see if we can | 134 // Let's disassemble the preamble of the target function to see if we can |
97 // patch, and to see how much of the preamble we need to take. We need 5 | 135 // patch, and to see how much of the preamble we need to take. We need 5 |
98 // bytes for our jmp instruction, so let's find the minimum number of | 136 // bytes for our jmp instruction, so let's find the minimum number of |
99 // instructions to get 5 bytes. | 137 // instructions to get 5 bytes. |
100 MiniDisassembler disassembler; | 138 MiniDisassembler disassembler; |
101 unsigned int preamble_bytes = 0; | 139 unsigned int preamble_bytes = 0; |
102 while (preamble_bytes < 5) { | 140 unsigned int stub_bytes = 0; |
| 141 while (preamble_bytes < kRequiredTargetPatchBytes) { |
| 142 unsigned int cur_bytes = 0; |
103 InstructionType instruction_type = | 143 InstructionType instruction_type = |
104 disassembler.Disassemble(target + preamble_bytes, preamble_bytes); | 144 disassembler.Disassemble(target + preamble_bytes, cur_bytes); |
105 if (IT_JUMP == instruction_type) { | 145 if (IT_JUMP == instruction_type) { |
106 SIDESTEP_ASSERT(false && | 146 unsigned int jump_bytes = 0; |
107 "Unable to patch because there is a jump instruction " | 147 SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION; |
108 "in the first 5 bytes."); | 148 if (IsShortConditionalJump(target + preamble_bytes, cur_bytes)) { |
109 return SIDESTEP_JUMP_INSTRUCTION; | 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; |
110 } else if (IT_RETURN == instruction_type) { | 168 } else if (IT_RETURN == instruction_type) { |
111 SIDESTEP_ASSERT(false && | 169 SIDESTEP_ASSERT(false && |
112 "Unable to patch because function is too short"); | 170 "Unable to patch because function is too short"); |
113 return SIDESTEP_FUNCTION_TOO_SMALL; | 171 return SIDESTEP_FUNCTION_TOO_SMALL; |
114 } else if (IT_GENERIC != instruction_type) { | 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 { |
115 SIDESTEP_ASSERT(false && | 188 SIDESTEP_ASSERT(false && |
116 "Disassembler encountered unsupported instruction " | 189 "Disassembler encountered unsupported instruction " |
117 "(either unused or unknown"); | 190 "(either unused or unknown"); |
118 return SIDESTEP_UNSUPPORTED_INSTRUCTION; | 191 return SIDESTEP_UNSUPPORTED_INSTRUCTION; |
119 } | 192 } |
| 193 preamble_bytes += cur_bytes; |
120 } | 194 } |
121 | 195 |
122 if (NULL != bytes_needed) | 196 if (NULL != bytes_needed) |
123 *bytes_needed = preamble_bytes + 5; | 197 *bytes_needed = stub_bytes + kRequiredStubJumpBytes |
| 198 + required_trampoline_bytes; |
124 | 199 |
125 // Inv: cbPreamble is the number of bytes (at least 5) that we need to take | 200 // Inv: cbPreamble is the number of bytes (at least 5) that we need to take |
126 // from the preamble to have whole instructions that are 5 bytes or more | 201 // from the preamble to have whole instructions that are 5 bytes or more |
127 // in size total. The size of the stub required is cbPreamble + size of | 202 // in size total. The size of the stub required is cbPreamble + |
128 // jmp (5) | 203 // kRequiredStubJumpBytes (5) + required_trampoline_bytes (0 or 13) |
129 if (preamble_bytes + 5 > stub_size) { | 204 if (stub_bytes + kRequiredStubJumpBytes + required_trampoline_bytes |
| 205 > stub_size) { |
130 SIDESTEP_ASSERT(false); | 206 SIDESTEP_ASSERT(false); |
131 return SIDESTEP_INSUFFICIENT_BUFFER; | 207 return SIDESTEP_INSUFFICIENT_BUFFER; |
132 } | 208 } |
133 | 209 |
134 // First, copy the preamble that we will overwrite. | |
135 memcpy(reinterpret_cast<void*>(preamble_stub), | |
136 reinterpret_cast<void*>(target), preamble_bytes); | |
137 | |
138 // Now, make a jmp instruction to the rest of the target function (minus the | 210 // Now, make a jmp instruction to the rest of the target function (minus the |
139 // preamble bytes we moved into the stub) and copy it into our preamble-stub. | 211 // preamble bytes we moved into the stub) and copy it into our preamble-stub. |
140 // find address to jump to, relative to next address after jmp instruction | 212 // find address to jump to, relative to next address after jmp instruction |
141 #ifdef _MSC_VER | 213 #ifdef _MSC_VER |
142 #pragma warning(push) | 214 #pragma warning(push) |
143 #pragma warning(disable:4244) | 215 #pragma warning(disable:4244) |
144 #endif | 216 #endif |
145 int relative_offset_to_target_rest | 217 int relative_offset_to_target_rest |
146 = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) - | 218 = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) - |
147 (preamble_stub + preamble_bytes + 5)); | 219 (preamble_stub + stub_bytes + kRequiredStubJumpBytes)); |
148 #ifdef _MSC_VER | 220 #ifdef _MSC_VER |
149 #pragma warning(pop) | 221 #pragma warning(pop) |
150 #endif | 222 #endif |
151 // jmp (Jump near, relative, displacement relative to next instruction) | 223 // jmp (Jump near, relative, displacement relative to next instruction) |
152 preamble_stub[preamble_bytes] = ASM_JMP32REL; | 224 preamble_stub[stub_bytes] = ASM_JMP32REL; |
153 // copy the address | 225 // copy the address |
154 memcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1), | 226 memcpy(reinterpret_cast<void*>(preamble_stub + stub_bytes + 1), |
155 reinterpret_cast<void*>(&relative_offset_to_target_rest), 4); | 227 reinterpret_cast<void*>(&relative_offset_to_target_rest), 4); |
156 | 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 |
157 // Inv: preamble_stub points to assembly code that will execute the | 245 // Inv: preamble_stub points to assembly code that will execute the |
158 // original function by first executing the first cbPreamble bytes of the | 246 // original function by first executing the first cbPreamble bytes of the |
159 // preamble, then jumping to the rest of the function. | 247 // preamble, then jumping to the rest of the function. |
160 | 248 |
161 // Overwrite the first 5 bytes of the target function with a jump to our | 249 // Overwrite the first 5 bytes of the target function with a jump to our |
162 // replacement function. | 250 // replacement function. |
163 // (Jump near, relative, displacement relative to next instruction) | 251 // (Jump near, relative, displacement relative to next instruction) |
164 target[0] = ASM_JMP32REL; | 252 target[0] = ASM_JMP32REL; |
165 | 253 |
166 // Find offset from instruction after jmp, to the replacement function. | 254 // Find offset from instruction after jmp, to the replacement function. |
167 #ifdef _MSC_VER | 255 #ifdef _MSC_VER |
168 #pragma warning(push) | 256 #pragma warning(push) |
169 #pragma warning(disable:4244) | 257 #pragma warning(disable:4244) |
170 #endif | 258 #endif |
171 int offset_to_replacement_function = | 259 int offset_to_replacement_function = |
172 reinterpret_cast<unsigned char*>(replacement_function) - | 260 reinterpret_cast<unsigned char*>(replacement_function) - |
173 reinterpret_cast<unsigned char*>(target) - 5; | 261 reinterpret_cast<unsigned char*>(target) - 5; |
174 #ifdef _MSC_VER | 262 #ifdef _MSC_VER |
175 #pragma warning(pop) | 263 #pragma warning(pop) |
176 #endif | 264 #endif |
177 // complete the jmp instruction | 265 // complete the jmp instruction |
178 memcpy(reinterpret_cast<void*>(target + 1), | 266 memcpy(reinterpret_cast<void*>(target + 1), |
179 reinterpret_cast<void*>(&offset_to_replacement_function), 4); | 267 reinterpret_cast<void*>(&offset_to_replacement_function), 4); |
| 268 |
180 // Set any remaining bytes that were moved to the preamble-stub to INT3 so | 269 // Set any remaining bytes that were moved to the preamble-stub to INT3 so |
181 // as not to cause confusion (otherwise you might see some strange | 270 // as not to cause confusion (otherwise you might see some strange |
182 // instructions if you look at the disassembly, or even invalid | 271 // instructions if you look at the disassembly, or even invalid |
183 // instructions). Also, by doing this, we will break into the debugger if | 272 // instructions). Also, by doing this, we will break into the debugger if |
184 // some code calls into this portion of the code. If this happens, it | 273 // some code calls into this portion of the code. If this happens, it |
185 // means that this function cannot be patched using this patcher without | 274 // means that this function cannot be patched using this patcher without |
186 // further thought. | 275 // further thought. |
187 if (preamble_bytes > 5) { | 276 if (preamble_bytes > kRequiredTargetPatchBytes) { |
188 memset(reinterpret_cast<void*>(target + 5), ASM_INT3, preamble_bytes - 5); | 277 memset(reinterpret_cast<void*>(target + kRequiredTargetPatchBytes), |
| 278 ASM_INT3, preamble_bytes - kRequiredTargetPatchBytes); |
189 } | 279 } |
190 | 280 |
191 // Inv: The memory pointed to by target_function now points to a relative | 281 // Inv: The memory pointed to by target_function now points to a relative |
192 // jump instruction that jumps over to the preamble_stub. The preamble | 282 // jump instruction that jumps over to the preamble_stub. The preamble |
193 // stub contains the first stub_size bytes of the original target | 283 // stub contains the first stub_size bytes of the original target |
194 // function's preamble code, followed by a relative jump back to the next | 284 // function's preamble code, followed by a relative jump back to the next |
195 // instruction after the first cbPreamble bytes. | 285 // instruction after the first cbPreamble bytes. |
196 | 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 // |
197 return SIDESTEP_SUCCESS; | 293 return SIDESTEP_SUCCESS; |
198 } | 294 } |
199 | 295 |
200 }; // namespace sidestep | 296 }; // namespace sidestep |
OLD | NEW |