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

Side by Side Diff: chrome_elf/hook_util/hook_util.cc

Issue 2183263003: [chrome_elf] Big ELF cleanup. Part 1. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Adjusted g_crash_reports. Created 4 years, 4 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
OLDNEW
(Empty)
1 // Copyright 2014 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 "hook_util.h"
6
7 #include <versionhelpers.h> // windows.h must be before
8
9 #include "base/win/pe_image.h"
10 #include "sandbox/win/src/interception_internal.h"
11 #include "sandbox/win/src/internal_types.h"
12 #include "sandbox/win/src/sandbox_utils.h"
13 #include "sandbox/win/src/service_resolver.h"
14
15 namespace {
16
17 //------------------------------------------------------------------------------
18 // Common hooking utility functions - LOCAL
19 //------------------------------------------------------------------------------
20
21 #if !defined(_WIN64)
22 // Whether a process is running under WOW64 (the wrapper that allows 32-bit
23 // processes to run on 64-bit versions of Windows). This will return
24 // WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
25 // Chrome on 64-bit Windows". WOW64_UNKNOWN means "an error occurred", e.g.
26 // the process does not have sufficient access rights to determine this.
27 enum WOW64Status {
28 WOW64_DISABLED,
29 WOW64_ENABLED,
30 WOW64_UNKNOWN,
31 };
32
33 WOW64Status GetWOW64StatusForCurrentProcess() {
34 typedef BOOL(WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL);
35 IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
36 GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
37 if (!is_wow64_process)
38 return WOW64_DISABLED;
39 BOOL is_wow64 = FALSE;
40 if (!is_wow64_process(GetCurrentProcess(), &is_wow64))
41 return WOW64_UNKNOWN;
42 return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
43 }
44 #endif // !defined(_WIN64)
45
46 // Change the page protections to writable, copy the data,
47 // restore protections. Returns a winerror code.
48 DWORD PatchMem(void* target, void* new_bytes, size_t length) {
49 if (target == nullptr || new_bytes == nullptr || length == 0)
50 return ERROR_INVALID_PARAMETER;
51
52 // Preserve executable state.
53 MEMORY_BASIC_INFORMATION memory_info = {};
54 if (!::VirtualQuery(target, &memory_info, sizeof(memory_info))) {
55 return GetLastError();
56 }
57
58 DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
59 PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
60 memory_info.Protect;
61
62 // Make target writeable.
63 DWORD old_page_protection = 0;
64 if (!::VirtualProtect(target, length,
65 is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
66 &old_page_protection)) {
67 return GetLastError();
68 }
69
70 // Write the data.
71 ::memcpy(target, new_bytes, length);
72
73 // Restore old page protection.
74 if (!::VirtualProtect(target, length, old_page_protection,
75 &old_page_protection)) {
76 // Yes, this could fail. However, memory was already patched.
77 #ifdef _DEBUG
78 assert(false);
79 #endif // _DEBUG
80 }
81
82 return NO_ERROR;
83 }
84
85 //------------------------------------------------------------------------------
86 // Import Address Table hooking support - LOCAL
87 //------------------------------------------------------------------------------
88
89 void* GetIATFunctionPtr(IMAGE_THUNK_DATA* iat_thunk) {
90 if (iat_thunk == nullptr)
91 return nullptr;
92
93 // Works around the 64 bit portability warning:
94 // The Function member inside IMAGE_THUNK_DATA is really a pointer
95 // to the IAT function. IMAGE_THUNK_DATA correctly maps to IMAGE_THUNK_DATA32
96 // or IMAGE_THUNK_DATA64 for correct pointer size.
97 union FunctionThunk {
98 IMAGE_THUNK_DATA thunk;
99 void* pointer;
100 } iat_function;
101
102 iat_function.thunk = *iat_thunk;
103 return iat_function.pointer;
104 }
105
106 // Used to pass target function information during pe_image enumeration.
107 struct IATHookFunctionInfo {
108 bool finished_operation;
109 const char* imported_from_module;
110 const char* function_name;
111 void* new_function;
112 void** old_function;
113 IMAGE_THUNK_DATA** iat_thunk;
114 DWORD return_code;
115 };
116
117 // Callback function for pe_image enumeration. This function is called from
118 // within PEImage::EnumOneImportChunk().
119 // NOTE: Returning true means continue enumerating. False means stop.
120 bool IATFindHookFuncCallback(const base::win::PEImage& image,
121 const char* module,
122 DWORD ordinal,
123 const char* import_name,
124 DWORD hint,
125 IMAGE_THUNK_DATA* iat,
126 void* cookie) {
127 IATHookFunctionInfo* hook_func_info =
128 reinterpret_cast<IATHookFunctionInfo*>(cookie);
129 if (hook_func_info == nullptr)
130 return false;
131
132 // Check for the right module.
133 if (module == nullptr ||
134 ::strnicmp(module, hook_func_info->imported_from_module,
135 ::strlen(module)) != 0)
136 return true;
137
138 // Check for the right function.
139 if (import_name == nullptr ||
140 ::strnicmp(import_name, hook_func_info->function_name,
141 ::strlen(import_name)) != 0)
142 return true;
143
144 // At this point, the target function was found. Even if something fails now,
145 // don't do any further enumerating.
146 hook_func_info->finished_operation = true;
147
148 // This is it. Do the hook!
149 // 1) Save the old function pointer.
150 *(hook_func_info->old_function) = GetIATFunctionPtr(iat);
151
152 // 2) Save the IAT thunk.
153 *(hook_func_info->iat_thunk) = iat;
154
155 // 3) Sanity check the pointer sizes (architectures).
156 if (sizeof(iat->u1.Function) != sizeof(hook_func_info->new_function)) {
157 hook_func_info->return_code = ERROR_BAD_ENVIRONMENT;
158 return false;
159 }
160
161 // 4) Patch the function pointer.
162 hook_func_info->return_code =
163 PatchMem(&(iat->u1.Function), &(hook_func_info->new_function),
164 sizeof(hook_func_info->new_function));
165
166 return false;
167 }
168
169 DWORD ApplyIATHook(HMODULE module_handle,
robertshield 2016/08/02 02:38:41 Please document this function Are the return value
penny 2016/08/02 21:07:43 Done.
170 const char* imported_from_module,
171 const char* function_name,
172 void* new_function,
173 void** old_function,
174 IMAGE_THUNK_DATA** iat_thunk) {
175 base::win::PEImage target_image(module_handle);
176 if (!target_image.VerifyMagic())
177 return 1;
robertshield 2016/08/02 02:38:41 Along the same lines, should this be ERROR_INVALID
penny 2016/08/02 21:07:43 Done.
178
179 IATHookFunctionInfo hook_info = {false,
180 imported_from_module,
181 function_name,
182 new_function,
183 old_function,
184 iat_thunk,
185 ERROR_GEN_FAILURE};
186
187 // First go through the IAT. If we don't find the import we are looking
188 // for in IAT, search delay import table.
189 target_image.EnumAllImports(IATFindHookFuncCallback, &hook_info);
190 if (!hook_info.finished_operation) {
191 target_image.EnumAllDelayImports(IATFindHookFuncCallback, &hook_info);
192 }
193
194 return hook_info.return_code;
195 }
196
197 DWORD RemoveIATHook(void* intercept_function,
198 void* original_function,
199 IMAGE_THUNK_DATA* iat_thunk) {
200 if (GetIATFunctionPtr(iat_thunk) != intercept_function) {
201 // Someone else has messed with the same target. Cannot unpatch.
202 #ifdef _DEBUG
203 assert(false);
204 #endif // _DEBUG
205 return ERROR_INVALID_FUNCTION;
206 }
207
208 return PatchMem(&(iat_thunk->u1.Function), &original_function,
209 sizeof(original_function));
210 }
211
212 } // namespace
213
214 namespace elf_hook {
215
216 //------------------------------------------------------------------------------
217 // System Service hooking support
218 //------------------------------------------------------------------------------
219
220 sandbox::ServiceResolverThunk* HookSystemService(bool relaxed) {
221 // Create a thunk via the appropriate ServiceResolver instance.
222 sandbox::ServiceResolverThunk* thunk = nullptr;
223
224 // No hooking unsupported OS versions.
robertshield 2016/08/02 02:38:41 nit: No hooking _on_ unsupported
penny 2016/08/02 21:07:43 Well, technically we're hooking the operating syst
robertshield 2016/08/03 04:52:45 Potato, po-tah-to I guess, 'twas merely a nit :-)
225 if (!::IsWindows7OrGreater())
226 return thunk;
227
228 // Pseudo-handle, no need to close.
229 HANDLE current_process = ::GetCurrentProcess();
230
231 #if defined(_WIN64)
232 // ServiceResolverThunk can handle all the formats in 64-bit (instead only
233 // handling one like it does in 32-bit versions).
234 thunk = new sandbox::ServiceResolverThunk(current_process, relaxed);
235 #else
236 if (GetWOW64StatusForCurrentProcess() == WOW64_ENABLED) {
237 if (::IsWindows10OrGreater())
238 thunk = new sandbox::Wow64W10ResolverThunk(current_process, relaxed);
239 else if (::IsWindows8OrGreater())
240 thunk = new sandbox::Wow64W8ResolverThunk(current_process, relaxed);
241 else
242 thunk = new sandbox::Wow64ResolverThunk(current_process, relaxed);
243 } else if (::IsWindows8OrGreater()) {
244 thunk = new sandbox::Win8ResolverThunk(current_process, relaxed);
245 } else {
246 thunk = new sandbox::ServiceResolverThunk(current_process, relaxed);
247 }
248 #endif
249
250 return thunk;
251 }
252
253 //------------------------------------------------------------------------------
254 // Import Address Table hooking support
255 //------------------------------------------------------------------------------
256
257 IATHook::IATHook()
258 : intercept_function_(nullptr),
259 original_function_(nullptr),
260 iat_thunk_(nullptr) {}
261
262 IATHook::~IATHook() {
263 if (intercept_function_ != nullptr) {
264 if (Unhook() != NO_ERROR) {
265 #ifdef _DEBUG
266 assert(false);
267 #endif // _DEBUG
268 }
269 }
270 }
271
272 DWORD IATHook::Hook(HMODULE module,
273 const char* imported_from_module,
274 const char* function_name,
275 void* new_function) {
276 if ((module == 0 || module == INVALID_HANDLE_VALUE) ||
277 imported_from_module == nullptr || function_name == nullptr ||
278 new_function == nullptr)
279 return ERROR_INVALID_PARAMETER;
280
281 DWORD winerror = ApplyIATHook(module, imported_from_module, function_name,
282 new_function, &original_function_, &iat_thunk_);
283 if (winerror == NO_ERROR) {
284 intercept_function_ = new_function;
285 #ifdef _DEBUG
286 if (original_function_ == new_function)
287 assert(false);
288 #endif //_DEBUG
289 }
290
291 return winerror;
292 }
293
294 DWORD IATHook::Unhook() {
295 DWORD winerror =
296 RemoveIATHook(intercept_function_, original_function_, iat_thunk_);
297 #ifdef _DEBUG
298 if (winerror != NO_ERROR)
299 assert(false);
300 #endif //_DEBUG
301
302 intercept_function_ = nullptr;
303 original_function_ = nullptr;
304 iat_thunk_ = nullptr;
305
306 return winerror;
307 }
308
309 } // namespace elf_hook
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698