1
/* Copyright (c) 2007, Google Inc.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are
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
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.
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.
31
* Author: Joi Sigurdsson
33
* Implementation of PreamblePatcher
36
#include "preamble_patcher.h"
38
#include "mini_disassembler.h"
40
// compatibility shims
41
#include "base/logging.h"
43
// Definitions of assembly statements we need
44
#define ASM_JMP32REL 0xE9
49
SideStepError PreamblePatcher::RawPatchWithStubAndProtections(
50
void* target_function, void *replacement_function,
51
unsigned char* preamble_stub, unsigned long stub_size,
52
unsigned long* bytes_needed) {
53
// We need to be able to write to a process-local copy of the first
54
// MAX_PREAMBLE_STUB_SIZE bytes of target_function
55
DWORD old_target_function_protect = 0;
56
BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function),
57
MAX_PREAMBLE_STUB_SIZE, PAGE_READWRITE,
58
&old_target_function_protect);
60
ASSERT(false, "Failed to make page containing target function "
62
return SIDESTEP_ACCESS_DENIED;
65
SideStepError error_code = RawPatchWithStub(target_function,
70
if (SIDESTEP_SUCCESS != error_code) {
75
// Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of
76
// pTargetFunction to what they were before we started goofing around.
77
succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function),
78
MAX_PREAMBLE_STUB_SIZE,
79
old_target_function_protect,
80
&old_target_function_protect);
82
ASSERT(false, "Failed to restore protection to target function.");
83
// We must not return an error here because the function has actually
84
// been patched, and returning an error would likely cause our client
85
// code not to unpatch it. So we just keep going.
88
// Flush the instruction cache to make sure the processor doesn't execute the
89
// old version of the instructions (before our patch).
91
// FlushInstructionCache is actually a no-op at least on single-processor
92
// XP machines. I'm not sure why this is so, but it is, yet I want to keep the
93
// call to the API here for correctness in case there is a difference in
94
// some variants of Windows/hardware.
95
succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
97
MAX_PREAMBLE_STUB_SIZE);
99
ASSERT(false, "Failed to flush instruction cache.");
100
// We must not return an error here because the function has actually
101
// been patched, and returning an error would likely cause our client
102
// code not to unpatch it. So we just keep going.
105
return SIDESTEP_SUCCESS;
108
SideStepError PreamblePatcher::RawPatch(void* target_function,
109
void* replacement_function,
110
void** original_function_stub) {
111
if (!target_function || !replacement_function || !original_function_stub ||
112
(*original_function_stub) || target_function == replacement_function) {
113
ASSERT(false, "Preconditions not met");
114
return SIDESTEP_INVALID_PARAMETER;
117
// @see MAX_PREAMBLE_STUB_SIZE for an explanation of how we arrives at
119
byte* preamble_stub = new unsigned char[MAX_PREAMBLE_STUB_SIZE];
120
if (!preamble_stub) {
121
ASSERT(false, "Unable to allocate preamble-stub.");
122
return SIDESTEP_INSUFFICIENT_BUFFER;
125
// Change the protection of the newly allocated preamble stub to
126
// PAGE_EXECUTE_READWRITE. This is required to work with DEP (Data
127
// Execution Prevention) which will cause an exception if code is executed
128
// from a page on which you do not have read access.
129
DWORD old_stub_protect = 0;
130
BOOL succeeded = VirtualProtect(preamble_stub, MAX_PREAMBLE_STUB_SIZE,
131
PAGE_EXECUTE_READWRITE, &old_stub_protect);
133
ASSERT(false, "Failed to make page preamble stub read-write-execute.");
134
delete[] preamble_stub;
135
return SIDESTEP_ACCESS_DENIED;
138
SideStepError error_code = RawPatchWithStubAndProtections(target_function,
139
replacement_function,
141
MAX_PREAMBLE_STUB_SIZE,
143
if (SIDESTEP_SUCCESS != error_code) {
145
delete[] preamble_stub;
149
RAW_VLOG(1, "PreamblePatcher::RawPatch successfully patched 0x%x",
152
*original_function_stub = reinterpret_cast<void*>(preamble_stub);
153
return SIDESTEP_SUCCESS;
156
SideStepError PreamblePatcher::Unpatch(void* target_function,
157
void* replacement_function,
158
void* original_function_stub) {
159
ASSERT1(target_function && original_function_stub);
160
if (!target_function || !original_function_stub) {
161
return SIDESTEP_INVALID_PARAMETER;
164
// We disassemble the preamble of the _stub_ to see how many bytes we
165
// originally copied to the stub.
166
MiniDisassembler disassembler;
167
unsigned int preamble_bytes = 0;
168
while (preamble_bytes < 5) {
169
InstructionType instruction_type =
170
disassembler.Disassemble(
171
reinterpret_cast<byte*>(original_function_stub) + preamble_bytes,
173
if (IT_GENERIC != instruction_type) {
174
ASSERT(false, "Should only have generic instructions in stub!!");
175
return SIDESTEP_UNSUPPORTED_INSTRUCTION;
179
// Before unpatching, target_function should be a JMP to
180
// replacement_function. If it's not, then either it's an error, or
181
// we're falling into the case where the original instruction was a
182
// JMP, and we patched the jumped_to address rather than the JMP
183
// itself. (For instance, if malloc() is just a JMP to __malloc(),
184
// we patched __malloc() and not malloc().)
185
unsigned char* target = reinterpret_cast<unsigned char*>(target_function);
186
while (1) { // we stop when target is a JMP to replacement_function
187
if (target[0] != ASM_JMP32REL) {
188
ASSERT(false, "target_function does not look like it was patched.");
189
return SIDESTEP_INVALID_PARAMETER;
191
int relative_offset; // Windows guarantees int is 4 bytes
192
ASSERT1(sizeof(relative_offset) == 4);
193
memcpy(reinterpret_cast<void*>(&relative_offset),
194
reinterpret_cast<void*>(target + 1), 4);
195
unsigned char* jump_to = target + 5 + relative_offset;
196
if (jump_to == replacement_function)
198
target = jump_to; // follow the jmp
201
// We need to be able to write to a process-local copy of the first
202
// MAX_PREAMBLE_STUB_SIZE bytes of target_function
203
DWORD old_target_function_protect = 0;
204
BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target),
205
MAX_PREAMBLE_STUB_SIZE, PAGE_READWRITE,
206
&old_target_function_protect);
208
ASSERT(false, "Failed to make page containing target function "
210
return SIDESTEP_ACCESS_DENIED;
213
// Replace the first few bytes of the original function with the bytes we
214
// previously moved to the preamble stub.
215
memcpy(reinterpret_cast<void*>(target),
216
original_function_stub, preamble_bytes);
218
// Stub is now useless so delete it.
219
// [csilvers: Commented out for perftools because it causes big problems
220
// when we're unpatching malloc. We just let this live on as a leak.]
221
//delete original_function_stub;
223
// Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of
224
// target to what they were before we started goofing around.
225
succeeded = ::VirtualProtect(reinterpret_cast<void*>(target),
226
MAX_PREAMBLE_STUB_SIZE,
227
old_target_function_protect,
228
&old_target_function_protect);
230
// Flush the instruction cache to make sure the processor doesn't execute the
231
// old version of the instructions (before our patch).
233
// See comment on FlushInstructionCache elsewhere in this file.
234
succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
236
MAX_PREAMBLE_STUB_SIZE);
238
ASSERT(false, "Failed to flush instruction cache.");
239
return SIDESTEP_UNEXPECTED;
242
RAW_VLOG(1, "PreamblePatcher::Unpatch successfully unpatched 0x%x",
244
return SIDESTEP_SUCCESS;
247
}; // namespace sidestep