[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame^] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 5 | #include "sandbox/src/service_resolver.h" |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 6 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 7 | #include "base/logging.h" |
[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame^] | 8 | #include "base/memory/scoped_ptr.h" |
[email protected] | 0483cf18 | 2010-02-11 22:20:31 | [diff] [blame] | 9 | #include "sandbox/src/win_utils.h" |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 10 | |
| 11 | namespace { |
| 12 | #pragma pack(push, 1) |
| 13 | |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 14 | const ULONG kMmovR10EcxMovEax = 0xB8D18B4C; |
| 15 | const USHORT kSyscall = 0x050F; |
| 16 | const BYTE kRetNp = 0xC3; |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 17 | |
| 18 | // Service code for 64 bit systems. |
| 19 | struct ServiceEntry { |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 20 | // This struct contains roughly the following code: |
| 21 | // 00 mov r10,rcx |
| 22 | // 03 mov eax,52h |
| 23 | // 08 syscall |
| 24 | // 0a ret |
| 25 | // 0b xchg ax,ax |
| 26 | // 0e xchg ax,ax |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 27 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 28 | ULONG mov_r10_rcx_mov_eax; // = 4C 8B D1 B8 |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 29 | ULONG service_id; |
| 30 | USHORT syscall; // = 0F 05 |
| 31 | BYTE ret; // = C3 |
| 32 | BYTE pad; // = 66 |
| 33 | USHORT xchg_ax_ax1; // = 66 90 |
| 34 | USHORT xchg_ax_ax2; // = 66 90 |
| 35 | }; |
| 36 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 37 | // We don't have an internal thunk for x64. |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 38 | struct ServiceFullThunk { |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 39 | ServiceEntry original; |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 40 | }; |
| 41 | |
| 42 | #pragma pack(pop) |
| 43 | |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 44 | }; // namespace |
| 45 | |
| 46 | namespace sandbox { |
| 47 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 48 | NTSTATUS ServiceResolverThunk::Setup(const void* target_module, |
| 49 | const void* interceptor_module, |
| 50 | const char* target_name, |
| 51 | const char* interceptor_name, |
| 52 | const void* interceptor_entry_point, |
| 53 | void* thunk_storage, |
| 54 | size_t storage_bytes, |
| 55 | size_t* storage_used) { |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 56 | NTSTATUS ret = Init(target_module, interceptor_module, target_name, |
| 57 | interceptor_name, interceptor_entry_point, |
| 58 | thunk_storage, storage_bytes); |
| 59 | if (!NT_SUCCESS(ret)) |
| 60 | return ret; |
| 61 | |
| 62 | size_t thunk_bytes = GetThunkSize(); |
| 63 | scoped_array<char> thunk_buffer(new char[thunk_bytes]); |
| 64 | ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>( |
| 65 | thunk_buffer.get()); |
| 66 | |
| 67 | if (!IsFunctionAService(&thunk->original)) |
| 68 | return STATUS_UNSUCCESSFUL; |
| 69 | |
| 70 | ret = PerformPatch(thunk, thunk_storage); |
| 71 | |
| 72 | if (NULL != storage_used) |
| 73 | *storage_used = thunk_bytes; |
| 74 | |
| 75 | return ret; |
| 76 | } |
| 77 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 78 | size_t ServiceResolverThunk::GetThunkSize() const { |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 79 | return sizeof(ServiceFullThunk); |
| 80 | } |
| 81 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 82 | bool ServiceResolverThunk::IsFunctionAService(void* local_thunk) const { |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 83 | ServiceEntry function_code; |
| 84 | SIZE_T read; |
| 85 | if (!::ReadProcessMemory(process_, target_, &function_code, |
| 86 | sizeof(function_code), &read)) |
| 87 | return false; |
| 88 | |
| 89 | if (sizeof(function_code) != read) |
| 90 | return false; |
| 91 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 92 | if (kMmovR10EcxMovEax != function_code.mov_r10_rcx_mov_eax || |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 93 | kSyscall != function_code.syscall || kRetNp != function_code.ret) |
| 94 | return false; |
| 95 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 96 | // Save the verified code. |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 97 | memcpy(local_thunk, &function_code, sizeof(function_code)); |
| 98 | |
| 99 | return true; |
| 100 | } |
| 101 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 102 | NTSTATUS ServiceResolverThunk::PerformPatch(void* local_thunk, |
| 103 | void* remote_thunk) { |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 104 | ServiceFullThunk* full_local_thunk = reinterpret_cast<ServiceFullThunk*>( |
| 105 | local_thunk); |
| 106 | ServiceFullThunk* full_remote_thunk = reinterpret_cast<ServiceFullThunk*>( |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 107 | remote_thunk); |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 108 | |
| 109 | // Patch the original code. |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 110 | ServiceEntry local_service; |
| 111 | DCHECK_GE(GetInternalThunkSize(), sizeof(local_service)); |
| 112 | if (!SetInternalThunk(&local_service, sizeof(local_service), NULL, |
| 113 | interceptor_)) |
| 114 | return STATUS_UNSUCCESSFUL; |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 115 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 116 | // Copy the local thunk buffer to the child. |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 117 | SIZE_T actual; |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 118 | if (!::WriteProcessMemory(process_, remote_thunk, local_thunk, |
| 119 | sizeof(ServiceFullThunk), &actual)) |
| 120 | return STATUS_UNSUCCESSFUL; |
| 121 | |
| 122 | if (sizeof(ServiceFullThunk) != actual) |
| 123 | return STATUS_UNSUCCESSFUL; |
| 124 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 125 | // And now change the function to intercept, on the child. |
| 126 | if (NULL != ntdll_base_) { |
| 127 | // Running a unit test. |
| 128 | if (!::WriteProcessMemory(process_, target_, &local_service, |
| 129 | sizeof(local_service), &actual)) |
| 130 | return STATUS_UNSUCCESSFUL; |
| 131 | } else { |
| 132 | if (!WriteProtectedChildMemory(process_, target_, &local_service, |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 133 | sizeof(local_service))) |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 134 | return STATUS_UNSUCCESSFUL; |
| 135 | } |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 136 | |
| 137 | return STATUS_SUCCESS; |
| 138 | } |
| 139 | |
[email protected] | ea38baf5 | 2010-02-01 23:42:58 | [diff] [blame] | 140 | bool Wow64ResolverThunk::IsFunctionAService(void* local_thunk) const { |
| 141 | NOTREACHED(); |
| 142 | return false; |
| 143 | } |
| 144 | |
| 145 | bool Win2kResolverThunk::IsFunctionAService(void* local_thunk) const { |
| 146 | NOTREACHED(); |
| 147 | return false; |
| 148 | } |
| 149 | |
[email protected] | ddcd5e3 | 2010-01-29 00:24:26 | [diff] [blame] | 150 | } // namespace sandbox |