OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 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 | 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/wow64.h" | 5 #include "sandbox/src/wow64.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/scoped_ptr.h" | 10 #include "base/scoped_ptr.h" |
11 #include "sandbox/src/sandbox.h" | 11 #include "base/win/windows_version.h" |
12 #include "sandbox/src/target_process.h" | 12 #include "sandbox/src/target_process.h" |
13 | 13 |
14 namespace { | 14 namespace { |
15 | 15 |
16 // Holds the information needed for the interception of NtMapViewOfSection on | 16 // Holds the information needed for the interception of NtMapViewOfSection on |
17 // 64 bits. | 17 // 64 bits. |
18 // Warning: do not modify this definition without changing also the code on the | 18 // Warning: do not modify this definition without changing also the code on the |
19 // 64 bit helper process. | 19 // 64 bit helper process. |
20 struct PatchInfo32 { | 20 struct PatchInfo32 { |
21 HANDLE dll_load; // Event to signal the broker. | 21 HANDLE dll_load; // Event to signal the broker. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 namespace sandbox { | 73 namespace sandbox { |
74 | 74 |
75 Wow64::~Wow64() { | 75 Wow64::~Wow64() { |
76 if (dll_load_) | 76 if (dll_load_) |
77 ::CloseHandle(dll_load_); | 77 ::CloseHandle(dll_load_); |
78 | 78 |
79 if (continue_load_) | 79 if (continue_load_) |
80 ::CloseHandle(continue_load_); | 80 ::CloseHandle(continue_load_); |
81 } | 81 } |
82 | 82 |
83 bool Wow64::IsWow64() { | |
84 if (init_) | |
85 return is_wow64_; | |
86 | |
87 is_wow64_ = false; | |
88 | |
89 HMODULE kernel32 = ::GetModuleHandle(sandbox::kKerneldllName); | |
90 if (!kernel32) | |
91 return false; | |
92 | |
93 IsWow64ProcessFunction is_wow64_process = reinterpret_cast< | |
94 IsWow64ProcessFunction>(::GetProcAddress(kernel32, "IsWow64Process")); | |
95 | |
96 init_ = true; | |
97 if (!is_wow64_process) | |
98 return false; | |
99 | |
100 BOOL wow64; | |
101 if (!is_wow64_process(::GetCurrentProcess(), &wow64)) | |
102 return false; | |
103 | |
104 if (wow64) | |
105 is_wow64_ = true; | |
106 | |
107 return is_wow64_; | |
108 } | |
109 | |
110 // The basic idea is to allocate one page of memory on the child, and initialize | 83 // The basic idea is to allocate one page of memory on the child, and initialize |
111 // the first part of it with our version of PatchInfo32. Then launch the helper | 84 // the first part of it with our version of PatchInfo32. Then launch the helper |
112 // process passing it that address on the child. The helper process will patch | 85 // process passing it that address on the child. The helper process will patch |
113 // the 64 bit version of NtMapViewOfFile, and the interception will signal the | 86 // the 64 bit version of NtMapViewOfFile, and the interception will signal the |
114 // first event on the buffer. We'll be waiting on that event and after the 32 | 87 // first event on the buffer. We'll be waiting on that event and after the 32 |
115 // bit version of ntdll is loaded, we'll remove the interception and return to | 88 // bit version of ntdll is loaded, we'll remove the interception and return to |
116 // our caller. | 89 // our caller. |
117 bool Wow64::WaitForNtdll(DWORD timeout_ms) { | 90 bool Wow64::WaitForNtdll() { |
118 DCHECK(!init_); | 91 if (base::win::GetWOW64Status() != base::win::WOW64_ENABLED) |
119 if (!IsWow64()) | |
120 return true; | 92 return true; |
121 | 93 |
122 const size_t page_size = 4096; | 94 const size_t page_size = 4096; |
123 | 95 |
124 // Create some default manual reset un-named events, not signaled. | 96 // Create some default manual reset un-named events, not signaled. |
125 dll_load_ = ::CreateEvent(NULL, TRUE, FALSE, NULL); | 97 dll_load_ = ::CreateEvent(NULL, TRUE, FALSE, NULL); |
126 continue_load_ = ::CreateEvent(NULL, TRUE, FALSE, NULL); | 98 continue_load_ = ::CreateEvent(NULL, TRUE, FALSE, NULL); |
127 HANDLE current_process = ::GetCurrentProcess(); | 99 HANDLE current_process = ::GetCurrentProcess(); |
128 HANDLE remote_load, remote_continue; | 100 HANDLE remote_load, remote_continue; |
129 DWORD access = EVENT_MODIFY_STATE | SYNCHRONIZE; | 101 DWORD access = EVENT_MODIFY_STATE | SYNCHRONIZE; |
(...skipping 14 matching lines...) Expand all Loading... |
144 PatchInfo32 local_patch_info = {0}; | 116 PatchInfo32 local_patch_info = {0}; |
145 local_patch_info.dll_load = remote_load; | 117 local_patch_info.dll_load = remote_load; |
146 local_patch_info.continue_load = remote_continue; | 118 local_patch_info.continue_load = remote_continue; |
147 SIZE_T written; | 119 SIZE_T written; |
148 if (!::WriteProcessMemory(child_->Process(), patch_info, &local_patch_info, | 120 if (!::WriteProcessMemory(child_->Process(), patch_info, &local_patch_info, |
149 offsetof(PatchInfo32, section), &written)) | 121 offsetof(PatchInfo32, section), &written)) |
150 return false; | 122 return false; |
151 if (offsetof(PatchInfo32, section) != written) | 123 if (offsetof(PatchInfo32, section) != written) |
152 return false; | 124 return false; |
153 | 125 |
154 if (!RunWowHelper(buffer, timeout_ms)) | 126 if (!RunWowHelper(buffer)) |
155 return false; | 127 return false; |
156 | 128 |
157 // The child is intercepted on 64 bit, go on and wait for our event. | 129 // The child is intercepted on 64 bit, go on and wait for our event. |
158 if (!DllMapped(timeout_ms)) | 130 if (!DllMapped()) |
159 return false; | 131 return false; |
160 | 132 |
161 // The 32 bit version is available, cleanup the child. | 133 // The 32 bit version is available, cleanup the child. |
162 return Restore64Code(child_->Process(), patch_info); | 134 return Restore64Code(child_->Process(), patch_info); |
163 } | 135 } |
164 | 136 |
165 bool Wow64::RunWowHelper(void* buffer, DWORD timeout_ms) { | 137 bool Wow64::RunWowHelper(void* buffer) { |
166 COMPILE_ASSERT(sizeof(buffer) <= sizeof(timeout_ms), unsupported_64_bits); | 138 COMPILE_ASSERT(sizeof(buffer) <= sizeof DWORD, unsupported_64_bits); |
167 | 139 |
168 // Get the path to the helper (beside the exe). | 140 // Get the path to the helper (beside the exe). |
169 wchar_t prog_name[MAX_PATH]; | 141 wchar_t prog_name[MAX_PATH]; |
170 GetModuleFileNameW(NULL, prog_name, MAX_PATH); | 142 GetModuleFileNameW(NULL, prog_name, MAX_PATH); |
171 std::wstring path(prog_name); | 143 std::wstring path(prog_name); |
172 size_t name_pos = path.find_last_of(L"\\"); | 144 size_t name_pos = path.find_last_of(L"\\"); |
173 if (std::wstring::npos == name_pos) | 145 if (std::wstring::npos == name_pos) |
174 return false; | 146 return false; |
175 path.resize(name_pos + 1); | 147 path.resize(name_pos + 1); |
176 | 148 |
177 std::wstringstream command; | 149 std::wstringstream command; |
178 command << std::hex << std::showbase << L"\"" << path << | 150 command << std::hex << std::showbase << L"\"" << path << |
179 L"wow_helper.exe\" " << child_->ProcessId() << " " << | 151 L"wow_helper.exe\" " << child_->ProcessId() << " " << |
180 bit_cast<ULONG>(buffer); | 152 bit_cast<ULONG>(buffer); |
181 | 153 |
182 scoped_ptr_malloc<wchar_t> writable_command(_wcsdup(command.str().c_str())); | 154 scoped_ptr_malloc<wchar_t> writable_command(_wcsdup(command.str().c_str())); |
183 | 155 |
184 STARTUPINFO startup_info = {0}; | 156 STARTUPINFO startup_info = {0}; |
185 startup_info.cb = sizeof(startup_info); | 157 startup_info.cb = sizeof(startup_info); |
186 PROCESS_INFORMATION process_info; | 158 PROCESS_INFORMATION process_info; |
187 if (!::CreateProcess(NULL, writable_command.get(), NULL, NULL, FALSE, 0, NULL, | 159 if (!::CreateProcess(NULL, writable_command.get(), NULL, NULL, FALSE, 0, NULL, |
188 NULL, &startup_info, &process_info)) | 160 NULL, &startup_info, &process_info)) |
189 return false; | 161 return false; |
190 | 162 |
191 DWORD reason = ::WaitForSingleObject(process_info.hProcess, timeout_ms); | 163 DWORD reason = ::WaitForSingleObject(process_info.hProcess, INFINITE); |
192 | 164 |
193 DWORD code; | 165 DWORD code; |
194 bool ok = ::GetExitCodeProcess(process_info.hProcess, &code) ? true : false; | 166 bool ok = ::GetExitCodeProcess(process_info.hProcess, &code) ? true : false; |
195 | 167 |
196 ::CloseHandle(process_info.hProcess); | 168 ::CloseHandle(process_info.hProcess); |
197 ::CloseHandle(process_info.hThread); | 169 ::CloseHandle(process_info.hThread); |
198 | 170 |
199 if (WAIT_TIMEOUT == reason) | 171 if (WAIT_TIMEOUT == reason) |
200 return false; | 172 return false; |
201 | 173 |
202 return ok && (0 == code); | 174 return ok && (0 == code); |
203 } | 175 } |
204 | 176 |
205 // First we must wake up the child, then wait for dll loads on the child until | 177 // First we must wake up the child, then wait for dll loads on the child until |
206 // the one we care is loaded; at that point we must suspend the child again. | 178 // the one we care is loaded; at that point we must suspend the child again. |
207 bool Wow64::DllMapped(DWORD timeout_ms) { | 179 bool Wow64::DllMapped() { |
208 if (1 != ::ResumeThread(child_->MainThread())) { | 180 if (1 != ::ResumeThread(child_->MainThread())) { |
209 NOTREACHED(); | 181 NOTREACHED(); |
210 return false; | 182 return false; |
211 } | 183 } |
212 | 184 |
213 for (;;) { | 185 for (;;) { |
214 DWORD reason = ::WaitForSingleObject(dll_load_, timeout_ms); | 186 DWORD reason = ::WaitForSingleObject(dll_load_, INFINITE); |
215 if (WAIT_TIMEOUT == reason || WAIT_ABANDONED == reason) | 187 if (WAIT_TIMEOUT == reason || WAIT_ABANDONED == reason) |
216 return false; | 188 return false; |
217 | 189 |
218 if (!::ResetEvent(dll_load_)) | 190 if (!::ResetEvent(dll_load_)) |
219 return false; | 191 return false; |
220 | 192 |
221 bool found = NtdllPresent(); | 193 bool found = NtdllPresent(); |
222 if (found) { | 194 if (found) { |
223 if (::SuspendThread(child_->MainThread())) | 195 if (::SuspendThread(child_->MainThread())) |
224 return false; | 196 return false; |
(...skipping 13 matching lines...) Expand all Loading... |
238 SIZE_T read; | 210 SIZE_T read; |
239 if (!::ReadProcessMemory(child_->Process(), ntdll_, &buffer, kBufferSize, | 211 if (!::ReadProcessMemory(child_->Process(), ntdll_, &buffer, kBufferSize, |
240 &read)) | 212 &read)) |
241 return false; | 213 return false; |
242 if (kBufferSize != read) | 214 if (kBufferSize != read) |
243 return false; | 215 return false; |
244 return true; | 216 return true; |
245 } | 217 } |
246 | 218 |
247 } // namespace sandbox | 219 } // namespace sandbox |
OLD | NEW |