preamble_patcher_with_stub.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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