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