blob: afc94413c053f65b5bae2b508c13c4d8630fbae3 [file] [log] [blame]
[email protected]3b63f8f42011-03-28 01:54:151// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]ddcd5e32010-01-29 00:24:262// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]ea38baf52010-02-01 23:42:585#include "sandbox/src/service_resolver.h"
[email protected]ddcd5e32010-01-29 00:24:266
[email protected]ea38baf52010-02-01 23:42:587#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:158#include "base/memory/scoped_ptr.h"
[email protected]0483cf182010-02-11 22:20:319#include "sandbox/src/win_utils.h"
[email protected]ddcd5e32010-01-29 00:24:2610
11namespace {
12#pragma pack(push, 1)
13
[email protected]ddcd5e32010-01-29 00:24:2614const ULONG kMmovR10EcxMovEax = 0xB8D18B4C;
15const USHORT kSyscall = 0x050F;
16const BYTE kRetNp = 0xC3;
[email protected]ddcd5e32010-01-29 00:24:2617
18// Service code for 64 bit systems.
19struct ServiceEntry {
[email protected]ea38baf52010-02-01 23:42:5820 // 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]ddcd5e32010-01-29 00:24:2627
[email protected]ea38baf52010-02-01 23:42:5828 ULONG mov_r10_rcx_mov_eax; // = 4C 8B D1 B8
[email protected]ddcd5e32010-01-29 00:24:2629 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]ea38baf52010-02-01 23:42:5837// We don't have an internal thunk for x64.
[email protected]ddcd5e32010-01-29 00:24:2638struct ServiceFullThunk {
[email protected]ddcd5e32010-01-29 00:24:2639 ServiceEntry original;
[email protected]ddcd5e32010-01-29 00:24:2640};
41
42#pragma pack(pop)
43
[email protected]ddcd5e32010-01-29 00:24:2644}; // namespace
45
46namespace sandbox {
47
[email protected]ea38baf52010-02-01 23:42:5848NTSTATUS 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]ddcd5e32010-01-29 00:24:2656 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]ea38baf52010-02-01 23:42:5878size_t ServiceResolverThunk::GetThunkSize() const {
[email protected]ddcd5e32010-01-29 00:24:2679 return sizeof(ServiceFullThunk);
80}
81
[email protected]ea38baf52010-02-01 23:42:5882bool ServiceResolverThunk::IsFunctionAService(void* local_thunk) const {
[email protected]ddcd5e32010-01-29 00:24:2683 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]ea38baf52010-02-01 23:42:5892 if (kMmovR10EcxMovEax != function_code.mov_r10_rcx_mov_eax ||
[email protected]ddcd5e32010-01-29 00:24:2693 kSyscall != function_code.syscall || kRetNp != function_code.ret)
94 return false;
95
[email protected]ea38baf52010-02-01 23:42:5896 // Save the verified code.
[email protected]ddcd5e32010-01-29 00:24:2697 memcpy(local_thunk, &function_code, sizeof(function_code));
98
99 return true;
100}
101
[email protected]ea38baf52010-02-01 23:42:58102NTSTATUS ServiceResolverThunk::PerformPatch(void* local_thunk,
103 void* remote_thunk) {
[email protected]ddcd5e32010-01-29 00:24:26104 ServiceFullThunk* full_local_thunk = reinterpret_cast<ServiceFullThunk*>(
105 local_thunk);
106 ServiceFullThunk* full_remote_thunk = reinterpret_cast<ServiceFullThunk*>(
[email protected]ea38baf52010-02-01 23:42:58107 remote_thunk);
[email protected]ddcd5e32010-01-29 00:24:26108
109 // Patch the original code.
[email protected]ea38baf52010-02-01 23:42:58110 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]ddcd5e32010-01-29 00:24:26115
[email protected]ea38baf52010-02-01 23:42:58116 // Copy the local thunk buffer to the child.
[email protected]ddcd5e32010-01-29 00:24:26117 SIZE_T actual;
[email protected]ddcd5e32010-01-29 00:24:26118 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]ea38baf52010-02-01 23:42:58125 // 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]ddcd5e32010-01-29 00:24:26133 sizeof(local_service)))
[email protected]ea38baf52010-02-01 23:42:58134 return STATUS_UNSUCCESSFUL;
135 }
[email protected]ddcd5e32010-01-29 00:24:26136
137 return STATUS_SUCCESS;
138}
139
[email protected]ea38baf52010-02-01 23:42:58140bool Wow64ResolverThunk::IsFunctionAService(void* local_thunk) const {
141 NOTREACHED();
142 return false;
143}
144
145bool Win2kResolverThunk::IsFunctionAService(void* local_thunk) const {
146 NOTREACHED();
147 return false;
148}
149
[email protected]ddcd5e32010-01-29 00:24:26150} // namespace sandbox