diff options
Diffstat (limited to 'sandbox/src/Wow64.cc')
-rw-r--r-- | sandbox/src/Wow64.cc | 219 |
1 files changed, 0 insertions, 219 deletions
diff --git a/sandbox/src/Wow64.cc b/sandbox/src/Wow64.cc deleted file mode 100644 index 5098647..0000000 --- a/sandbox/src/Wow64.cc +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "sandbox/src/wow64.h" - -#include <sstream> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/win/scoped_process_information.h" -#include "base/win/windows_version.h" -#include "sandbox/src/target_process.h" - -namespace { - -// Holds the information needed for the interception of NtMapViewOfSection on -// 64 bits. -// Warning: do not modify this definition without changing also the code on the -// 64 bit helper process. -struct PatchInfo32 { - HANDLE dll_load; // Event to signal the broker. - ULONG pad1; - HANDLE continue_load; // Event to wait for the broker. - ULONG pad2; - HANDLE section; // First argument of the call. - ULONG pad3; - void* orig_MapViewOfSection; - ULONG original_high; - void* signal_and_wait; - ULONG pad4; - void* patch_location; - ULONG patch_high; -}; - -// Size of the 64 bit service entry. -const SIZE_T kServiceEntry64Size = 0x10; - -// Removes the interception of ntdll64. -bool Restore64Code(HANDLE child, PatchInfo32* patch_info) { - PatchInfo32 local_patch_info; - SIZE_T actual; - if (!::ReadProcessMemory(child, patch_info, &local_patch_info, - sizeof(local_patch_info), &actual)) - return false; - if (sizeof(local_patch_info) != actual) - return false; - - if (local_patch_info.original_high) - return false; - if (local_patch_info.patch_high) - return false; - - char buffer[kServiceEntry64Size]; - - if (!::ReadProcessMemory(child, local_patch_info.orig_MapViewOfSection, - &buffer, kServiceEntry64Size, &actual)) - return false; - if (kServiceEntry64Size != actual) - return false; - - if (!::WriteProcessMemory(child, local_patch_info.patch_location, &buffer, - kServiceEntry64Size, &actual)) - return false; - if (kServiceEntry64Size != actual) - return false; - return true; -} - -typedef BOOL (WINAPI* IsWow64ProcessFunction)(HANDLE process, BOOL* wow64); - -} // namespace - -namespace sandbox { - -Wow64::~Wow64() { - if (dll_load_) - ::CloseHandle(dll_load_); - - if (continue_load_) - ::CloseHandle(continue_load_); -} - -// The basic idea is to allocate one page of memory on the child, and initialize -// the first part of it with our version of PatchInfo32. Then launch the helper -// process passing it that address on the child. The helper process will patch -// the 64 bit version of NtMapViewOfFile, and the interception will signal the -// first event on the buffer. We'll be waiting on that event and after the 32 -// bit version of ntdll is loaded, we'll remove the interception and return to -// our caller. -bool Wow64::WaitForNtdll() { - if (base::win::OSInfo::GetInstance()->wow64_status() != - base::win::OSInfo::WOW64_ENABLED) - return true; - - const size_t page_size = 4096; - - // Create some default manual reset un-named events, not signaled. - dll_load_ = ::CreateEvent(NULL, TRUE, FALSE, NULL); - continue_load_ = ::CreateEvent(NULL, TRUE, FALSE, NULL); - HANDLE current_process = ::GetCurrentProcess(); - HANDLE remote_load, remote_continue; - DWORD access = EVENT_MODIFY_STATE | SYNCHRONIZE; - if (!::DuplicateHandle(current_process, dll_load_, child_->Process(), - &remote_load, access, FALSE, 0)) - return false; - if (!::DuplicateHandle(current_process, continue_load_, child_->Process(), - &remote_continue, access, FALSE, 0)) - return false; - - void* buffer = ::VirtualAllocEx(child_->Process(), NULL, page_size, - MEM_COMMIT, PAGE_EXECUTE_READWRITE); - DCHECK(buffer); - if (!buffer) - return false; - - PatchInfo32* patch_info = reinterpret_cast<PatchInfo32*>(buffer); - PatchInfo32 local_patch_info = {0}; - local_patch_info.dll_load = remote_load; - local_patch_info.continue_load = remote_continue; - SIZE_T written; - if (!::WriteProcessMemory(child_->Process(), patch_info, &local_patch_info, - offsetof(PatchInfo32, section), &written)) - return false; - if (offsetof(PatchInfo32, section) != written) - return false; - - if (!RunWowHelper(buffer)) - return false; - - // The child is intercepted on 64 bit, go on and wait for our event. - if (!DllMapped()) - return false; - - // The 32 bit version is available, cleanup the child. - return Restore64Code(child_->Process(), patch_info); -} - -bool Wow64::RunWowHelper(void* buffer) { - COMPILE_ASSERT(sizeof(buffer) <= sizeof(DWORD), unsupported_64_bits); - - // Get the path to the helper (beside the exe). - wchar_t prog_name[MAX_PATH]; - GetModuleFileNameW(NULL, prog_name, MAX_PATH); - std::wstring path(prog_name); - size_t name_pos = path.find_last_of(L"\\"); - if (std::wstring::npos == name_pos) - return false; - path.resize(name_pos + 1); - - std::wstringstream command; - command << std::hex << std::showbase << L"\"" << path << - L"wow_helper.exe\" " << child_->ProcessId() << " " << - bit_cast<ULONG>(buffer); - - scoped_ptr_malloc<wchar_t> writable_command(_wcsdup(command.str().c_str())); - - STARTUPINFO startup_info = {0}; - startup_info.cb = sizeof(startup_info); - base::win::ScopedProcessInformation process_info; - if (!::CreateProcess(NULL, writable_command.get(), NULL, NULL, FALSE, 0, NULL, - NULL, &startup_info, process_info.Receive())) - return false; - - DWORD reason = ::WaitForSingleObject(process_info.process_handle(), INFINITE); - - DWORD code; - bool ok = - ::GetExitCodeProcess(process_info.process_handle(), &code) ? true : false; - - if (WAIT_TIMEOUT == reason) - return false; - - return ok && (0 == code); -} - -// First we must wake up the child, then wait for dll loads on the child until -// the one we care is loaded; at that point we must suspend the child again. -bool Wow64::DllMapped() { - if (1 != ::ResumeThread(child_->MainThread())) { - NOTREACHED(); - return false; - } - - for (;;) { - DWORD reason = ::WaitForSingleObject(dll_load_, INFINITE); - if (WAIT_TIMEOUT == reason || WAIT_ABANDONED == reason) - return false; - - if (!::ResetEvent(dll_load_)) - return false; - - bool found = NtdllPresent(); - if (found) { - if (::SuspendThread(child_->MainThread())) - return false; - } - - if (!::SetEvent(continue_load_)) - return false; - - if (found) - return true; - } -} - -bool Wow64::NtdllPresent() { - const size_t kBufferSize = 512; - char buffer[kBufferSize]; - SIZE_T read; - if (!::ReadProcessMemory(child_->Process(), ntdll_, &buffer, kBufferSize, - &read)) - return false; - if (kBufferSize != read) - return false; - return true; -} - -} // namespace sandbox |