diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 22:41:28 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 22:41:28 +0000 |
commit | a814a8d55429605fe6d7045045cd25b6bf624580 (patch) | |
tree | 58fcd994d4ce41ef021f6406a6fac32d9ca2d265 /sandbox/wow_helper | |
parent | e6c9e14e0dfec2bb156a1f7a107cda3ebee8d392 (diff) | |
download | chromium_src-a814a8d55429605fe6d7045045cd25b6bf624580.zip chromium_src-a814a8d55429605fe6d7045045cd25b6bf624580.tar.gz chromium_src-a814a8d55429605fe6d7045045cd25b6bf624580.tar.bz2 |
Add sandbox to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/wow_helper')
-rw-r--r-- | sandbox/wow_helper/service64_resolver.cc | 371 | ||||
-rw-r--r-- | sandbox/wow_helper/service64_resolver.h | 97 | ||||
-rw-r--r-- | sandbox/wow_helper/target_code.cc | 59 | ||||
-rw-r--r-- | sandbox/wow_helper/target_code.h | 66 | ||||
-rw-r--r-- | sandbox/wow_helper/wow_helper.cc | 152 | ||||
-rw-r--r-- | sandbox/wow_helper/wow_helper.exe | bin | 0 -> 99328 bytes | |||
-rw-r--r-- | sandbox/wow_helper/wow_helper.pdb | bin | 0 -> 2141184 bytes | |||
-rw-r--r-- | sandbox/wow_helper/wow_helper.vcproj | 231 |
8 files changed, 976 insertions, 0 deletions
diff --git a/sandbox/wow_helper/service64_resolver.cc b/sandbox/wow_helper/service64_resolver.cc new file mode 100644 index 0000000..6718149 --- /dev/null +++ b/sandbox/wow_helper/service64_resolver.cc @@ -0,0 +1,371 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "sandbox/wow_helper/service64_resolver.h" + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "sandbox/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) { + DCHECK(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 || + kPad != function_code.pad || kNop16 != function_code.xchg_ax_ax1 || + kNop16 != function_code.xchg_ax_ax1) + 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 diff --git a/sandbox/wow_helper/service64_resolver.h b/sandbox/wow_helper/service64_resolver.h new file mode 100644 index 0000000..9d20bed --- /dev/null +++ b/sandbox/wow_helper/service64_resolver.h @@ -0,0 +1,97 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef SANDBOX_WOW_HELPER_SERVICE64_RESOLVER_H__ +#define SANDBOX_WOW_HELPER_SERVICE64_RESOLVER_H__ + +#include "sandbox/src/nt_internals.h" +#include "sandbox/src/resolver.h" + +namespace sandbox { + +// This is the concrete resolver used to perform service-call type functions +// inside ntdll.dll (64-bit). +class Service64ResolverThunk : public ResolverThunk { + public: + // The service resolver needs a child process to write to. + explicit Service64ResolverThunk(HANDLE process) + : process_(process), ntdll_base_(NULL) {} + virtual ~Service64ResolverThunk() {} + + // Implementation of Resolver::Setup. + virtual NTSTATUS 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); + + // Implementation of Resolver::ResolveInterceptor. + virtual NTSTATUS ResolveInterceptor(const void* module, + const char* function_name, + const void** address); + + // Implementation of Resolver::ResolveTarget. + virtual NTSTATUS ResolveTarget(const void* module, + const char* function_name, + void** address); + + // Implementation of Resolver::GetThunkSize. + virtual size_t GetThunkSize() const; + + protected: + // The unit test will use this member to allow local patch on a buffer. + HMODULE ntdll_base_; + + // Handle of the child process. + HANDLE process_; + + private: + // Returns true if the code pointer by target_ corresponds to the expected + // type of function. Saves that code on the first part of the thunk pointed + // by local_thunk (should be directly accessible from the parent). + virtual bool IsFunctionAService(void* local_thunk) const; + + // Performs the actual patch of target_. + // local_thunk must be already fully initialized, and the first part must + // contain the original code. The real type of this buffer is ServiceFullThunk + // (yes, private). remote_thunk (real type ServiceFullThunk), must be + // allocated on the child, and will contain the thunk data, after this call. + // Returns the apropriate status code. + virtual NTSTATUS PerformPatch(void* local_thunk, void* remote_thunk); + + DISALLOW_EVIL_CONSTRUCTORS(Service64ResolverThunk); +}; + +} // namespace sandbox + + +#endif // SANDBOX_WOW_HELPER_SERVICE64_RESOLVER_H__ diff --git a/sandbox/wow_helper/target_code.cc b/sandbox/wow_helper/target_code.cc new file mode 100644 index 0000000..1ef1582 --- /dev/null +++ b/sandbox/wow_helper/target_code.cc @@ -0,0 +1,59 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "sandbox/wow_helper/target_code.h" + +namespace sandbox { + +// Hooks NtMapViewOfSection to detect the load of dlls. +NTSTATUS WINAPI TargetNtMapViewOfSection( + PatchInfo *patch_info, HANDLE process, PVOID *base, ULONG_PTR zero_bits, + SIZE_T commit_size, PLARGE_INTEGER offset, PSIZE_T view_size, + SECTION_INHERIT inherit, ULONG allocation_type, ULONG protect) { + NTSTATUS ret = patch_info->orig_MapViewOfSection(patch_info->section, process, + base, zero_bits, commit_size, + offset, view_size, inherit, + allocation_type, protect); + + LARGE_INTEGER timeout; + timeout.QuadPart = -(5 * 10000000); // 5 seconds. + + // The wait is alertable. + patch_info->signal_and_wait(patch_info->dll_load, patch_info->continue_load, + TRUE, &timeout); + + return ret; +} + +// Marks the end of the code to copy to the target process. +NTSTATUS WINAPI TargetEnd() { + return STATUS_SUCCESS; +} + +} // namespace sandbox diff --git a/sandbox/wow_helper/target_code.h b/sandbox/wow_helper/target_code.h new file mode 100644 index 0000000..9ae9089 --- /dev/null +++ b/sandbox/wow_helper/target_code.h @@ -0,0 +1,66 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef SANDBOX_WOW_HELPER_TARGET_CODE_H__ +#define SANDBOX_WOW_HELPER_TARGET_CODE_H__ + +#include "sandbox/src/nt_internals.h" + +namespace sandbox { + +extern "C" { + +// Holds the information needed for the interception of NtMapViewOfSection. +// Changes of this structure must be synchronized with changes of PatchInfo32 +// on sandbox/src/wow64.cc. +struct PatchInfo { + HANDLE dll_load; // Event to signal the broker. + HANDLE continue_load; // Event to wait for the broker. + HANDLE section; // First argument of the call. + NtMapViewOfSectionFunction orig_MapViewOfSection; + NtSignalAndWaitForSingleObjectFunction signal_and_wait; + void* patch_location; +}; + +// Interception of NtMapViewOfSection on the child process. +// It should never be called directly. This function provides the means to +// detect dlls being loaded, so we can patch them if needed. +NTSTATUS WINAPI TargetNtMapViewOfSection( + PatchInfo* patch_info, HANDLE process, PVOID* base, ULONG_PTR zero_bits, + SIZE_T commit_size, PLARGE_INTEGER offset, PSIZE_T view_size, + SECTION_INHERIT inherit, ULONG allocation_type, ULONG protect); + +// Marker of the end of TargetNtMapViewOfSection. +NTSTATUS WINAPI TargetEnd(); + +} // extern "C" + +} // namespace sandbox + +#endif // SANDBOX_WOW_HELPER_TARGET_CODE_H__ diff --git a/sandbox/wow_helper/wow_helper.cc b/sandbox/wow_helper/wow_helper.cc new file mode 100644 index 0000000..9e8ae09f --- /dev/null +++ b/sandbox/wow_helper/wow_helper.cc @@ -0,0 +1,152 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Wow_helper.exe is a simple Win32 64-bit executable designed to help to +// sandbox a 32 bit application running on a 64 bit OS. The basic idea is to +// perform a 64 bit interception of the target process and notify the 32-bit +// broker process whenever a DLL is being loaded. This allows the broker to +// setup the interceptions (32-bit) properly on the target. + +#include <windows.h> + +#include <string> + +#include "base/logging.h" +#include "sandbox/wow_helper/service64_resolver.h" +#include "sandbox/wow_helper/target_code.h" + +namespace { + +// Grabbed from chrome/common/string_util.h +template <class char_type> +inline char_type* WriteInto( + std::basic_string<char_type, std::char_traits<char_type>, + std::allocator<char_type> >* str, + size_t length_including_null) { + str->reserve(length_including_null); + str->resize(length_including_null - 1); + return &((*str)[0]); +} + +// Grabbed from chrome/common/string_util.cc +std::string WideToMultiByte(const std::wstring& wide, UINT code_page) { + if (wide.length() == 0) + return std::string(); + + // compute the length of the buffer we'll need + int charcount = WideCharToMultiByte(code_page, 0, wide.c_str(), -1, + NULL, 0, NULL, NULL); + if (charcount == 0) + return std::string(); + + // convert + std::string mb; + WideCharToMultiByte(code_page, 0, wide.c_str(), -1, + WriteInto(&mb, charcount), charcount, NULL, NULL); + + return mb; +} + +// Grabbed from chrome/common/string_util.cc +std::string WideToUTF8(const std::wstring& wide) { + return WideToMultiByte(wide, CP_UTF8); +} + +} // namespace + +namespace sandbox { + +// Performs the interception of NtMapViewOfSection on the 64-bit version of +// ntdll.dll. 'thunk' is the buffer on the address space of process 'child', +// that will be used to store the information about the patch. +int PatchNtdll(HANDLE child, void* thunk, size_t thunk_bytes) { + wchar_t* ntdll_name = L"ntdll.dll"; + HMODULE ntdll_base = ::GetModuleHandle(ntdll_name); + if (!ntdll_base) + return 100; + + Service64ResolverThunk resolver(child); + size_t used = resolver.GetThunkSize(); + char* code = reinterpret_cast<char*>(thunk) + used; + NTSTATUS ret = resolver.Setup(ntdll_base, NULL, "NtMapViewOfSection", NULL, + code, thunk, thunk_bytes, NULL); + if (!NT_SUCCESS(ret)) + return 101; + + size_t size = reinterpret_cast<char*>(&TargetEnd) - + reinterpret_cast<char*>(&TargetNtMapViewOfSection); + + if (size + used > thunk_bytes) + return 102; + + SIZE_T written; + if (!::WriteProcessMemory(child, code, &TargetNtMapViewOfSection, size, + &written)) + return 103; + + if (size != written) + return 104; + + return 0; +} + +} // namespace sandbox + +// We must receive two arguments: the process id of the target to intercept and +// the address of a page of memory on that process that will be used for the +// interception. We receive the address because the broker will cleanup the +// patch when the work is performed. +// +// It should be noted that we don't wait until the real work is done; this +// program quits as soon as the 64-bit interception is performed. +int wWinMain(HINSTANCE, HINSTANCE, wchar_t* command_line, int) { + COMPILE_ASSERT(sizeof(void*) > sizeof(DWORD), unsupported_32_bits); + if (!command_line) + return 1; + + wchar_t* next; + DWORD process_id = wcstoul(command_line, &next, 0); + if (!process_id) + return 2; + + DWORD access = PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE; + HANDLE child = ::OpenProcess(access, FALSE, process_id); + DCHECK(child); + if (!child) + return 3; + + DWORD buffer = wcstoul(next, NULL, 0); + if (!buffer) + return 4; + + void* thunk = reinterpret_cast<void*>(static_cast<ULONG_PTR>(buffer)); + + const size_t kPageSize = 4096; + return sandbox::PatchNtdll(child, thunk, kPageSize); +} diff --git a/sandbox/wow_helper/wow_helper.exe b/sandbox/wow_helper/wow_helper.exe Binary files differnew file mode 100644 index 0000000..163270a --- /dev/null +++ b/sandbox/wow_helper/wow_helper.exe diff --git a/sandbox/wow_helper/wow_helper.pdb b/sandbox/wow_helper/wow_helper.pdb Binary files differnew file mode 100644 index 0000000..a0d7d48 --- /dev/null +++ b/sandbox/wow_helper/wow_helper.pdb diff --git a/sandbox/wow_helper/wow_helper.vcproj b/sandbox/wow_helper/wow_helper.vcproj new file mode 100644 index 0000000..3fef097 --- /dev/null +++ b/sandbox/wow_helper/wow_helper.vcproj @@ -0,0 +1,231 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="wow_helper" + ProjectGUID="{BCF3A457-39F1-4DAA-9A65-93CFCD559036}" + RootNamespace="wow_helper" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="x64" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|x64" + OutputDirectory="$(ProjectDir)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="$(SolutionDir)..;$(SolutionDir)..\third_party\platformsdk_vista_6_0\files\Include;$(SolutionDir)..\third_party\platformsdk_vista_6_0\files\VC\INCLUDE;$(VSInstallDir)\VC\atlmfc\include" + PreprocessorDefinitions="_WIN32_WINNT=0x0501;WINVER=0x0501;WIN32;_DEBUG" + MinimalRebuild="true" + BasicRuntimeChecks="0" + RuntimeLibrary="1" + BufferSecurityCheck="false" + RuntimeTypeInfo="false" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="2" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|x64" + OutputDirectory="$(ProjectDir)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + TargetEnvironment="3" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="$(SolutionDir)..;$(SolutionDir)..\third_party\platformsdk_vista_6_0\files\Include;$(SolutionDir)..\third_party\platformsdk_vista_6_0\files\VC\INCLUDE;$(VSInstallDir)\VC\atlmfc\include" + PreprocessorDefinitions="_WIN32_WINNT=0x0501;WINVER=0x0501;WIN32;NDEBUG" + RuntimeLibrary="0" + BufferSecurityCheck="false" + RuntimeTypeInfo="false" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="17" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="base" + > + <File + RelativePath="..\..\base\logging.cc" + > + </File> + <File + RelativePath="..\..\base\logging.h" + > + </File> + <File + RelativePath="..\..\base\scoped_ptr.h" + > + </File> + </Filter> + <Filter + Name="sandbox" + > + <File + RelativePath="..\src\nt_internals.h" + > + </File> + <File + RelativePath="..\src\resolver.h" + > + </File> + </Filter> + <File + RelativePath=".\service64_resolver.cc" + > + </File> + <File + RelativePath=".\service64_resolver.h" + > + </File> + <File + RelativePath=".\target_code.cc" + > + </File> + <File + RelativePath=".\target_code.h" + > + </File> + <File + RelativePath=".\wow_helper.cc" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> |