OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sandbox/src/service_resolver.h" | 5 #include "sandbox/src/service_resolver.h" |
6 | 6 |
7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
8 #include "sandbox/src/sandbox_utils.h" | 8 #include "sandbox/src/sandbox_utils.h" |
9 #include "sandbox/src/win_utils.h" | 9 #include "sandbox/src/win_utils.h" |
10 | 10 |
11 namespace { | 11 namespace { |
12 #pragma pack(push, 1) | 12 #pragma pack(push, 1) |
13 | 13 |
14 const BYTE kMovEax = 0xB8; | 14 const BYTE kMovEax = 0xB8; |
15 const BYTE kMovEdx = 0xBA; | 15 const BYTE kMovEdx = 0xBA; |
| 16 const USHORT kMovEdxEsp = 0xD48B; |
16 const USHORT kCallPtrEdx = 0x12FF; | 17 const USHORT kCallPtrEdx = 0x12FF; |
17 const USHORT kCallEdx = 0xD2FF; | 18 const USHORT kCallEdx = 0xD2FF; |
| 19 const BYTE kCallEip = 0xE8; |
18 const BYTE kRet = 0xC2; | 20 const BYTE kRet = 0xC2; |
| 21 const BYTE kRet2 = 0xC3; |
19 const BYTE kNop = 0x90; | 22 const BYTE kNop = 0x90; |
20 const USHORT kJmpEdx = 0xE2FF; | 23 const USHORT kJmpEdx = 0xE2FF; |
21 const USHORT kXorEcx = 0xC933; | 24 const USHORT kXorEcx = 0xC933; |
22 const ULONG kLeaEdx = 0x0424548D; | 25 const ULONG kLeaEdx = 0x0424548D; |
23 const ULONG kCallFs1 = 0xC015FF64; | 26 const ULONG kCallFs1 = 0xC015FF64; |
24 const USHORT kCallFs2 = 0; | 27 const USHORT kCallFs2 = 0; |
25 const BYTE kCallFs3 = 0; | 28 const BYTE kCallFs3 = 0; |
26 const BYTE kAddEsp1 = 0x83; | 29 const BYTE kAddEsp1 = 0x83; |
27 const USHORT kAddEsp2 = 0x4C4; | 30 const USHORT kAddEsp2 = 0x4C4; |
28 const BYTE kJmp32 = 0xE9; | 31 const BYTE kJmp32 = 0xE9; |
| 32 const USHORT kSysenter = 0x340F; |
29 | 33 |
30 const int kMaxService = 1000; | 34 const int kMaxService = 1000; |
31 | 35 |
32 // Service code for 32 bit systems. | 36 // Service code for 32 bit systems. |
33 // NOTE: on win2003 "call dword ptr [edx]" is "call edx". | 37 // NOTE: on win2003 "call dword ptr [edx]" is "call edx". |
34 struct ServiceEntry { | 38 struct ServiceEntry { |
35 // this struct contains roughly the following code: | 39 // This struct contains roughly the following code: |
36 // 00 mov eax,25h | 40 // 00 mov eax,25h |
37 // 05 mov edx,offset SharedUserData!SystemCallStub (7ffe0300) | 41 // 05 mov edx,offset SharedUserData!SystemCallStub (7ffe0300) |
38 // 0a call dword ptr [edx] | 42 // 0a call dword ptr [edx] |
39 // 0c ret 2Ch | 43 // 0c ret 2Ch |
40 // 0f nop | 44 // 0f nop |
41 BYTE mov_eax; // = B8 | 45 BYTE mov_eax; // = B8 |
42 ULONG service_id; | 46 ULONG service_id; |
43 BYTE mov_edx; // = BA | 47 BYTE mov_edx; // = BA |
44 ULONG stub; | 48 ULONG stub; |
45 USHORT call_ptr_edx; // = FF 12 | 49 USHORT call_ptr_edx; // = FF 12 |
46 BYTE ret; // = C2 | 50 BYTE ret; // = C2 |
47 USHORT num_params; | 51 USHORT num_params; |
48 BYTE nop; | 52 BYTE nop; |
49 ULONG pad1; // Extend the structure to be the same size as the | 53 }; |
50 ULONG pad2; // 64 version (Wow64Entry) | 54 |
| 55 // Service code for 32 bit Windows 8. |
| 56 struct ServiceEntryW8 { |
| 57 // This struct contains the following code: |
| 58 // 00 b825000000 mov eax,25h |
| 59 // 05 e803000000 call eip+3 |
| 60 // 0a c22c00 ret 2Ch |
| 61 // 0d 8bd4 mov edx,esp |
| 62 // 0f 0f34 sysenter |
| 63 // 11 c3 ret |
| 64 // 12 8bff mov edi,edi |
| 65 BYTE mov_eax; // = B8 |
| 66 ULONG service_id; |
| 67 BYTE call_eip; // = E8 |
| 68 ULONG call_offset; |
| 69 BYTE ret_p; // = C2 |
| 70 USHORT num_params; |
| 71 USHORT mov_edx_esp; // = BD D4 |
| 72 USHORT sysenter; // = 0F 34 |
| 73 BYTE ret; // = C3 |
| 74 USHORT nop; |
51 }; | 75 }; |
52 | 76 |
53 // Service code for a 32 bit process running on a 64 bit os. | 77 // Service code for a 32 bit process running on a 64 bit os. |
54 struct Wow64Entry { | 78 struct Wow64Entry { |
55 // This struct may contain one of two versions of code: | 79 // This struct may contain one of two versions of code: |
56 // 1. For XP, Vista and 2K3: | 80 // 1. For XP, Vista and 2K3: |
57 // 00 b852000000 mov eax, 25h | 81 // 00 b825000000 mov eax, 25h |
58 // 05 33c9 xor ecx, ecx | 82 // 05 33c9 xor ecx, ecx |
59 // 07 8d542404 lea edx, [esp + 4] | 83 // 07 8d542404 lea edx, [esp + 4] |
60 // 0b 64ff15c0000000 call dword ptr fs:[0C0h] | 84 // 0b 64ff15c0000000 call dword ptr fs:[0C0h] |
61 // 12 c22c00 ret 2Ch | 85 // 12 c22c00 ret 2Ch |
62 // | 86 // |
63 // 2. For Windows 7: | 87 // 2. For Windows 7: |
64 // 00 b852000000 mov eax, 25h | 88 // 00 b825000000 mov eax, 25h |
65 // 05 33c9 xor ecx, ecx | 89 // 05 33c9 xor ecx, ecx |
66 // 07 8d542404 lea edx, [esp + 4] | 90 // 07 8d542404 lea edx, [esp + 4] |
67 // 0b 64ff15c0000000 call dword ptr fs:[0C0h] | 91 // 0b 64ff15c0000000 call dword ptr fs:[0C0h] |
68 // 12 83c404 add esp, 4 | 92 // 12 83c404 add esp, 4 |
69 // 15 c22c00 ret 2Ch | 93 // 15 c22c00 ret 2Ch |
70 // | 94 // |
71 // So we base the structure on the bigger one: | 95 // So we base the structure on the bigger one: |
72 BYTE mov_eax; // = B8 | 96 BYTE mov_eax; // = B8 |
73 ULONG service_id; | 97 ULONG service_id; |
74 USHORT xor_ecx; // = 33 C9 | 98 USHORT xor_ecx; // = 33 C9 |
75 ULONG lea_edx; // = 8D 54 24 04 | 99 ULONG lea_edx; // = 8D 54 24 04 |
76 ULONG call_fs1; // = 64 FF 15 C0 | 100 ULONG call_fs1; // = 64 FF 15 C0 |
77 USHORT call_fs2; // = 00 00 | 101 USHORT call_fs2; // = 00 00 |
78 BYTE call_fs3; // = 00 | 102 BYTE call_fs3; // = 00 |
79 BYTE add_esp1; // = 83 or ret | 103 BYTE add_esp1; // = 83 or ret |
80 USHORT add_esp2; // = C4 04 or num_params | 104 USHORT add_esp2; // = C4 04 or num_params |
81 BYTE ret; // = C2 | 105 BYTE ret; // = C2 |
82 USHORT num_params; | 106 USHORT num_params; |
83 }; | 107 }; |
84 | 108 |
| 109 // Service code for a 32 bit process running on 64 bit Windows 8. |
| 110 struct Wow64EntryW8 { |
| 111 // 00 b825000000 mov eax, 25h |
| 112 // 05 64ff15c0000000 call dword ptr fs:[0C0h] |
| 113 // 0b c22c00 ret 2Ch |
| 114 // 0f 90 nop |
| 115 BYTE mov_eax; // = B8 |
| 116 ULONG service_id; |
| 117 ULONG call_fs1; // = 64 FF 15 C0 |
| 118 USHORT call_fs2; // = 00 00 |
| 119 BYTE call_fs3; // = 00 |
| 120 BYTE ret; // = C2 |
| 121 USHORT num_params; |
| 122 BYTE nop; |
| 123 }; |
| 124 |
85 // Make sure that relaxed patching works as expected. | 125 // Make sure that relaxed patching works as expected. |
86 COMPILE_ASSERT(sizeof(ServiceEntry) == sizeof(Wow64Entry), wrong_service_len); | 126 const size_t kMinServiceSize = offsetof(ServiceEntry, ret); |
| 127 COMPILE_ASSERT(sizeof(ServiceEntryW8) >= kMinServiceSize, wrong_service_len); |
| 128 COMPILE_ASSERT(sizeof(Wow64Entry) >= kMinServiceSize, wrong_service_len); |
| 129 COMPILE_ASSERT(sizeof(Wow64EntryW8) >= kMinServiceSize, wrong_service_len); |
87 | 130 |
88 struct ServiceFullThunk { | 131 struct ServiceFullThunk { |
89 union { | 132 union { |
90 ServiceEntry original; | 133 ServiceEntry original; |
| 134 ServiceEntryW8 original_w8; |
91 Wow64Entry wow_64; | 135 Wow64Entry wow_64; |
| 136 Wow64EntryW8 wow_64_w8; |
92 }; | 137 }; |
93 int internal_thunk; // Dummy member to the beginning of the internal thunk. | 138 int internal_thunk; // Dummy member to the beginning of the internal thunk. |
94 }; | 139 }; |
95 | 140 |
96 #pragma pack(pop) | 141 #pragma pack(pop) |
97 | 142 |
98 }; // namespace | 143 }; // namespace |
99 | 144 |
100 namespace sandbox { | 145 namespace sandbox { |
101 | 146 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 remote_thunk); | 250 remote_thunk); |
206 | 251 |
207 // patch the original code | 252 // patch the original code |
208 memcpy(&intercepted_code, &full_local_thunk->original, | 253 memcpy(&intercepted_code, &full_local_thunk->original, |
209 sizeof(intercepted_code)); | 254 sizeof(intercepted_code)); |
210 intercepted_code.mov_eax = kMovEax; | 255 intercepted_code.mov_eax = kMovEax; |
211 intercepted_code.service_id = full_local_thunk->original.service_id; | 256 intercepted_code.service_id = full_local_thunk->original.service_id; |
212 intercepted_code.mov_edx = kMovEdx; | 257 intercepted_code.mov_edx = kMovEdx; |
213 intercepted_code.stub = bit_cast<ULONG>(&full_remote_thunk->internal_thunk); | 258 intercepted_code.stub = bit_cast<ULONG>(&full_remote_thunk->internal_thunk); |
214 intercepted_code.call_ptr_edx = kJmpEdx; | 259 intercepted_code.call_ptr_edx = kJmpEdx; |
215 if (!win2k_) { | 260 bytes_to_write = kMinServiceSize; |
216 intercepted_code.ret = kRet; | |
217 intercepted_code.num_params = full_local_thunk->original.num_params; | |
218 intercepted_code.nop = kNop; | |
219 } else { | |
220 bytes_to_write = offsetof(ServiceEntry, ret); | |
221 } | |
222 | 261 |
223 if (relative_jump_) { | 262 if (relative_jump_) { |
224 intercepted_code.mov_eax = kJmp32; | 263 intercepted_code.mov_eax = kJmp32; |
225 intercepted_code.service_id = relative_jump_; | 264 intercepted_code.service_id = relative_jump_; |
226 bytes_to_write = offsetof(ServiceEntry, mov_edx); | 265 bytes_to_write = offsetof(ServiceEntry, mov_edx); |
227 } | 266 } |
228 | 267 |
229 // setup the thunk | 268 // setup the thunk |
230 SetInternalThunk(&full_local_thunk->internal_thunk, GetInternalThunkSize(), | 269 SetInternalThunk(&full_local_thunk->internal_thunk, GetInternalThunkSize(), |
231 remote_thunk, interceptor_); | 270 remote_thunk, interceptor_); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 kAddEsp2 == function_code.add_esp2 && | 350 kAddEsp2 == function_code.add_esp2 && |
312 kRet == function_code.ret) || kRet == function_code.add_esp1) { | 351 kRet == function_code.ret) || kRet == function_code.add_esp1) { |
313 // Save the verified code | 352 // Save the verified code |
314 memcpy(local_thunk, &function_code, sizeof(function_code)); | 353 memcpy(local_thunk, &function_code, sizeof(function_code)); |
315 return true; | 354 return true; |
316 } | 355 } |
317 | 356 |
318 return false; | 357 return false; |
319 } | 358 } |
320 | 359 |
| 360 bool Wow64W8ResolverThunk::IsFunctionAService(void* local_thunk) const { |
| 361 Wow64EntryW8 function_code; |
| 362 SIZE_T read; |
| 363 if (!::ReadProcessMemory(process_, target_, &function_code, |
| 364 sizeof(function_code), &read)) |
| 365 return false; |
| 366 |
| 367 if (sizeof(function_code) != read) |
| 368 return false; |
| 369 |
| 370 if (kMovEax != function_code.mov_eax || kCallFs1 != function_code.call_fs1 || |
| 371 kCallFs2 != function_code.call_fs2 || |
| 372 kCallFs3 != function_code.call_fs3 || kRet != function_code.ret) { |
| 373 return false; |
| 374 } |
| 375 |
| 376 // Save the verified code |
| 377 memcpy(local_thunk, &function_code, sizeof(function_code)); |
| 378 return true; |
| 379 } |
| 380 |
321 bool Win2kResolverThunk::IsFunctionAService(void* local_thunk) const { | 381 bool Win2kResolverThunk::IsFunctionAService(void* local_thunk) const { |
322 ServiceEntry function_code; | 382 ServiceEntry function_code; |
323 SIZE_T read; | 383 SIZE_T read; |
324 if (!::ReadProcessMemory(process_, target_, &function_code, | 384 if (!::ReadProcessMemory(process_, target_, &function_code, |
325 sizeof(function_code), &read)) | 385 sizeof(function_code), &read)) |
326 return false; | 386 return false; |
327 | 387 |
328 if (sizeof(function_code) != read) | 388 if (sizeof(function_code) != read) |
329 return false; | 389 return false; |
330 | 390 |
331 if (kMovEax != function_code.mov_eax || | 391 if (kMovEax != function_code.mov_eax || |
332 function_code.service_id > kMaxService) | 392 function_code.service_id > kMaxService) |
333 return false; | 393 return false; |
334 | 394 |
335 // Save the verified code | 395 // Save the verified code |
336 memcpy(local_thunk, &function_code, sizeof(function_code)); | 396 memcpy(local_thunk, &function_code, sizeof(function_code)); |
337 | 397 |
338 return true; | 398 return true; |
339 } | 399 } |
340 | 400 |
| 401 bool Win8ResolverThunk::IsFunctionAService(void* local_thunk) const { |
| 402 ServiceEntryW8 function_code; |
| 403 SIZE_T read; |
| 404 if (!::ReadProcessMemory(process_, target_, &function_code, |
| 405 sizeof(function_code), &read)) |
| 406 return false; |
| 407 |
| 408 if (sizeof(function_code) != read) |
| 409 return false; |
| 410 |
| 411 if (kMovEax != function_code.mov_eax || kCallEip != function_code.call_eip || |
| 412 function_code.call_offset != 3 || kRet != function_code.ret_p || |
| 413 kMovEdxEsp != function_code.mov_edx_esp || |
| 414 kSysenter != function_code.sysenter || kRet2 != function_code.ret) { |
| 415 return false; |
| 416 } |
| 417 |
| 418 // Save the verified code |
| 419 memcpy(local_thunk, &function_code, sizeof(function_code)); |
| 420 |
| 421 return true; |
| 422 } |
| 423 |
341 } // namespace sandbox | 424 } // namespace sandbox |
OLD | NEW |