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

Side by Side Diff: sandbox/win/src/service_resolver_32.cc

Issue 1851213002: Remove sandbox on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix nacl compile issues Created 4 years, 8 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
« no previous file with comments | « sandbox/win/src/service_resolver.cc ('k') | sandbox/win/src/service_resolver_64.cc » ('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) 2012 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 "sandbox/win/src/service_resolver.h"
6
7 #include <stddef.h>
8
9 #include "base/bit_cast.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "sandbox/win/src/win_utils.h"
12
13 namespace {
14 #pragma pack(push, 1)
15
16 const BYTE kMovEax = 0xB8;
17 const BYTE kMovEdx = 0xBA;
18 const USHORT kMovEdxEsp = 0xD48B;
19 const USHORT kCallPtrEdx = 0x12FF;
20 const USHORT kCallEdx = 0xD2FF;
21 const BYTE kCallEip = 0xE8;
22 const BYTE kRet = 0xC2;
23 const BYTE kRet2 = 0xC3;
24 const USHORT kJmpEdx = 0xE2FF;
25 const USHORT kXorEcx = 0xC933;
26 const ULONG kLeaEdx = 0x0424548D;
27 const ULONG kCallFs1 = 0xC015FF64;
28 const USHORT kCallFs2 = 0;
29 const BYTE kCallFs3 = 0;
30 const BYTE kAddEsp1 = 0x83;
31 const USHORT kAddEsp2 = 0x4C4;
32 const BYTE kJmp32 = 0xE9;
33 const USHORT kSysenter = 0x340F;
34
35 // Service code for 32 bit systems.
36 // NOTE: on win2003 "call dword ptr [edx]" is "call edx".
37 struct ServiceEntry {
38 // This struct contains roughly the following code:
39 // 00 mov eax,25h
40 // 05 mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
41 // 0a call dword ptr [edx]
42 // 0c ret 2Ch
43 // 0f nop
44 BYTE mov_eax; // = B8
45 ULONG service_id;
46 BYTE mov_edx; // = BA
47 ULONG stub;
48 USHORT call_ptr_edx; // = FF 12
49 BYTE ret; // = C2
50 USHORT num_params;
51 BYTE nop;
52 };
53
54 // Service code for 32 bit Windows 8.
55 struct ServiceEntryW8 {
56 // This struct contains the following code:
57 // 00 b825000000 mov eax,25h
58 // 05 e803000000 call eip+3
59 // 0a c22c00 ret 2Ch
60 // 0d 8bd4 mov edx,esp
61 // 0f 0f34 sysenter
62 // 11 c3 ret
63 // 12 8bff mov edi,edi
64 BYTE mov_eax; // = B8
65 ULONG service_id;
66 BYTE call_eip; // = E8
67 ULONG call_offset;
68 BYTE ret_p; // = C2
69 USHORT num_params;
70 USHORT mov_edx_esp; // = BD D4
71 USHORT sysenter; // = 0F 34
72 BYTE ret; // = C3
73 USHORT nop;
74 };
75
76 // Service code for a 32 bit process running on a 64 bit os.
77 struct Wow64Entry {
78 // This struct may contain one of two versions of code:
79 // 1. For XP, Vista and 2K3:
80 // 00 b825000000 mov eax, 25h
81 // 05 33c9 xor ecx, ecx
82 // 07 8d542404 lea edx, [esp + 4]
83 // 0b 64ff15c0000000 call dword ptr fs:[0C0h]
84 // 12 c22c00 ret 2Ch
85 //
86 // 2. For Windows 7:
87 // 00 b825000000 mov eax, 25h
88 // 05 33c9 xor ecx, ecx
89 // 07 8d542404 lea edx, [esp + 4]
90 // 0b 64ff15c0000000 call dword ptr fs:[0C0h]
91 // 12 83c404 add esp, 4
92 // 15 c22c00 ret 2Ch
93 //
94 // So we base the structure on the bigger one:
95 BYTE mov_eax; // = B8
96 ULONG service_id;
97 USHORT xor_ecx; // = 33 C9
98 ULONG lea_edx; // = 8D 54 24 04
99 ULONG call_fs1; // = 64 FF 15 C0
100 USHORT call_fs2; // = 00 00
101 BYTE call_fs3; // = 00
102 BYTE add_esp1; // = 83 or ret
103 USHORT add_esp2; // = C4 04 or num_params
104 BYTE ret; // = C2
105 USHORT num_params;
106 };
107
108 // Service code for a 32 bit process running on 64 bit Windows 8.
109 struct Wow64EntryW8 {
110 // 00 b825000000 mov eax, 25h
111 // 05 64ff15c0000000 call dword ptr fs:[0C0h]
112 // 0b c22c00 ret 2Ch
113 // 0f 90 nop
114 BYTE mov_eax; // = B8
115 ULONG service_id;
116 ULONG call_fs1; // = 64 FF 15 C0
117 USHORT call_fs2; // = 00 00
118 BYTE call_fs3; // = 00
119 BYTE ret; // = C2
120 USHORT num_params;
121 BYTE nop;
122 };
123
124 // Service code for a 32 bit process running on 64 bit Windows 10.
125 struct Wow64EntryW10 {
126 // 00 b828000000 mov eax, 28h
127 // 05 bab0d54877 mov edx, 7748D5B0h
128 // 09 ffd2 call edx
129 // 0b c22800 ret 28h
130 BYTE mov_eax; // = B8
131 ULONG service_id;
132 BYTE mov_edx; // = BA
133 ULONG mov_edx_param;
134 USHORT call_edx; // = FF D2
135 BYTE ret; // = C2
136 USHORT num_params;
137 };
138
139 // Make sure that relaxed patching works as expected.
140 const size_t kMinServiceSize = offsetof(ServiceEntry, ret);
141 static_assert(sizeof(ServiceEntryW8) >= kMinServiceSize,
142 "wrong service length");
143 static_assert(sizeof(Wow64Entry) >= kMinServiceSize, "wrong service length");
144 static_assert(sizeof(Wow64EntryW8) >= kMinServiceSize, "wrong service length");
145
146 struct ServiceFullThunk {
147 union {
148 ServiceEntry original;
149 ServiceEntryW8 original_w8;
150 Wow64Entry wow_64;
151 Wow64EntryW8 wow_64_w8;
152 };
153 int internal_thunk; // Dummy member to the beginning of the internal thunk.
154 };
155
156 #pragma pack(pop)
157
158 }; // namespace
159
160 namespace sandbox {
161
162 NTSTATUS ServiceResolverThunk::Setup(const void* target_module,
163 const void* interceptor_module,
164 const char* target_name,
165 const char* interceptor_name,
166 const void* interceptor_entry_point,
167 void* thunk_storage,
168 size_t storage_bytes,
169 size_t* storage_used) {
170 NTSTATUS ret = Init(target_module, interceptor_module, target_name,
171 interceptor_name, interceptor_entry_point,
172 thunk_storage, storage_bytes);
173 if (!NT_SUCCESS(ret))
174 return ret;
175
176 relative_jump_ = 0;
177 size_t thunk_bytes = GetThunkSize();
178 scoped_ptr<char[]> thunk_buffer(new char[thunk_bytes]);
179 ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(
180 thunk_buffer.get());
181
182 if (!IsFunctionAService(&thunk->original) &&
183 (!relaxed_ || !SaveOriginalFunction(&thunk->original, thunk_storage))) {
184 return STATUS_UNSUCCESSFUL;
185 }
186
187 ret = PerformPatch(thunk, thunk_storage);
188
189 if (NULL != storage_used)
190 *storage_used = thunk_bytes;
191
192 return ret;
193 }
194
195 size_t ServiceResolverThunk::GetThunkSize() const {
196 return offsetof(ServiceFullThunk, internal_thunk) + GetInternalThunkSize();
197 }
198
199 NTSTATUS ServiceResolverThunk::CopyThunk(const void* target_module,
200 const char* target_name,
201 BYTE* thunk_storage,
202 size_t storage_bytes,
203 size_t* storage_used) {
204 NTSTATUS ret = ResolveTarget(target_module, target_name, &target_);
205 if (!NT_SUCCESS(ret))
206 return ret;
207
208 size_t thunk_bytes = GetThunkSize();
209 if (storage_bytes < thunk_bytes)
210 return STATUS_UNSUCCESSFUL;
211
212 ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(thunk_storage);
213
214 if (!IsFunctionAService(&thunk->original) &&
215 (!relaxed_ || !SaveOriginalFunction(&thunk->original, thunk_storage))) {
216 return STATUS_UNSUCCESSFUL;
217 }
218
219 if (NULL != storage_used)
220 *storage_used = thunk_bytes;
221
222 return ret;
223 }
224
225 bool ServiceResolverThunk::IsFunctionAService(void* local_thunk) const {
226 ServiceEntry function_code;
227 SIZE_T read;
228 if (!::ReadProcessMemory(process_, target_, &function_code,
229 sizeof(function_code), &read)) {
230 return false;
231 }
232
233 if (sizeof(function_code) != read)
234 return false;
235
236 if (kMovEax != function_code.mov_eax ||
237 kMovEdx != function_code.mov_edx ||
238 (kCallPtrEdx != function_code.call_ptr_edx &&
239 kCallEdx != function_code.call_ptr_edx) ||
240 kRet != function_code.ret) {
241 return false;
242 }
243
244 // Find the system call pointer if we don't already have it.
245 if (kCallEdx != function_code.call_ptr_edx) {
246 DWORD ki_system_call;
247 if (!::ReadProcessMemory(process_,
248 bit_cast<const void*>(function_code.stub),
249 &ki_system_call, sizeof(ki_system_call), &read)) {
250 return false;
251 }
252
253 if (sizeof(ki_system_call) != read)
254 return false;
255
256 HMODULE module_1, module_2;
257 // last check, call_stub should point to a KiXXSystemCall function on ntdll
258 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
259 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
260 bit_cast<const wchar_t*>(ki_system_call),
261 &module_1)) {
262 return false;
263 }
264
265 if (NULL != ntdll_base_) {
266 // This path is only taken when running the unit tests. We want to be
267 // able to patch a buffer in memory, so target_ is not inside ntdll.
268 module_2 = ntdll_base_;
269 } else {
270 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
271 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
272 reinterpret_cast<const wchar_t*>(target_),
273 &module_2))
274 return false;
275 }
276
277 if (module_1 != module_2)
278 return false;
279 }
280
281 // Save the verified code
282 memcpy(local_thunk, &function_code, sizeof(function_code));
283
284 return true;
285 }
286
287 NTSTATUS ServiceResolverThunk::PerformPatch(void* local_thunk,
288 void* remote_thunk) {
289 ServiceEntry intercepted_code;
290 size_t bytes_to_write = sizeof(intercepted_code);
291 ServiceFullThunk *full_local_thunk = reinterpret_cast<ServiceFullThunk*>(
292 local_thunk);
293 ServiceFullThunk *full_remote_thunk = reinterpret_cast<ServiceFullThunk*>(
294 remote_thunk);
295
296 // patch the original code
297 memcpy(&intercepted_code, &full_local_thunk->original,
298 sizeof(intercepted_code));
299 intercepted_code.mov_eax = kMovEax;
300 intercepted_code.service_id = full_local_thunk->original.service_id;
301 intercepted_code.mov_edx = kMovEdx;
302 intercepted_code.stub = bit_cast<ULONG>(&full_remote_thunk->internal_thunk);
303 intercepted_code.call_ptr_edx = kJmpEdx;
304 bytes_to_write = kMinServiceSize;
305
306 if (relative_jump_) {
307 intercepted_code.mov_eax = kJmp32;
308 intercepted_code.service_id = relative_jump_;
309 bytes_to_write = offsetof(ServiceEntry, mov_edx);
310 }
311
312 // setup the thunk
313 SetInternalThunk(&full_local_thunk->internal_thunk, GetInternalThunkSize(),
314 remote_thunk, interceptor_);
315
316 size_t thunk_size = GetThunkSize();
317
318 // copy the local thunk buffer to the child
319 SIZE_T written;
320 if (!::WriteProcessMemory(process_, remote_thunk, local_thunk,
321 thunk_size, &written)) {
322 return STATUS_UNSUCCESSFUL;
323 }
324
325 if (thunk_size != written)
326 return STATUS_UNSUCCESSFUL;
327
328 // and now change the function to intercept, on the child
329 if (NULL != ntdll_base_) {
330 // running a unit test
331 if (!::WriteProcessMemory(process_, target_, &intercepted_code,
332 bytes_to_write, &written))
333 return STATUS_UNSUCCESSFUL;
334 } else {
335 if (!WriteProtectedChildMemory(process_, target_, &intercepted_code,
336 bytes_to_write))
337 return STATUS_UNSUCCESSFUL;
338 }
339
340 return STATUS_SUCCESS;
341 }
342
343 bool ServiceResolverThunk::SaveOriginalFunction(void* local_thunk,
344 void* remote_thunk) {
345 ServiceEntry function_code;
346 SIZE_T read;
347 if (!::ReadProcessMemory(process_, target_, &function_code,
348 sizeof(function_code), &read)) {
349 return false;
350 }
351
352 if (sizeof(function_code) != read)
353 return false;
354
355 if (kJmp32 == function_code.mov_eax) {
356 // Plain old entry point patch. The relative jump address follows it.
357 ULONG relative = function_code.service_id;
358
359 // First, fix our copy of their patch.
360 relative += bit_cast<ULONG>(target_) - bit_cast<ULONG>(remote_thunk);
361
362 function_code.service_id = relative;
363
364 // And now, remember how to re-patch it.
365 ServiceFullThunk *full_thunk =
366 reinterpret_cast<ServiceFullThunk*>(remote_thunk);
367
368 const ULONG kJmp32Size = 5;
369
370 relative_jump_ = bit_cast<ULONG>(&full_thunk->internal_thunk) -
371 bit_cast<ULONG>(target_) - kJmp32Size;
372 }
373
374 // Save the verified code
375 memcpy(local_thunk, &function_code, sizeof(function_code));
376
377 return true;
378 }
379
380 bool Wow64ResolverThunk::IsFunctionAService(void* local_thunk) const {
381 Wow64Entry function_code;
382 SIZE_T read;
383 if (!::ReadProcessMemory(process_, target_, &function_code,
384 sizeof(function_code), &read)) {
385 return false;
386 }
387
388 if (sizeof(function_code) != read)
389 return false;
390
391 if (kMovEax != function_code.mov_eax || kXorEcx != function_code.xor_ecx ||
392 kLeaEdx != function_code.lea_edx || kCallFs1 != function_code.call_fs1 ||
393 kCallFs2 != function_code.call_fs2 ||
394 kCallFs3 != function_code.call_fs3) {
395 return false;
396 }
397
398 if ((kAddEsp1 == function_code.add_esp1 &&
399 kAddEsp2 == function_code.add_esp2 &&
400 kRet == function_code.ret) || kRet == function_code.add_esp1) {
401 // Save the verified code
402 memcpy(local_thunk, &function_code, sizeof(function_code));
403 return true;
404 }
405
406 return false;
407 }
408
409 bool Wow64W8ResolverThunk::IsFunctionAService(void* local_thunk) const {
410 Wow64EntryW8 function_code;
411 SIZE_T read;
412 if (!::ReadProcessMemory(process_, target_, &function_code,
413 sizeof(function_code), &read)) {
414 return false;
415 }
416
417 if (sizeof(function_code) != read)
418 return false;
419
420 if (kMovEax != function_code.mov_eax || kCallFs1 != function_code.call_fs1 ||
421 kCallFs2 != function_code.call_fs2 ||
422 kCallFs3 != function_code.call_fs3 || kRet != function_code.ret) {
423 return false;
424 }
425
426 // Save the verified code
427 memcpy(local_thunk, &function_code, sizeof(function_code));
428 return true;
429 }
430
431 bool Win8ResolverThunk::IsFunctionAService(void* local_thunk) const {
432 ServiceEntryW8 function_code;
433 SIZE_T read;
434 if (!::ReadProcessMemory(process_, target_, &function_code,
435 sizeof(function_code), &read)) {
436 return false;
437 }
438
439 if (sizeof(function_code) != read)
440 return false;
441
442 if (kMovEax != function_code.mov_eax || kCallEip != function_code.call_eip ||
443 function_code.call_offset != 3 || kRet != function_code.ret_p ||
444 kMovEdxEsp != function_code.mov_edx_esp ||
445 kSysenter != function_code.sysenter || kRet2 != function_code.ret) {
446 return false;
447 }
448
449 // Save the verified code
450 memcpy(local_thunk, &function_code, sizeof(function_code));
451
452 return true;
453 }
454
455 bool Wow64W10ResolverThunk::IsFunctionAService(void* local_thunk) const {
456 Wow64EntryW10 function_code;
457 SIZE_T read;
458 if (!::ReadProcessMemory(process_, target_, &function_code,
459 sizeof(function_code), &read)) {
460 return false;
461 }
462
463 if (sizeof(function_code) != read)
464 return false;
465
466 if (kMovEax != function_code.mov_eax ||
467 kMovEdx != function_code.mov_edx ||
468 kCallEdx != function_code.call_edx ||
469 kRet != function_code.ret) {
470 return false;
471 }
472
473 // Save the verified code
474 memcpy(local_thunk, &function_code, sizeof(function_code));
475 return true;
476 }
477
478 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/win/src/service_resolver.cc ('k') | sandbox/win/src/service_resolver_64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698