| Index: sandbox/win/src/Wow64.cc
|
| diff --git a/sandbox/win/src/Wow64.cc b/sandbox/win/src/Wow64.cc
|
| deleted file mode 100644
|
| index c5984d629ba1361e3484b6639f2cba1942d5dcd5..0000000000000000000000000000000000000000
|
| --- a/sandbox/win/src/Wow64.cc
|
| +++ /dev/null
|
| @@ -1,226 +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/win/src/Wow64.h"
|
| -
|
| -#include <stddef.h>
|
| -
|
| -#include <sstream>
|
| -
|
| -#include "base/bit_cast.h"
|
| -#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/win/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(TargetProcess* child, HMODULE ntdll)
|
| - : child_(child), ntdll_(ntdll), dll_load_(NULL), continue_load_(NULL) {
|
| -}
|
| -
|
| -Wow64::~Wow64() {
|
| -}
|
| -
|
| -// 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_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
|
| - continue_load_.Set(::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_.Get(), child_->Process(),
|
| - &remote_load, access, FALSE, 0)) {
|
| - return false;
|
| - }
|
| - if (!::DuplicateHandle(current_process, continue_load_.Get(),
|
| - 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) {
|
| - static_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);
|
| - base::string16 path(prog_name);
|
| - size_t name_pos = path.find_last_of(L"\\");
|
| - if (base::string16::npos == name_pos)
|
| - return false;
|
| - path.resize(name_pos + 1);
|
| -
|
| - std::basic_stringstream<base::char16> command;
|
| - command << std::hex << std::showbase << L"\"" << path <<
|
| - L"wow_helper.exe\" " << child_->ProcessId() << " " <<
|
| - bit_cast<ULONG>(buffer);
|
| -
|
| - scoped_ptr<wchar_t, base::FreeDeleter>
|
| - writable_command(_wcsdup(command.str().c_str()));
|
| -
|
| - STARTUPINFO startup_info = {0};
|
| - startup_info.cb = sizeof(startup_info);
|
| - PROCESS_INFORMATION temp_process_info = {};
|
| - if (!::CreateProcess(NULL, writable_command.get(), NULL, NULL, FALSE, 0, NULL,
|
| - NULL, &startup_info, &temp_process_info))
|
| - return false;
|
| - base::win::ScopedProcessInformation process_info(temp_process_info);
|
| -
|
| - 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_.Get(), INFINITE);
|
| - if (WAIT_TIMEOUT == reason || WAIT_ABANDONED == reason)
|
| - return false;
|
| -
|
| - if (!::ResetEvent(dll_load_.Get()))
|
| - return false;
|
| -
|
| - bool found = NtdllPresent();
|
| - if (found) {
|
| - if (::SuspendThread(child_->MainThread()))
|
| - return false;
|
| - }
|
| -
|
| - if (!::SetEvent(continue_load_.Get()))
|
| - 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
|
|
|