1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <stdint.h>
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <windows.h>
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome_elf/ntdll_cache.h"
9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)FunctionLookupTable g_ntdll_lookup;
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void InitCache() {
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  HMODULE ntdll_handle = ::GetModuleHandle(L"ntdll.dll");
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // To find the Export Address Table address, we start from the DOS header.
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The module handle is actually the address of the header.
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  IMAGE_DOS_HEADER* dos_header =
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      reinterpret_cast<IMAGE_DOS_HEADER*>(ntdll_handle);
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The e_lfanew is an offset from the DOS header to the NT header. It should
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // never be 0.
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  IMAGE_NT_HEADERS* nt_headers = reinterpret_cast<IMAGE_NT_HEADERS*>(
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ntdll_handle + dos_header->e_lfanew / sizeof(uint32_t));
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // For modules that have an import address table, its offset from the
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // DOS header is stored in the second data directory's VirtualAddress.
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!nt_headers->OptionalHeader.DataDirectory[0].VirtualAddress)
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  BYTE* base_addr = reinterpret_cast<BYTE*>(ntdll_handle);
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  IMAGE_DATA_DIRECTORY* exports_data_dir =
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      &nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  IMAGE_EXPORT_DIRECTORY* exports = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base_addr + exports_data_dir->VirtualAddress);
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  WORD* ordinals = reinterpret_cast<WORD*>(
37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base_addr + exports->AddressOfNameOrdinals);
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DWORD* names = reinterpret_cast<DWORD*>(
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base_addr + exports->AddressOfNames);
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DWORD* funcs = reinterpret_cast<DWORD*>(
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base_addr + exports->AddressOfFunctions);
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int num_entries = exports->NumberOfNames;
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (int i = 0; i < num_entries; i++) {
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    char* name = reinterpret_cast<char*>(base_addr + names[i]);
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    WORD ord =  ordinals[i];
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DWORD func = funcs[ord];
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    FARPROC func_addr = reinterpret_cast<FARPROC>(func + base_addr);
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    g_ntdll_lookup[std::string(name)] = func_addr;
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
52