• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
EnumExportsCallback(const base::win::PEImage & image,DWORD ordinal,DWORD hint,LPCSTR name,PVOID function_addr,LPCSTR forward,PVOID cookie)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 
InitCache()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