| Index: sandbox/win/wow_helper/service64_resolver.cc
|
| diff --git a/sandbox/win/wow_helper/service64_resolver.cc b/sandbox/win/wow_helper/service64_resolver.cc
|
| deleted file mode 100644
|
| index 0424d9fdddeb994e75cfb6585484e93b84fad696..0000000000000000000000000000000000000000
|
| --- a/sandbox/win/wow_helper/service64_resolver.cc
|
| +++ /dev/null
|
| @@ -1,346 +0,0 @@
|
| -// Copyright (c) 2011 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/wow_helper/service64_resolver.h"
|
| -
|
| -#include <limits.h>
|
| -#include <stddef.h>
|
| -
|
| -#include "base/bit_cast.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "sandbox/win/wow_helper/target_code.h"
|
| -
|
| -namespace {
|
| -#pragma pack(push, 1)
|
| -
|
| -const BYTE kMovEax = 0xB8;
|
| -const BYTE kMovEdx = 0xBA;
|
| -const USHORT kCallPtrEdx = 0x12FF;
|
| -const BYTE kRet = 0xC2;
|
| -const BYTE kNop = 0x90;
|
| -const USHORT kJmpEdx = 0xE2FF;
|
| -const USHORT kXorEcx = 0xC933;
|
| -const ULONG kLeaEdx = 0x0424548D;
|
| -const ULONG kCallFs1 = 0xC015FF64;
|
| -const ULONG kCallFs2Ret = 0xC2000000;
|
| -const BYTE kPopEdx = 0x5A;
|
| -const BYTE kPushEdx = 0x52;
|
| -const BYTE kPush32 = 0x68;
|
| -
|
| -const ULONG kMmovR10EcxMovEax = 0xB8D18B4C;
|
| -const USHORT kSyscall = 0x050F;
|
| -const BYTE kRetNp = 0xC3;
|
| -const BYTE kPad = 0x66;
|
| -const USHORT kNop16 = 0x9066;
|
| -const BYTE kRelJmp = 0xE9;
|
| -
|
| -const ULONG kXorRaxMovEax = 0xB8C03148;
|
| -const ULONG kSaveRcx = 0x10488948;
|
| -const ULONG kMovRcxRaxJmp = 0xE9C88B48;
|
| -
|
| -// Service code for 64 bit systems.
|
| -struct ServiceEntry {
|
| - // this struct contains roughly the following code:
|
| - // mov r10,rcx
|
| - // mov eax,52h
|
| - // syscall
|
| - // ret
|
| - // xchg ax,ax
|
| - // xchg ax,ax
|
| -
|
| - ULONG mov_r10_ecx_mov_eax; // = 4C 8B D1 B8
|
| - ULONG service_id;
|
| - USHORT syscall; // = 0F 05
|
| - BYTE ret; // = C3
|
| - BYTE pad; // = 66
|
| - USHORT xchg_ax_ax1; // = 66 90
|
| - USHORT xchg_ax_ax2; // = 66 90
|
| -};
|
| -
|
| -struct Redirected {
|
| - // this struct contains roughly the following code:
|
| - // jmp relative_32
|
| - // xchg ax,ax // 3 byte nop
|
| -
|
| - Redirected() {
|
| - jmp = kRelJmp;
|
| - relative = 0;
|
| - pad = kPad;
|
| - xchg_ax_ax = kNop16;
|
| - };
|
| - BYTE jmp; // = E9
|
| - ULONG relative;
|
| - BYTE pad; // = 66
|
| - USHORT xchg_ax_ax; // = 66 90
|
| -};
|
| -
|
| -struct InternalThunk {
|
| - // this struct contains roughly the following code:
|
| - // xor rax,rax
|
| - // mov eax, 0x00080000 // Thunk storage.
|
| - // mov [rax]PatchInfo.service, rcx // Save first argument.
|
| - // mov rcx, rax
|
| - // jmp relative_to_interceptor
|
| -
|
| - InternalThunk() {
|
| - xor_rax_mov_eax = kXorRaxMovEax;
|
| - patch_info = 0;
|
| - save_rcx = kSaveRcx;
|
| - mov_rcx_rax_jmp = kMovRcxRaxJmp;
|
| - relative = 0;
|
| - };
|
| - ULONG xor_rax_mov_eax; // = 48 31 C0 B8
|
| - ULONG patch_info;
|
| - ULONG save_rcx; // = 48 89 48 10
|
| - ULONG mov_rcx_rax_jmp; // = 48 8b c8 e9
|
| - ULONG relative;
|
| -};
|
| -
|
| -struct ServiceFullThunk {
|
| - sandbox::PatchInfo patch_info;
|
| - ServiceEntry original;
|
| - InternalThunk internal_thunk;
|
| -};
|
| -
|
| -#pragma pack(pop)
|
| -
|
| -// Simple utility function to write to a buffer on the child, if the memery has
|
| -// write protection attributes.
|
| -// Arguments:
|
| -// child_process (in): process to write to.
|
| -// address (out): memory position on the child to write to.
|
| -// buffer (in): local buffer with the data to write .
|
| -// length (in): number of bytes to write.
|
| -// Returns true on success.
|
| -bool WriteProtectedChildMemory(HANDLE child_process,
|
| - void* address,
|
| - const void* buffer,
|
| - size_t length) {
|
| - // first, remove the protections
|
| - DWORD old_protection;
|
| - if (!::VirtualProtectEx(child_process, address, length,
|
| - PAGE_WRITECOPY, &old_protection))
|
| - return false;
|
| -
|
| - SIZE_T written;
|
| - bool ok = ::WriteProcessMemory(child_process, address, buffer, length,
|
| - &written) && (length == written);
|
| -
|
| - // always attempt to restore the original protection
|
| - if (!::VirtualProtectEx(child_process, address, length,
|
| - old_protection, &old_protection))
|
| - return false;
|
| -
|
| - return ok;
|
| -}
|
| -
|
| -// Get pointers to the functions that we need from ntdll.dll.
|
| -NTSTATUS ResolveNtdll(sandbox::PatchInfo* patch_info) {
|
| - wchar_t* ntdll_name = L"ntdll.dll";
|
| - HMODULE ntdll = ::GetModuleHandle(ntdll_name);
|
| - if (!ntdll)
|
| - return STATUS_PROCEDURE_NOT_FOUND;
|
| -
|
| - void* signal = ::GetProcAddress(ntdll, "NtSignalAndWaitForSingleObject");
|
| - if (!signal)
|
| - return STATUS_PROCEDURE_NOT_FOUND;
|
| -
|
| - patch_info->signal_and_wait =
|
| - reinterpret_cast<NtSignalAndWaitForSingleObjectFunction>(signal);
|
| -
|
| - return STATUS_SUCCESS;
|
| -}
|
| -
|
| -}; // namespace
|
| -
|
| -namespace sandbox {
|
| -
|
| -NTSTATUS ResolverThunk::Init(const void* target_module,
|
| - const void* interceptor_module,
|
| - const char* target_name,
|
| - const char* interceptor_name,
|
| - const void* interceptor_entry_point,
|
| - void* thunk_storage,
|
| - size_t storage_bytes) {
|
| - if (NULL == thunk_storage || 0 == storage_bytes ||
|
| - NULL == target_module || NULL == target_name)
|
| - return STATUS_INVALID_PARAMETER;
|
| -
|
| - if (storage_bytes < GetThunkSize())
|
| - return STATUS_BUFFER_TOO_SMALL;
|
| -
|
| - NTSTATUS ret = STATUS_SUCCESS;
|
| - if (NULL == interceptor_entry_point) {
|
| - ret = ResolveInterceptor(interceptor_module, interceptor_name,
|
| - &interceptor_entry_point);
|
| - if (!NT_SUCCESS(ret))
|
| - return ret;
|
| - }
|
| -
|
| - ret = ResolveTarget(target_module, target_name, &target_);
|
| - if (!NT_SUCCESS(ret))
|
| - return ret;
|
| -
|
| - interceptor_ = interceptor_entry_point;
|
| -
|
| - return ret;
|
| -}
|
| -
|
| -NTSTATUS ResolverThunk::ResolveInterceptor(const void* interceptor_module,
|
| - const char* interceptor_name,
|
| - const void** address) {
|
| - return STATUS_NOT_IMPLEMENTED;
|
| -}
|
| -
|
| -NTSTATUS ResolverThunk::ResolveTarget(const void* module,
|
| - const char* function_name,
|
| - void** address) {
|
| - return STATUS_NOT_IMPLEMENTED;
|
| -}
|
| -
|
| -NTSTATUS Service64ResolverThunk::Setup(const void* target_module,
|
| - const void* interceptor_module,
|
| - const char* target_name,
|
| - const char* interceptor_name,
|
| - const void* interceptor_entry_point,
|
| - void* thunk_storage,
|
| - size_t storage_bytes,
|
| - size_t* storage_used) {
|
| - NTSTATUS ret = Init(target_module, interceptor_module, target_name,
|
| - interceptor_name, interceptor_entry_point,
|
| - thunk_storage, storage_bytes);
|
| - if (!NT_SUCCESS(ret))
|
| - return ret;
|
| -
|
| - size_t thunk_bytes = GetThunkSize();
|
| - scoped_ptr<char[]> thunk_buffer(new char[thunk_bytes]);
|
| - ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(
|
| - thunk_buffer.get());
|
| -
|
| - if (!IsFunctionAService(&thunk->original))
|
| - return STATUS_UNSUCCESSFUL;
|
| -
|
| - ret = PerformPatch(thunk, thunk_storage);
|
| -
|
| - if (NULL != storage_used)
|
| - *storage_used = thunk_bytes;
|
| -
|
| - return ret;
|
| -}
|
| -
|
| -NTSTATUS Service64ResolverThunk::ResolveInterceptor(
|
| - const void* interceptor_module,
|
| - const char* interceptor_name,
|
| - const void** address) {
|
| - // After all, we are using a locally mapped version of the exe, so the
|
| - // action is the same as for a target function.
|
| - return ResolveTarget(interceptor_module, interceptor_name,
|
| - const_cast<void**>(address));
|
| -}
|
| -
|
| -// In this case all the work is done from the parent, so resolve is
|
| -// just a simple GetProcAddress.
|
| -NTSTATUS Service64ResolverThunk::ResolveTarget(const void* module,
|
| - const char* function_name,
|
| - void** address) {
|
| - if (NULL == module)
|
| - return STATUS_UNSUCCESSFUL;
|
| -
|
| - *address = ::GetProcAddress(bit_cast<HMODULE>(module), function_name);
|
| -
|
| - if (NULL == *address)
|
| - return STATUS_UNSUCCESSFUL;
|
| -
|
| - return STATUS_SUCCESS;
|
| -}
|
| -
|
| -size_t Service64ResolverThunk::GetThunkSize() const {
|
| - return sizeof(ServiceFullThunk);
|
| -}
|
| -
|
| -bool Service64ResolverThunk::IsFunctionAService(void* local_thunk) const {
|
| - ServiceEntry function_code;
|
| - SIZE_T read;
|
| - if (!::ReadProcessMemory(process_, target_, &function_code,
|
| - sizeof(function_code), &read))
|
| - return false;
|
| -
|
| - if (sizeof(function_code) != read)
|
| - return false;
|
| -
|
| - if (kMmovR10EcxMovEax != function_code.mov_r10_ecx_mov_eax ||
|
| - kSyscall != function_code.syscall || kRetNp != function_code.ret)
|
| - return false;
|
| -
|
| - // Save the verified code
|
| - memcpy(local_thunk, &function_code, sizeof(function_code));
|
| -
|
| - return true;
|
| -}
|
| -
|
| -NTSTATUS Service64ResolverThunk::PerformPatch(void* local_thunk,
|
| - void* remote_thunk) {
|
| - ServiceFullThunk* full_local_thunk = reinterpret_cast<ServiceFullThunk*>(
|
| - local_thunk);
|
| - ServiceFullThunk* full_remote_thunk = reinterpret_cast<ServiceFullThunk*>(
|
| - remote_thunk);
|
| -
|
| - // If the source or target are above 4GB we cannot do this relative jump.
|
| - if (reinterpret_cast<ULONG_PTR>(full_remote_thunk) >
|
| - static_cast<ULONG_PTR>(ULONG_MAX))
|
| - return STATUS_CONFLICTING_ADDRESSES;
|
| -
|
| - if (reinterpret_cast<ULONG_PTR>(target_) > static_cast<ULONG_PTR>(ULONG_MAX))
|
| - return STATUS_CONFLICTING_ADDRESSES;
|
| -
|
| - // Patch the original code.
|
| - Redirected local_service;
|
| - Redirected* remote_service = reinterpret_cast<Redirected*>(target_);
|
| - ULONG_PTR diff = reinterpret_cast<BYTE*>(&full_remote_thunk->internal_thunk) -
|
| - &remote_service->pad;
|
| - local_service.relative = static_cast<ULONG>(diff);
|
| -
|
| - // Setup the PatchInfo structure.
|
| - SIZE_T actual;
|
| - if (!::ReadProcessMemory(process_, remote_thunk, local_thunk,
|
| - sizeof(PatchInfo), &actual))
|
| - return STATUS_UNSUCCESSFUL;
|
| - if (sizeof(PatchInfo) != actual)
|
| - return STATUS_UNSUCCESSFUL;
|
| -
|
| - full_local_thunk->patch_info.orig_MapViewOfSection = reinterpret_cast<
|
| - NtMapViewOfSectionFunction>(&full_remote_thunk->original);
|
| - full_local_thunk->patch_info.patch_location = target_;
|
| - NTSTATUS ret = ResolveNtdll(&full_local_thunk->patch_info);
|
| - if (!NT_SUCCESS(ret))
|
| - return ret;
|
| -
|
| - // Setup the thunk. The jump out is performed from right after the end of the
|
| - // thunk (full_remote_thunk + 1).
|
| - InternalThunk my_thunk;
|
| - ULONG_PTR patch_info = reinterpret_cast<ULONG_PTR>(remote_thunk);
|
| - my_thunk.patch_info = static_cast<ULONG>(patch_info);
|
| - diff = reinterpret_cast<const BYTE*>(interceptor_) -
|
| - reinterpret_cast<BYTE*>(full_remote_thunk + 1);
|
| - my_thunk.relative = static_cast<ULONG>(diff);
|
| -
|
| - memcpy(&full_local_thunk->internal_thunk, &my_thunk, sizeof(my_thunk));
|
| -
|
| - // copy the local thunk buffer to the child
|
| - if (!::WriteProcessMemory(process_, remote_thunk, local_thunk,
|
| - sizeof(ServiceFullThunk), &actual))
|
| - return STATUS_UNSUCCESSFUL;
|
| -
|
| - if (sizeof(ServiceFullThunk) != actual)
|
| - return STATUS_UNSUCCESSFUL;
|
| -
|
| - // and now change the function to intercept, on the child
|
| - if (!::WriteProtectedChildMemory(process_, target_, &local_service,
|
| - sizeof(local_service)))
|
| - return STATUS_UNSUCCESSFUL;
|
| -
|
| - return STATUS_SUCCESS;
|
| -}
|
| -
|
| -} // namespace sandbox
|
|
|