15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Copyright (c) 2007, Google Inc.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modification, are permitted provided that the following conditions are
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * met:
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in the documentation and/or other materials provided with the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distribution.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * contributors may be used to endorse or promote products derived from
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this software without specific prior written permission.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ---
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Author: Joi Sigurdsson
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Author: Scott Francis
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Implementation of PreamblePatcher
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "preamble_patcher.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "mini_disassembler.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// compatibility shims
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Definitions of assembly statements we need
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP32REL 0xE9
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_INT3 0xCC
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP32ABS_0 0xFF
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP32ABS_1 0x25
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP8REL 0xEB
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JCC32REL_0 0x0F
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JCC32REL_1_MASK 0x80
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_NOP 0x90
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// X64 opcodes
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_REXW 0x48
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_MOVRAX_IMM 0xB8
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP 0xFF
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASM_JMP_RAX 0xE0
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sidestep {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PreamblePatcher::PreamblePage* PreamblePatcher::preamble_pages_ = NULL;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)long PreamblePatcher::granularity_ = 0;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)long PreamblePatcher::pagesize_ = 0;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::initialized_ = false;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const unsigned int kPreamblePageMagic = 0x4347414D; // "MAGC"
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handle a special case that we see with functions that point into an
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IAT table (including functions linked statically into the
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// application): these function already starts with ASM_JMP32*.  For
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// instance, malloc() might be implemented as a JMP to __malloc().
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function follows the initial JMPs for us, until we get to the
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// place where the actual code is defined.  If we get to STOP_BEFORE,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we return the address before stop_before.  The stop_before_trampoline
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// flag is used in 64-bit mode.  If true, we will return the address
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before a trampoline is detected.  Trampolines are defined as:
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    nop
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    mov rax, <replacement_function>
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    jmp rax
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See PreamblePatcher::RawPatchWithStub for more information.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* PreamblePatcher::ResolveTargetImpl(unsigned char* target,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         unsigned char* stop_before,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         bool stop_before_trampoline) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target == NULL)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (1) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* new_target;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (target[0] == ASM_JMP32REL) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // target[1-4] holds the place the jmp goes to, but it's
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // relative to the next instruction.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int relative_offset;   // Windows guarantees int is 4 bytes
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SIDESTEP_ASSERT(sizeof(relative_offset) == 4);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memcpy(reinterpret_cast<void*>(&relative_offset),
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             reinterpret_cast<void*>(target + 1), 4);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_target = target + 5 + relative_offset;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (target[0] == ASM_JMP8REL) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Visual Studio 7.1 implements new[] as an 8 bit jump to new
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signed char relative_offset;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memcpy(reinterpret_cast<void*>(&relative_offset),
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             reinterpret_cast<void*>(target + 1), 1);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_target = target + 2 + relative_offset;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (target[0] == ASM_JMP32ABS_0 &&
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               target[1] == ASM_JMP32ABS_1) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Visual studio seems to sometimes do it this way instead of the
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // previous way.  Not sure what the rules are, but it was happening
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // with operator new in some binaries.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      void** new_target_v;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (kIs64BitBinary) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // In 64-bit mode JMPs are RIP-relative, not absolute
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int target_offset;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(reinterpret_cast<void*>(&target_offset),
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               reinterpret_cast<void*>(target + 2), 4);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_target_v = reinterpret_cast<void**>(target + target_offset + 6);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SIDESTEP_ASSERT(sizeof(new_target) == 4);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(&new_target_v, reinterpret_cast<void*>(target + 2), 4);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_target = reinterpret_cast<unsigned char*>(*new_target_v);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (new_target == stop_before)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (stop_before_trampoline && *new_target == ASM_NOP
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        && new_target[1] == ASM_REXW && new_target[2] == ASM_MOVRAX_IMM)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target = new_target;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return target;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Special case scoped_ptr to avoid dependency on scoped_ptr below.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DeleteUnsignedCharArray {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteUnsignedCharArray(unsigned char* array) : array_(array) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~DeleteUnsignedCharArray() {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (array_) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PreamblePatcher::FreePreambleBlock(array_);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* Release() {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* temp = array_;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    array_ = NULL;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return temp;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* array_;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::RawPatchWithStubAndProtections(
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* target_function, void *replacement_function,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* preamble_stub, unsigned long stub_size,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned long* bytes_needed) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to be able to write to a process-local copy of the first
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MAX_PREAMBLE_STUB_SIZE bytes of target_function
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD old_target_function_protect = 0;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function),
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    MAX_PREAMBLE_STUB_SIZE,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    PAGE_EXECUTE_READWRITE,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &old_target_function_protect);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!succeeded) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false && "Failed to make page containing target function "
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "copy-on-write.");
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_ACCESS_DENIED;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SideStepError error_code = RawPatchWithStub(target_function,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              replacement_function,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              preamble_stub,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              stub_size,
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              bytes_needed);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pTargetFunction to what they were before we started goofing around.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We do this regardless of whether the patch succeeded or not.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function),
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               MAX_PREAMBLE_STUB_SIZE,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               old_target_function_protect,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &old_target_function_protect);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!succeeded) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false &&
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Failed to restore protection to target function.");
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We must not return an error here because the function has
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // likely actually been patched, and returning an error might
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // cause our client code not to unpatch it.  So we just keep
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // going.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SIDESTEP_SUCCESS != error_code) {  // Testing RawPatchWithStub, above
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return error_code;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Flush the instruction cache to make sure the processor doesn't execute the
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // old version of the instructions (before our patch).
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FlushInstructionCache is actually a no-op at least on
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // single-processor XP machines.  I'm not sure why this is so, but
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it is, yet I want to keep the call to the API here for
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // correctness in case there is a difference in some variants of
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Windows/hardware.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      target_function,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      MAX_PREAMBLE_STUB_SIZE);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!succeeded) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false && "Failed to flush instruction cache.");
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We must not return an error here because the function has actually
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // been patched, and returning an error would likely cause our client
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // code not to unpatch it.  So we just keep going.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SIDESTEP_SUCCESS;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::RawPatch(void* target_function,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        void* replacement_function,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        void** original_function_stub) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!target_function || !replacement_function || !original_function_stub ||
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*original_function_stub) || target_function == replacement_function) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false && "Preconditions not met");
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_INVALID_PARAMETER;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL succeeded = FALSE;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First, deal with a special case that we see with functions that
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // point into an IAT table (including functions linked statically
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // into the application): these function already starts with
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ASM_JMP32REL.  For instance, malloc() might be implemented as a
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // JMP to __malloc().  In that case, we replace the destination of
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the JMP (__malloc), rather than the JMP itself (malloc).  This
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // way we get the correct behavior no matter how malloc gets called.
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* new_target = ResolveTarget(target_function);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_target != target_function) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target_function = new_target;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In 64-bit mode, preamble_stub must be within 2GB of target function
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so that if target contains a jump, we can translate it.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* preamble_stub = AllocPreambleBlockNear(target_function);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!preamble_stub) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false && "Unable to allocate preamble-stub.");
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_INSUFFICIENT_BUFFER;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Frees the array at end of scope.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteUnsignedCharArray guard_preamble_stub(preamble_stub);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SideStepError error_code = RawPatchWithStubAndProtections(
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      target_function, replacement_function, preamble_stub,
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MAX_PREAMBLE_STUB_SIZE, NULL);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SIDESTEP_SUCCESS != error_code) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return error_code;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Flush the instruction cache to make sure the processor doesn't execute the
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // old version of the instructions (before our patch).
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FlushInstructionCache is actually a no-op at least on
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // single-processor XP machines.  I'm not sure why this is so, but
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it is, yet I want to keep the call to the API here for
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // correctness in case there is a difference in some variants of
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Windows/hardware.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      target_function,
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      MAX_PREAMBLE_STUB_SIZE);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!succeeded) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false && "Failed to flush instruction cache.");
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We must not return an error here because the function has actually
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // been patched, and returning an error would likely cause our client
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // code not to unpatch it.  So we just keep going.
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SIDESTEP_LOG("PreamblePatcher::RawPatch successfully patched.");
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // detach the scoped pointer so the memory is not freed
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *original_function_stub =
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<void*>(guard_preamble_stub.Release());
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SIDESTEP_SUCCESS;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::Unpatch(void* target_function,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       void* replacement_function,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       void* original_function_stub) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SIDESTEP_ASSERT(target_function && replacement_function &&
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  original_function_stub);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!target_function || !replacement_function ||
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !original_function_stub) {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_INVALID_PARAMETER;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Before unpatching, target_function should be a JMP to
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // replacement_function.  If it's not, then either it's an error, or
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we're falling into the case where the original instruction was a
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // JMP, and we patched the jumped_to address rather than the JMP
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // itself.  (For instance, if malloc() is just a JMP to __malloc(),
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we patched __malloc() and not malloc().)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* target = reinterpret_cast<unsigned char*>(target_function);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  target = reinterpret_cast<unsigned char*>(
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResolveTargetImpl(
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          target, reinterpret_cast<unsigned char*>(replacement_function),
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          true));
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should end at the function we patched.  When we patch, we insert
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a ASM_JMP32REL instruction, so look for that as a sanity check.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target[0] != ASM_JMP32REL) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false &&
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "target_function does not look like it was patched.");
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_INVALID_PARAMETER;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned int kRequiredTargetPatchBytes = 5;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to be able to write to a process-local copy of the first
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // kRequiredTargetPatchBytes bytes of target_function
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD old_target_function_protect = 0;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target),
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    kRequiredTargetPatchBytes,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    PAGE_EXECUTE_READWRITE,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &old_target_function_protect);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!succeeded) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false && "Failed to make page containing target function "
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "copy-on-write.");
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_ACCESS_DENIED;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* preamble_stub = reinterpret_cast<unsigned char*>(
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   original_function_stub);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disassemble the preamble of stub and copy the bytes back to target.
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we've done any conditional jumps in the preamble we need to convert
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them back to the orignal REL8 jumps in the target.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MiniDisassembler disassembler;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int preamble_bytes = 0;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int target_bytes = 0;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (target_bytes < kRequiredTargetPatchBytes) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int cur_bytes = 0;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InstructionType instruction_type =
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        disassembler.Disassemble(preamble_stub + preamble_bytes, cur_bytes);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IT_JUMP == instruction_type) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unsigned int jump_bytes = 0;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (IsNearConditionalJump(preamble_stub + preamble_bytes, cur_bytes) ||
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IsNearRelativeJump(preamble_stub + preamble_bytes, cur_bytes) ||
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IsNearAbsoluteCall(preamble_stub + preamble_bytes, cur_bytes) ||
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IsNearRelativeCall(preamble_stub + preamble_bytes, cur_bytes)) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        jump_ret = PatchNearJumpOrCall(preamble_stub + preamble_bytes,
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       cur_bytes, target + target_bytes,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       &jump_bytes, MAX_PREAMBLE_STUB_SIZE);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (jump_ret == SIDESTEP_JUMP_INSTRUCTION) {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SIDESTEP_ASSERT(false &&
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Found unsupported jump instruction in stub!!");
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return SIDESTEP_UNSUPPORTED_INSTRUCTION;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      target_bytes += jump_bytes;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (IT_GENERIC == instruction_type) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (IsMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes)) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned int mov_bytes = 0;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (PatchMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes,
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     target + target_bytes, &mov_bytes,
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     MAX_PREAMBLE_STUB_SIZE)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     != SIDESTEP_SUCCESS) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SIDESTEP_ASSERT(false &&
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "Found unsupported generic instruction in stub!!");
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return SIDESTEP_UNSUPPORTED_INSTRUCTION;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(reinterpret_cast<void*>(target + target_bytes),
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               reinterpret_cast<void*>(reinterpret_cast<unsigned char*>(
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   original_function_stub) + preamble_bytes), cur_bytes);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        target_bytes += cur_bytes;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SIDESTEP_ASSERT(false &&
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Found unsupported instruction in stub!!");
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SIDESTEP_UNSUPPORTED_INSTRUCTION;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preamble_bytes += cur_bytes;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FreePreambleBlock(reinterpret_cast<unsigned char*>(original_function_stub));
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Restore the protection of the first kRequiredTargetPatchBytes bytes of
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // target to what they were before we started goofing around.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  succeeded = ::VirtualProtect(reinterpret_cast<void*>(target),
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               kRequiredTargetPatchBytes,
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               old_target_function_protect,
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &old_target_function_protect);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Flush the instruction cache to make sure the processor doesn't execute the
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // old version of the instructions (before our patch).
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See comment on FlushInstructionCache elsewhere in this file.
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      target,
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      MAX_PREAMBLE_STUB_SIZE);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!succeeded) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false && "Failed to flush instruction cache.");
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_UNEXPECTED;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SIDESTEP_LOG("PreamblePatcher::Unpatch successfully unpatched.");
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SIDESTEP_SUCCESS;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PreamblePatcher::Initialize() {
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized_) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SYSTEM_INFO si = { 0 };
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::GetSystemInfo(&si);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    granularity_ = si.dwAllocationGranularity;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pagesize_ = si.dwPageSize;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialized_ = true;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unsigned char* PreamblePatcher::AllocPreambleBlockNear(void* target) {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PreamblePage* preamble_page = preamble_pages_;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (preamble_page != NULL) {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (preamble_page->free_ != NULL) {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      __int64 val = reinterpret_cast<__int64>(preamble_page) -
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reinterpret_cast<__int64>(target);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ((val > 0 && val + pagesize_ <= INT_MAX) ||
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (val < 0 && val >= INT_MIN)) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preamble_page = preamble_page->next_;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The free_ member of the page is used to store the next available block
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of memory to use or NULL if there are no chunks available, in which case
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we'll allocate a new page.
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (preamble_page == NULL || preamble_page->free_ == NULL) {
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Create a new preamble page and initialize the free list
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preamble_page = reinterpret_cast<PreamblePage*>(AllocPageNear(target));
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(preamble_page != NULL && "Could not allocate page!");
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void** pp = &preamble_page->free_;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* ptr = reinterpret_cast<unsigned char*>(preamble_page) +
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        MAX_PREAMBLE_STUB_SIZE;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* limit = reinterpret_cast<unsigned char*>(preamble_page) +
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pagesize_;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (ptr < limit) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *pp = ptr;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pp = reinterpret_cast<void**>(ptr);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ptr += MAX_PREAMBLE_STUB_SIZE;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *pp = NULL;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Insert the new page into the list
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preamble_page->magic_ = kPreamblePageMagic;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preamble_page->next_ = preamble_pages_;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preamble_pages_ = preamble_page;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* ret = reinterpret_cast<unsigned char*>(preamble_page->free_);
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preamble_page->free_ = *(reinterpret_cast<void**>(preamble_page->free_));
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PreamblePatcher::FreePreambleBlock(unsigned char* block) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SIDESTEP_ASSERT(block != NULL);
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SIDESTEP_ASSERT(granularity_ != 0);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uintptr_t ptr = reinterpret_cast<uintptr_t>(block);
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ptr -= ptr & (granularity_ - 1);
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PreamblePage* preamble_page = reinterpret_cast<PreamblePage*>(ptr);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SIDESTEP_ASSERT(preamble_page->magic_ == kPreamblePageMagic);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *(reinterpret_cast<void**>(block)) = preamble_page->free_;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preamble_page->free_ = block;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* PreamblePatcher::AllocPageNear(void* target) {
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MEMORY_BASIC_INFORMATION mbi = { 0 };
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!::VirtualQuery(target, &mbi, sizeof(mbi))) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false && "VirtualQuery failed on target address");
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initialized_ == false) {
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PreamblePatcher::Initialize();
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(initialized_);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* pv = NULL;
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* allocation_base = reinterpret_cast<unsigned char*>(
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mbi.AllocationBase);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __int64 i = 1;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool high_target = reinterpret_cast<__int64>(target) > UINT_MAX;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (pv == NULL) {
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __int64 val = reinterpret_cast<__int64>(allocation_base) -
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (i * granularity_);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (high_target &&
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<__int64>(target) - val > INT_MAX) {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We're further than 2GB from the target
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (val <= NULL) {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Less than 0
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pv = ::VirtualAlloc(reinterpret_cast<void*>(allocation_base -
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            (i++ * granularity_)),
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        pagesize_, MEM_COMMIT | MEM_RESERVE,
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        PAGE_EXECUTE_READWRITE);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We couldn't allocate low, try to allocate high
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pv == NULL) {
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i = 1;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Round up to the next multiple of page granularity
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    allocation_base = reinterpret_cast<unsigned char*>(
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (reinterpret_cast<__int64>(target) &
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (~(granularity_ - 1))) + granularity_);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (pv == NULL) {
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      __int64 val = reinterpret_cast<__int64>(allocation_base) +
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (i * granularity_) - reinterpret_cast<__int64>(target);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (val > INT_MAX || val < 0) {
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We're too far or we overflowed
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pv = ::VirtualAlloc(reinterpret_cast<void*>(allocation_base +
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              (i++ * granularity_)),
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          pagesize_, MEM_COMMIT | MEM_RESERVE,
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          PAGE_EXECUTE_READWRITE);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pv;
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsShortConditionalJump(
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* target,
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int instruction_size) {
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (*(target) & 0x70) == 0x70 && instruction_size == 2;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsNearConditionalJump(
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* target,
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int instruction_size) {
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *(target) == 0xf && (*(target + 1) & 0x80) == 0x80 &&
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      instruction_size == 6;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsNearRelativeJump(
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* target,
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int instruction_size) {
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *(target) == 0xe9 && instruction_size == 5;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsNearAbsoluteCall(
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* target,
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int instruction_size) {
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *(target) == 0xff && (*(target + 1) & 0x10) == 0x10 &&
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      instruction_size == 6;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsNearRelativeCall(
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* target,
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int instruction_size) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *(target) == 0xe8 && instruction_size == 5;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PreamblePatcher::IsMovWithDisplacement(
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* target,
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int instruction_size) {
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In this case, the ModRM byte's mod field will be 0 and r/m will be 101b (5)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return instruction_size == 7 && *target == 0x48 && *(target + 1) == 0x8b &&
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*(target + 2) >> 6) == 0 && (*(target + 2) & 0x7) == 5;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::PatchShortConditionalJump(
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* source,
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int instruction_size,
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* target,
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int* target_bytes,
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int target_size) {
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* original_jump_dest = (source + 2) + source[1];
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* stub_jump_from = target + 6;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __int64 fixup_jump_offset = original_jump_dest - stub_jump_from;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) {
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false &&
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Unable to fix up short jump because target"
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    " is too far away.");
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_JUMP_INSTRUCTION;
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *target_bytes = 6;
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_size > *target_bytes) {
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Convert the short jump to a near jump.
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // 0f 8x xx xx xx xx = Jcc rel32off
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned short jmpcode = ((0x80 | (source[0] & 0xf)) << 8) | 0x0f;
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(reinterpret_cast<void*>(target),
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           reinterpret_cast<void*>(&jmpcode), 2);
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(reinterpret_cast<void*>(target + 2),
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           reinterpret_cast<void*>(&fixup_jump_offset), 4);
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SIDESTEP_SUCCESS;
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::PatchNearJumpOrCall(
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* source,
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int instruction_size,
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* target,
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int* target_bytes,
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int target_size) {
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SIDESTEP_ASSERT(instruction_size == 5 || instruction_size == 6);
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int jmp_offset_in_instruction = instruction_size == 5 ? 1 : 2;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* original_jump_dest = reinterpret_cast<unsigned char *>(
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<__int64>(source + instruction_size) +
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *(reinterpret_cast<int*>(source + jmp_offset_in_instruction)));
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* stub_jump_from = target + instruction_size;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __int64 fixup_jump_offset = original_jump_dest - stub_jump_from;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false &&
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Unable to fix up near jump because target"
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    " is too far away.");
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_JUMP_INSTRUCTION;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((fixup_jump_offset < SCHAR_MAX && fixup_jump_offset > SCHAR_MIN)) {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *target_bytes = 2;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (target_size > *target_bytes) {
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the new offset is in range, use a short jump instead of a near jump.
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (source[0] == ASM_JCC32REL_0 &&
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (source[1] & ASM_JCC32REL_1_MASK) == ASM_JCC32REL_1_MASK) {
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned short jmpcode = (static_cast<unsigned char>(
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fixup_jump_offset) << 8) | (0x70 | (source[1] & 0xf));
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(reinterpret_cast<void*>(target),
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               reinterpret_cast<void*>(&jmpcode),
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               2);
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        target[0] = ASM_JMP8REL;
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        target[1] = static_cast<unsigned char>(fixup_jump_offset);
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *target_bytes = instruction_size;
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (target_size > *target_bytes) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memcpy(reinterpret_cast<void*>(target),
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             reinterpret_cast<void*>(source),
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             jmp_offset_in_instruction);
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memcpy(reinterpret_cast<void*>(target + jmp_offset_in_instruction),
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             reinterpret_cast<void*>(&fixup_jump_offset),
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             4);
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SIDESTEP_SUCCESS;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SideStepError PreamblePatcher::PatchMovWithDisplacement(
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     unsigned char* source,
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     unsigned int instruction_size,
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     unsigned char* target,
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     unsigned int* target_bytes,
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     unsigned int target_size) {
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SIDESTEP_ASSERT(instruction_size == 7);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int mov_offset_in_instruction = 3; // 0x48 0x8b 0x0d <offset>
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* original_mov_dest = reinterpret_cast<unsigned char*>(
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<__int64>(source + instruction_size) +
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *(reinterpret_cast<int*>(source + mov_offset_in_instruction)));
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* stub_mov_from = target + instruction_size;
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __int64 fixup_mov_offset = original_mov_dest - stub_mov_from;
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fixup_mov_offset > INT_MAX || fixup_mov_offset < INT_MIN) {
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIDESTEP_ASSERT(false &&
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Unable to fix up near MOV because target is too far away.");
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SIDESTEP_UNEXPECTED;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *target_bytes = instruction_size;
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_size > *target_bytes) {
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(reinterpret_cast<void*>(target),
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           reinterpret_cast<void*>(source),
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           mov_offset_in_instruction);
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(reinterpret_cast<void*>(target + mov_offset_in_instruction),
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           reinterpret_cast<void*>(&fixup_mov_offset),
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           4);
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SIDESTEP_SUCCESS;
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};  // namespace sidestep
685