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