Home | History | Annotate | Download | only in wow_helper
      1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Wow_helper.exe is a simple Win32 64-bit executable designed to help to
      6 // sandbox a 32 bit application running on a 64 bit OS. The basic idea is to
      7 // perform a 64 bit interception of the target process and notify the 32-bit
      8 // broker process whenever a DLL is being loaded. This allows the broker to
      9 // setup the interceptions (32-bit) properly on the target.
     10 
     11 #include <windows.h>
     12 
     13 #include <string>
     14 
     15 #include "sandbox/win/wow_helper/service64_resolver.h"
     16 #include "sandbox/win/wow_helper/target_code.h"
     17 
     18 namespace {
     19 
     20 // Grabbed from base/strings/string_util.h
     21 template <class string_type>
     22 inline typename string_type::value_type* WriteInto(string_type* str,
     23                                                    size_t length_with_null) {
     24   str->reserve(length_with_null);
     25   str->resize(length_with_null - 1);
     26   return &((*str)[0]);
     27 }
     28 
     29 // Grabbed from base/string_util.cc
     30 std::string WideToMultiByte(const std::wstring& wide, UINT code_page) {
     31   if (wide.length() == 0)
     32     return std::string();
     33 
     34   // compute the length of the buffer we'll need
     35   int charcount = WideCharToMultiByte(code_page, 0, wide.c_str(), -1,
     36                                       NULL, 0, NULL, NULL);
     37   if (charcount == 0)
     38     return std::string();
     39 
     40   // convert
     41   std::string mb;
     42   WideCharToMultiByte(code_page, 0, wide.c_str(), -1,
     43                       WriteInto(&mb, charcount), charcount, NULL, NULL);
     44 
     45   return mb;
     46 }
     47 
     48 // Grabbed from base/string_util.cc
     49 std::string WideToUTF8(const std::wstring& wide) {
     50   return WideToMultiByte(wide, CP_UTF8);
     51 }
     52 
     53 }  // namespace
     54 
     55 namespace sandbox {
     56 
     57 // Performs the interception of NtMapViewOfSection on the 64-bit version of
     58 // ntdll.dll. 'thunk' is the buffer on the address space of process 'child',
     59 // that will be used to store the information about the patch.
     60 int PatchNtdll(HANDLE child, void* thunk, size_t thunk_bytes) {
     61   wchar_t* ntdll_name = L"ntdll.dll";
     62   HMODULE ntdll_base = ::GetModuleHandle(ntdll_name);
     63   if (!ntdll_base)
     64     return 100;
     65 
     66   Service64ResolverThunk resolver(child);
     67   size_t used = resolver.GetThunkSize();
     68   char* code = reinterpret_cast<char*>(thunk) + used;
     69   NTSTATUS ret = resolver.Setup(ntdll_base, NULL, "NtMapViewOfSection", NULL,
     70                                 code, thunk, thunk_bytes, NULL);
     71   if (!NT_SUCCESS(ret))
     72     return 101;
     73 
     74   size_t size = reinterpret_cast<char*>(&TargetEnd) -
     75                 reinterpret_cast<char*>(&TargetNtMapViewOfSection);
     76 
     77   if (size + used > thunk_bytes)
     78     return 102;
     79 
     80   SIZE_T written;
     81   if (!::WriteProcessMemory(child, code, &TargetNtMapViewOfSection, size,
     82                             &written))
     83     return 103;
     84 
     85   if (size != written)
     86     return 104;
     87 
     88   return 0;
     89 }
     90 
     91 }  // namespace sandbox
     92 
     93 // We must receive two arguments: the process id of the target to intercept and
     94 // the address of a page of memory on that process that will be used for the
     95 // interception. We receive the address because the broker will cleanup the
     96 // patch when the work is performed.
     97 //
     98 // It should be noted that we don't wait until the real work is done; this
     99 // program quits as soon as the 64-bit interception is performed.
    100 int wWinMain(HINSTANCE, HINSTANCE, wchar_t* command_line, int) {
    101   COMPILE_ASSERT(sizeof(void*) > sizeof(DWORD), unsupported_32_bits);
    102   if (!command_line)
    103     return 1;
    104 
    105   wchar_t* next;
    106   DWORD process_id = wcstoul(command_line, &next, 0);
    107   if (!process_id)
    108     return 2;
    109 
    110   DWORD access = PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE;
    111   HANDLE child = ::OpenProcess(access, FALSE, process_id);
    112   if (!child)
    113     return 3;
    114 
    115   DWORD buffer = wcstoul(next, NULL, 0);
    116   if (!buffer)
    117     return 4;
    118 
    119   void* thunk = reinterpret_cast<void*>(static_cast<ULONG_PTR>(buffer));
    120 
    121   const size_t kPageSize = 4096;
    122   return sandbox::PatchNtdll(child, thunk, kPageSize);
    123 }
    124