| 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 |