15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wow_helper.exe is a simple Win32 64-bit executable designed to help to
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sandbox a 32 bit application running on a 64 bit OS. The basic idea is to
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// perform a 64 bit interception of the target process and notify the 32-bit
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// broker process whenever a DLL is being loaded. This allows the broker to
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// setup the interceptions (32-bit) properly on the target.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/wow_helper/service64_resolver.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/wow_helper/target_code.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Grabbed from base/strings/string_util.h
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class string_type>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline typename string_type::value_type* WriteInto(string_type* str,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   size_t length_with_null) {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  str->reserve(length_with_null);
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  str->resize(length_with_null - 1);
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &((*str)[0]);
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Grabbed from base/string_util.cc
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string WideToMultiByte(const std::wstring& wide, UINT code_page) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (wide.length() == 0)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return std::string();
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compute the length of the buffer we'll need
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int charcount = WideCharToMultiByte(code_page, 0, wide.c_str(), -1,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      NULL, 0, NULL, NULL);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (charcount == 0)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return std::string();
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // convert
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string mb;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WideCharToMultiByte(code_page, 0, wide.c_str(), -1,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      WriteInto(&mb, charcount), charcount, NULL, NULL);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mb;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Grabbed from base/string_util.cc
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string WideToUTF8(const std::wstring& wide) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return WideToMultiByte(wide, CP_UTF8);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sandbox {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Performs the interception of NtMapViewOfSection on the 64-bit version of
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ntdll.dll. 'thunk' is the buffer on the address space of process 'child',
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that will be used to store the information about the patch.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int PatchNtdll(HANDLE child, void* thunk, size_t thunk_bytes) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t* ntdll_name = L"ntdll.dll";
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMODULE ntdll_base = ::GetModuleHandle(ntdll_name);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ntdll_base)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 100;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Service64ResolverThunk resolver(child);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t used = resolver.GetThunkSize();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* code = reinterpret_cast<char*>(thunk) + used;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NTSTATUS ret = resolver.Setup(ntdll_base, NULL, "NtMapViewOfSection", NULL,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                code, thunk, thunk_bytes, NULL);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!NT_SUCCESS(ret))
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 101;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size = reinterpret_cast<char*>(&TargetEnd) -
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                reinterpret_cast<char*>(&TargetNtMapViewOfSection);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size + used > thunk_bytes)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 102;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SIZE_T written;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!::WriteProcessMemory(child, code, &TargetNtMapViewOfSection, size,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            &written))
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 103;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size != written)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 104;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace sandbox
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We must receive two arguments: the process id of the target to intercept and
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the address of a page of memory on that process that will be used for the
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// interception. We receive the address because the broker will cleanup the
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// patch when the work is performed.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It should be noted that we don't wait until the real work is done; this
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// program quits as soon as the 64-bit interception is performed.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int wWinMain(HINSTANCE, HINSTANCE, wchar_t* command_line, int) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMPILE_ASSERT(sizeof(void*) > sizeof(DWORD), unsupported_32_bits);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!command_line)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t* next;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD process_id = wcstoul(command_line, &next, 0);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!process_id)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 2;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD access = PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE child = ::OpenProcess(access, FALSE, process_id);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!child)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 3;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD buffer = wcstoul(next, NULL, 0);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 4;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* thunk = reinterpret_cast<void*>(static_cast<ULONG_PTR>(buffer));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t kPageSize = 4096;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sandbox::PatchNtdll(child, thunk, kPageSize);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
124