Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: app/win/iat_patch_function.cc

Issue 7231016: Move app/win/* files to base/win/, ui/base/win and chrome/common/ directories. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: brettw review Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « app/win/iat_patch_function.h ('k') | app/win/scoped_co_mem.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "app/win/iat_patch_function.h"
6
7 #include "base/logging.h"
8 #include "base/win/pe_image.h"
9
10 namespace app {
11 namespace win {
12
13 namespace {
14
15 struct InterceptFunctionInformation {
16 bool finished_operation;
17 const char* imported_from_module;
18 const char* function_name;
19 void* new_function;
20 void** old_function;
21 IMAGE_THUNK_DATA** iat_thunk;
22 DWORD return_code;
23 };
24
25 void* GetIATFunction(IMAGE_THUNK_DATA* iat_thunk) {
26 if (NULL == iat_thunk) {
27 NOTREACHED();
28 return NULL;
29 }
30
31 // Works around the 64 bit portability warning:
32 // The Function member inside IMAGE_THUNK_DATA is really a pointer
33 // to the IAT function. IMAGE_THUNK_DATA correctly maps to IMAGE_THUNK_DATA32
34 // or IMAGE_THUNK_DATA64 for correct pointer size.
35 union FunctionThunk {
36 IMAGE_THUNK_DATA thunk;
37 void* pointer;
38 } iat_function;
39
40 iat_function.thunk = *iat_thunk;
41 return iat_function.pointer;
42 }
43 // Change the page protection (of code pages) to writable and copy
44 // the data at the specified location
45 //
46 // Arguments:
47 // old_code Target location to copy
48 // new_code Source
49 // length Number of bytes to copy
50 //
51 // Returns: Windows error code (winerror.h). NO_ERROR if successful
52 DWORD ModifyCode(void* old_code, void* new_code, int length) {
53 if ((NULL == old_code) || (NULL == new_code) || (0 == length)) {
54 NOTREACHED();
55 return ERROR_INVALID_PARAMETER;
56 }
57
58 // Change the page protection so that we can write.
59 DWORD error = NO_ERROR;
60 DWORD old_page_protection = 0;
61 if (VirtualProtect(old_code,
62 length,
63 PAGE_READWRITE,
64 &old_page_protection)) {
65
66 // Write the data.
67 CopyMemory(old_code, new_code, length);
68
69 // Restore the old page protection.
70 error = ERROR_SUCCESS;
71 VirtualProtect(old_code,
72 length,
73 old_page_protection,
74 &old_page_protection);
75 } else {
76 error = GetLastError();
77 NOTREACHED();
78 }
79
80 return error;
81 }
82
83 bool InterceptEnumCallback(const base::win::PEImage& image, const char* module,
84 DWORD ordinal, const char* name, DWORD hint,
85 IMAGE_THUNK_DATA* iat, void* cookie) {
86 InterceptFunctionInformation* intercept_information =
87 reinterpret_cast<InterceptFunctionInformation*>(cookie);
88
89 if (NULL == intercept_information) {
90 NOTREACHED();
91 return false;
92 }
93
94 DCHECK(module);
95
96 if ((0 == lstrcmpiA(module, intercept_information->imported_from_module)) &&
97 (NULL != name) &&
98 (0 == lstrcmpiA(name, intercept_information->function_name))) {
99 // Save the old pointer.
100 if (NULL != intercept_information->old_function) {
101 *(intercept_information->old_function) = GetIATFunction(iat);
102 }
103
104 if (NULL != intercept_information->iat_thunk) {
105 *(intercept_information->iat_thunk) = iat;
106 }
107
108 // portability check
109 COMPILE_ASSERT(sizeof(iat->u1.Function) ==
110 sizeof(intercept_information->new_function), unknown_IAT_thunk_format);
111
112 // Patch the function.
113 intercept_information->return_code =
114 ModifyCode(&(iat->u1.Function),
115 &(intercept_information->new_function),
116 sizeof(intercept_information->new_function));
117
118 // Terminate further enumeration.
119 intercept_information->finished_operation = true;
120 return false;
121 }
122
123 return true;
124 }
125
126 // Helper to intercept a function in an import table of a specific
127 // module.
128 //
129 // Arguments:
130 // module_handle Module to be intercepted
131 // imported_from_module Module that exports the symbol
132 // function_name Name of the API to be intercepted
133 // new_function Interceptor function
134 // old_function Receives the original function pointer
135 // iat_thunk Receives pointer to IAT_THUNK_DATA
136 // for the API from the import table.
137 //
138 // Returns: Returns NO_ERROR on success or Windows error code
139 // as defined in winerror.h
140 DWORD InterceptImportedFunction(HMODULE module_handle,
141 const char* imported_from_module,
142 const char* function_name, void* new_function,
143 void** old_function,
144 IMAGE_THUNK_DATA** iat_thunk) {
145 if ((NULL == module_handle) || (NULL == imported_from_module) ||
146 (NULL == function_name) || (NULL == new_function)) {
147 NOTREACHED();
148 return ERROR_INVALID_PARAMETER;
149 }
150
151 base::win::PEImage target_image(module_handle);
152 if (!target_image.VerifyMagic()) {
153 NOTREACHED();
154 return ERROR_INVALID_PARAMETER;
155 }
156
157 InterceptFunctionInformation intercept_information = {
158 false,
159 imported_from_module,
160 function_name,
161 new_function,
162 old_function,
163 iat_thunk,
164 ERROR_GEN_FAILURE};
165
166 // First go through the IAT. If we don't find the import we are looking
167 // for in IAT, search delay import table.
168 target_image.EnumAllImports(InterceptEnumCallback, &intercept_information);
169 if (!intercept_information.finished_operation) {
170 target_image.EnumAllDelayImports(InterceptEnumCallback,
171 &intercept_information);
172 }
173
174 return intercept_information.return_code;
175 }
176
177 // Restore intercepted IAT entry with the original function.
178 //
179 // Arguments:
180 // intercept_function Interceptor function
181 // original_function Receives the original function pointer
182 //
183 // Returns: Returns NO_ERROR on success or Windows error code
184 // as defined in winerror.h
185 DWORD RestoreImportedFunction(void* intercept_function,
186 void* original_function,
187 IMAGE_THUNK_DATA* iat_thunk) {
188 if ((NULL == intercept_function) || (NULL == original_function) ||
189 (NULL == iat_thunk)) {
190 NOTREACHED();
191 return ERROR_INVALID_PARAMETER;
192 }
193
194 if (GetIATFunction(iat_thunk) != intercept_function) {
195 // Check if someone else has intercepted on top of us.
196 // We cannot unpatch in this case, just raise a red flag.
197 NOTREACHED();
198 return ERROR_INVALID_FUNCTION;
199 }
200
201 return ModifyCode(&(iat_thunk->u1.Function),
202 &original_function,
203 sizeof(original_function));
204 }
205
206 } // namespace
207
208 IATPatchFunction::IATPatchFunction()
209 : module_handle_(NULL),
210 original_function_(NULL),
211 iat_thunk_(NULL),
212 intercept_function_(NULL) {
213 }
214
215 IATPatchFunction::~IATPatchFunction() {
216 if (NULL != intercept_function_) {
217 DWORD error = Unpatch();
218 DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
219 }
220 }
221
222 DWORD IATPatchFunction::Patch(const wchar_t* module,
223 const char* imported_from_module,
224 const char* function_name,
225 void* new_function) {
226 DCHECK_EQ(static_cast<void*>(NULL), original_function_);
227 DCHECK_EQ(static_cast<IMAGE_THUNK_DATA*>(NULL), iat_thunk_);
228 DCHECK_EQ(static_cast<void*>(NULL), intercept_function_);
229
230 HMODULE module_handle = LoadLibraryW(module);
231
232 if (module_handle == NULL) {
233 NOTREACHED();
234 return GetLastError();
235 }
236
237 DWORD error = InterceptImportedFunction(module_handle,
238 imported_from_module,
239 function_name,
240 new_function,
241 &original_function_,
242 &iat_thunk_);
243
244 if (NO_ERROR == error) {
245 DCHECK_NE(original_function_, intercept_function_);
246 module_handle_ = module_handle;
247 intercept_function_ = new_function;
248 } else {
249 FreeLibrary(module_handle);
250 }
251
252 return error;
253 }
254
255 DWORD IATPatchFunction::Unpatch() {
256 DWORD error = RestoreImportedFunction(intercept_function_,
257 original_function_,
258 iat_thunk_);
259 DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
260
261 // Hands off the intercept if we fail to unpatch.
262 // If IATPatchFunction::Unpatch fails during RestoreImportedFunction
263 // it means that we cannot safely unpatch the import address table
264 // patch. In this case its better to be hands off the intercept as
265 // trying to unpatch again in the destructor of IATPatchFunction is
266 // not going to be any safer
267 if (module_handle_)
268 FreeLibrary(module_handle_);
269 module_handle_ = NULL;
270 intercept_function_ = NULL;
271 original_function_ = NULL;
272 iat_thunk_ = NULL;
273
274 return error;
275 }
276
277 } // namespace win
278 } // namespace app
OLDNEW
« no previous file with comments | « app/win/iat_patch_function.h ('k') | app/win/scoped_co_mem.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698