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

Side by Side Diff: sandbox/win/wow_helper/service64_resolver.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/wow_helper/service64_resolver.h ('k') | sandbox/win/wow_helper/target_code.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 "sandbox/win/wow_helper/service64_resolver.h"
6
7 #include <limits.h>
8 #include <stddef.h>
9
10 #include "base/bit_cast.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "sandbox/win/wow_helper/target_code.h"
13
14 namespace {
15 #pragma pack(push, 1)
16
17 const BYTE kMovEax = 0xB8;
18 const BYTE kMovEdx = 0xBA;
19 const USHORT kCallPtrEdx = 0x12FF;
20 const BYTE kRet = 0xC2;
21 const BYTE kNop = 0x90;
22 const USHORT kJmpEdx = 0xE2FF;
23 const USHORT kXorEcx = 0xC933;
24 const ULONG kLeaEdx = 0x0424548D;
25 const ULONG kCallFs1 = 0xC015FF64;
26 const ULONG kCallFs2Ret = 0xC2000000;
27 const BYTE kPopEdx = 0x5A;
28 const BYTE kPushEdx = 0x52;
29 const BYTE kPush32 = 0x68;
30
31 const ULONG kMmovR10EcxMovEax = 0xB8D18B4C;
32 const USHORT kSyscall = 0x050F;
33 const BYTE kRetNp = 0xC3;
34 const BYTE kPad = 0x66;
35 const USHORT kNop16 = 0x9066;
36 const BYTE kRelJmp = 0xE9;
37
38 const ULONG kXorRaxMovEax = 0xB8C03148;
39 const ULONG kSaveRcx = 0x10488948;
40 const ULONG kMovRcxRaxJmp = 0xE9C88B48;
41
42 // Service code for 64 bit systems.
43 struct ServiceEntry {
44 // this struct contains roughly the following code:
45 // mov r10,rcx
46 // mov eax,52h
47 // syscall
48 // ret
49 // xchg ax,ax
50 // xchg ax,ax
51
52 ULONG mov_r10_ecx_mov_eax; // = 4C 8B D1 B8
53 ULONG service_id;
54 USHORT syscall; // = 0F 05
55 BYTE ret; // = C3
56 BYTE pad; // = 66
57 USHORT xchg_ax_ax1; // = 66 90
58 USHORT xchg_ax_ax2; // = 66 90
59 };
60
61 struct Redirected {
62 // this struct contains roughly the following code:
63 // jmp relative_32
64 // xchg ax,ax // 3 byte nop
65
66 Redirected() {
67 jmp = kRelJmp;
68 relative = 0;
69 pad = kPad;
70 xchg_ax_ax = kNop16;
71 };
72 BYTE jmp; // = E9
73 ULONG relative;
74 BYTE pad; // = 66
75 USHORT xchg_ax_ax; // = 66 90
76 };
77
78 struct InternalThunk {
79 // this struct contains roughly the following code:
80 // xor rax,rax
81 // mov eax, 0x00080000 // Thunk storage.
82 // mov [rax]PatchInfo.service, rcx // Save first argument.
83 // mov rcx, rax
84 // jmp relative_to_interceptor
85
86 InternalThunk() {
87 xor_rax_mov_eax = kXorRaxMovEax;
88 patch_info = 0;
89 save_rcx = kSaveRcx;
90 mov_rcx_rax_jmp = kMovRcxRaxJmp;
91 relative = 0;
92 };
93 ULONG xor_rax_mov_eax; // = 48 31 C0 B8
94 ULONG patch_info;
95 ULONG save_rcx; // = 48 89 48 10
96 ULONG mov_rcx_rax_jmp; // = 48 8b c8 e9
97 ULONG relative;
98 };
99
100 struct ServiceFullThunk {
101 sandbox::PatchInfo patch_info;
102 ServiceEntry original;
103 InternalThunk internal_thunk;
104 };
105
106 #pragma pack(pop)
107
108 // Simple utility function to write to a buffer on the child, if the memery has
109 // write protection attributes.
110 // Arguments:
111 // child_process (in): process to write to.
112 // address (out): memory position on the child to write to.
113 // buffer (in): local buffer with the data to write .
114 // length (in): number of bytes to write.
115 // Returns true on success.
116 bool WriteProtectedChildMemory(HANDLE child_process,
117 void* address,
118 const void* buffer,
119 size_t length) {
120 // first, remove the protections
121 DWORD old_protection;
122 if (!::VirtualProtectEx(child_process, address, length,
123 PAGE_WRITECOPY, &old_protection))
124 return false;
125
126 SIZE_T written;
127 bool ok = ::WriteProcessMemory(child_process, address, buffer, length,
128 &written) && (length == written);
129
130 // always attempt to restore the original protection
131 if (!::VirtualProtectEx(child_process, address, length,
132 old_protection, &old_protection))
133 return false;
134
135 return ok;
136 }
137
138 // Get pointers to the functions that we need from ntdll.dll.
139 NTSTATUS ResolveNtdll(sandbox::PatchInfo* patch_info) {
140 wchar_t* ntdll_name = L"ntdll.dll";
141 HMODULE ntdll = ::GetModuleHandle(ntdll_name);
142 if (!ntdll)
143 return STATUS_PROCEDURE_NOT_FOUND;
144
145 void* signal = ::GetProcAddress(ntdll, "NtSignalAndWaitForSingleObject");
146 if (!signal)
147 return STATUS_PROCEDURE_NOT_FOUND;
148
149 patch_info->signal_and_wait =
150 reinterpret_cast<NtSignalAndWaitForSingleObjectFunction>(signal);
151
152 return STATUS_SUCCESS;
153 }
154
155 }; // namespace
156
157 namespace sandbox {
158
159 NTSTATUS ResolverThunk::Init(const void* target_module,
160 const void* interceptor_module,
161 const char* target_name,
162 const char* interceptor_name,
163 const void* interceptor_entry_point,
164 void* thunk_storage,
165 size_t storage_bytes) {
166 if (NULL == thunk_storage || 0 == storage_bytes ||
167 NULL == target_module || NULL == target_name)
168 return STATUS_INVALID_PARAMETER;
169
170 if (storage_bytes < GetThunkSize())
171 return STATUS_BUFFER_TOO_SMALL;
172
173 NTSTATUS ret = STATUS_SUCCESS;
174 if (NULL == interceptor_entry_point) {
175 ret = ResolveInterceptor(interceptor_module, interceptor_name,
176 &interceptor_entry_point);
177 if (!NT_SUCCESS(ret))
178 return ret;
179 }
180
181 ret = ResolveTarget(target_module, target_name, &target_);
182 if (!NT_SUCCESS(ret))
183 return ret;
184
185 interceptor_ = interceptor_entry_point;
186
187 return ret;
188 }
189
190 NTSTATUS ResolverThunk::ResolveInterceptor(const void* interceptor_module,
191 const char* interceptor_name,
192 const void** address) {
193 return STATUS_NOT_IMPLEMENTED;
194 }
195
196 NTSTATUS ResolverThunk::ResolveTarget(const void* module,
197 const char* function_name,
198 void** address) {
199 return STATUS_NOT_IMPLEMENTED;
200 }
201
202 NTSTATUS Service64ResolverThunk::Setup(const void* target_module,
203 const void* interceptor_module,
204 const char* target_name,
205 const char* interceptor_name,
206 const void* interceptor_entry_point,
207 void* thunk_storage,
208 size_t storage_bytes,
209 size_t* storage_used) {
210 NTSTATUS ret = Init(target_module, interceptor_module, target_name,
211 interceptor_name, interceptor_entry_point,
212 thunk_storage, storage_bytes);
213 if (!NT_SUCCESS(ret))
214 return ret;
215
216 size_t thunk_bytes = GetThunkSize();
217 scoped_ptr<char[]> thunk_buffer(new char[thunk_bytes]);
218 ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(
219 thunk_buffer.get());
220
221 if (!IsFunctionAService(&thunk->original))
222 return STATUS_UNSUCCESSFUL;
223
224 ret = PerformPatch(thunk, thunk_storage);
225
226 if (NULL != storage_used)
227 *storage_used = thunk_bytes;
228
229 return ret;
230 }
231
232 NTSTATUS Service64ResolverThunk::ResolveInterceptor(
233 const void* interceptor_module,
234 const char* interceptor_name,
235 const void** address) {
236 // After all, we are using a locally mapped version of the exe, so the
237 // action is the same as for a target function.
238 return ResolveTarget(interceptor_module, interceptor_name,
239 const_cast<void**>(address));
240 }
241
242 // In this case all the work is done from the parent, so resolve is
243 // just a simple GetProcAddress.
244 NTSTATUS Service64ResolverThunk::ResolveTarget(const void* module,
245 const char* function_name,
246 void** address) {
247 if (NULL == module)
248 return STATUS_UNSUCCESSFUL;
249
250 *address = ::GetProcAddress(bit_cast<HMODULE>(module), function_name);
251
252 if (NULL == *address)
253 return STATUS_UNSUCCESSFUL;
254
255 return STATUS_SUCCESS;
256 }
257
258 size_t Service64ResolverThunk::GetThunkSize() const {
259 return sizeof(ServiceFullThunk);
260 }
261
262 bool Service64ResolverThunk::IsFunctionAService(void* local_thunk) const {
263 ServiceEntry function_code;
264 SIZE_T read;
265 if (!::ReadProcessMemory(process_, target_, &function_code,
266 sizeof(function_code), &read))
267 return false;
268
269 if (sizeof(function_code) != read)
270 return false;
271
272 if (kMmovR10EcxMovEax != function_code.mov_r10_ecx_mov_eax ||
273 kSyscall != function_code.syscall || kRetNp != function_code.ret)
274 return false;
275
276 // Save the verified code
277 memcpy(local_thunk, &function_code, sizeof(function_code));
278
279 return true;
280 }
281
282 NTSTATUS Service64ResolverThunk::PerformPatch(void* local_thunk,
283 void* remote_thunk) {
284 ServiceFullThunk* full_local_thunk = reinterpret_cast<ServiceFullThunk*>(
285 local_thunk);
286 ServiceFullThunk* full_remote_thunk = reinterpret_cast<ServiceFullThunk*>(
287 remote_thunk);
288
289 // If the source or target are above 4GB we cannot do this relative jump.
290 if (reinterpret_cast<ULONG_PTR>(full_remote_thunk) >
291 static_cast<ULONG_PTR>(ULONG_MAX))
292 return STATUS_CONFLICTING_ADDRESSES;
293
294 if (reinterpret_cast<ULONG_PTR>(target_) > static_cast<ULONG_PTR>(ULONG_MAX))
295 return STATUS_CONFLICTING_ADDRESSES;
296
297 // Patch the original code.
298 Redirected local_service;
299 Redirected* remote_service = reinterpret_cast<Redirected*>(target_);
300 ULONG_PTR diff = reinterpret_cast<BYTE*>(&full_remote_thunk->internal_thunk) -
301 &remote_service->pad;
302 local_service.relative = static_cast<ULONG>(diff);
303
304 // Setup the PatchInfo structure.
305 SIZE_T actual;
306 if (!::ReadProcessMemory(process_, remote_thunk, local_thunk,
307 sizeof(PatchInfo), &actual))
308 return STATUS_UNSUCCESSFUL;
309 if (sizeof(PatchInfo) != actual)
310 return STATUS_UNSUCCESSFUL;
311
312 full_local_thunk->patch_info.orig_MapViewOfSection = reinterpret_cast<
313 NtMapViewOfSectionFunction>(&full_remote_thunk->original);
314 full_local_thunk->patch_info.patch_location = target_;
315 NTSTATUS ret = ResolveNtdll(&full_local_thunk->patch_info);
316 if (!NT_SUCCESS(ret))
317 return ret;
318
319 // Setup the thunk. The jump out is performed from right after the end of the
320 // thunk (full_remote_thunk + 1).
321 InternalThunk my_thunk;
322 ULONG_PTR patch_info = reinterpret_cast<ULONG_PTR>(remote_thunk);
323 my_thunk.patch_info = static_cast<ULONG>(patch_info);
324 diff = reinterpret_cast<const BYTE*>(interceptor_) -
325 reinterpret_cast<BYTE*>(full_remote_thunk + 1);
326 my_thunk.relative = static_cast<ULONG>(diff);
327
328 memcpy(&full_local_thunk->internal_thunk, &my_thunk, sizeof(my_thunk));
329
330 // copy the local thunk buffer to the child
331 if (!::WriteProcessMemory(process_, remote_thunk, local_thunk,
332 sizeof(ServiceFullThunk), &actual))
333 return STATUS_UNSUCCESSFUL;
334
335 if (sizeof(ServiceFullThunk) != actual)
336 return STATUS_UNSUCCESSFUL;
337
338 // and now change the function to intercept, on the child
339 if (!::WriteProtectedChildMemory(process_, target_, &local_service,
340 sizeof(local_service)))
341 return STATUS_UNSUCCESSFUL;
342
343 return STATUS_SUCCESS;
344 }
345
346 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/win/wow_helper/service64_resolver.h ('k') | sandbox/win/wow_helper/target_code.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698