Home | History | Annotate | Download | only in chrome_elf
      1 // Copyright 2013 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 #include "chrome_elf/ntdll_cache.h"
      6 
      7 #include <stdint.h>
      8 #include <windows.h>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/win/pe_image.h"
     13 #include "chrome_elf/thunk_getter.h"
     14 #include "sandbox/win/src/interception_internal.h"
     15 #include "sandbox/win/src/internal_types.h"
     16 #include "sandbox/win/src/service_resolver.h"
     17 
     18 FunctionLookupTable g_ntdll_lookup;
     19 
     20 // Allocate storage for thunks in a page of this module to save on doing
     21 // an extra allocation at run time.
     22 #pragma section(".crthunk",read,execute)
     23 __declspec(allocate(".crthunk")) sandbox::ThunkData g_nt_thunk_storage;
     24 
     25 
     26 
     27 namespace {
     28 
     29 bool EnumExportsCallback(const base::win::PEImage& image,
     30                          DWORD ordinal,
     31                          DWORD hint,
     32                          LPCSTR name,
     33                          PVOID function_addr,
     34                          LPCSTR forward,
     35                          PVOID cookie) {
     36   // Our lookup only cares about named functions that are in ntdll, so skip
     37   // unnamed or forwarded exports.
     38   if (name && function_addr)
     39     g_ntdll_lookup[std::string(name)] = function_addr;
     40 
     41   return true;
     42 }
     43 
     44 }  // namespace
     45 
     46 void InitCache() {
     47   HMODULE ntdll_handle = ::GetModuleHandle(L"ntdll.dll");
     48 
     49   base::win::PEImage ntdll_image(ntdll_handle);
     50 
     51   ntdll_image.EnumExports(EnumExportsCallback, NULL);
     52 
     53   // If ntdll has already been patched, don't copy it.
     54   const bool kRelaxed = false;
     55 
     56   // Create a thunk via the appropriate ServiceResolver instance.
     57   scoped_ptr<sandbox::ServiceResolverThunk> thunk(GetThunk(kRelaxed));
     58 
     59   if (thunk.get()) {
     60     BYTE* thunk_storage = reinterpret_cast<BYTE*>(&g_nt_thunk_storage);
     61 
     62     // Mark the thunk storage as readable and writeable, since we
     63     // are ready to write to it.
     64     DWORD old_protect = 0;
     65     if (!::VirtualProtect(&g_nt_thunk_storage,
     66                           sizeof(g_nt_thunk_storage),
     67                           PAGE_EXECUTE_READWRITE,
     68                           &old_protect)) {
     69       return;
     70     }
     71 
     72     size_t storage_used = 0;
     73     NTSTATUS ret = thunk->CopyThunk(::GetModuleHandle(sandbox::kNtdllName),
     74                                     "NtCreateFile",
     75                                     thunk_storage,
     76                                     sizeof(sandbox::ThunkData),
     77                                     &storage_used);
     78 
     79     if (!NT_SUCCESS(ret)) {
     80       memset(&g_nt_thunk_storage, 0, sizeof(g_nt_thunk_storage));
     81     }
     82 
     83     // Ensure that the pointer to the old function can't be changed.
     84     ::VirtualProtect(&g_nt_thunk_storage,
     85                      sizeof(g_nt_thunk_storage),
     86                      PAGE_EXECUTE_READ,
     87                      &old_protect);
     88   }
     89 }
     90