1// Copyright (c) 2010 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// This file was adapted from GreenBorder's Code.
6// To understand what this class is about (for other than well known functions
7// as GetProcAddress), a good starting point is "An In-Depth Look into the
8// Win32 Portable Executable File Format" by Matt Pietrek:
9// http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx
10
11#ifndef BASE_WIN_PE_IMAGE_H_
12#define BASE_WIN_PE_IMAGE_H_
13#pragma once
14
15#include <windows.h>
16#include <DelayIMP.h>
17
18namespace base {
19namespace win {
20
21// This class is a wrapper for the Portable Executable File Format (PE).
22// It's main purpose is to provide an easy way to work with imports and exports
23// from a file, mapped in memory as image.
24class PEImage {
25 public:
26  // Callback to enumerate sections.
27  // cookie is the value passed to the enumerate method.
28  // Returns true to continue the enumeration.
29  typedef bool (*EnumSectionsFunction)(const PEImage &image,
30                                       PIMAGE_SECTION_HEADER header,
31                                       PVOID section_start, DWORD section_size,
32                                       PVOID cookie);
33
34  // Callback to enumerate exports.
35  // function is the actual address of the symbol. If forward is not null, it
36  // contains the dll and symbol to forward this export to. cookie is the value
37  // passed to the enumerate method.
38  // Returns true to continue the enumeration.
39  typedef bool (*EnumExportsFunction)(const PEImage &image, DWORD ordinal,
40                                      DWORD hint, LPCSTR name, PVOID function,
41                                      LPCSTR forward, PVOID cookie);
42
43  // Callback to enumerate import blocks.
44  // name_table and iat point to the imports name table and address table for
45  // this block. cookie is the value passed to the enumerate method.
46  // Returns true to continue the enumeration.
47  typedef bool (*EnumImportChunksFunction)(const PEImage &image, LPCSTR module,
48                                           PIMAGE_THUNK_DATA name_table,
49                                           PIMAGE_THUNK_DATA iat, PVOID cookie);
50
51  // Callback to enumerate imports.
52  // module is the dll that exports this symbol. cookie is the value passed to
53  // the enumerate method.
54  // Returns true to continue the enumeration.
55  typedef bool (*EnumImportsFunction)(const PEImage &image, LPCSTR module,
56                                      DWORD ordinal, LPCSTR name, DWORD hint,
57                                      PIMAGE_THUNK_DATA iat, PVOID cookie);
58
59  // Callback to enumerate dalayed import blocks.
60  // module is the dll that exports this block of symbols. cookie is the value
61  // passed to the enumerate method.
62  // Returns true to continue the enumeration.
63  typedef bool (*EnumDelayImportChunksFunction)(const PEImage &image,
64                                                PImgDelayDescr delay_descriptor,
65                                                LPCSTR module,
66                                                PIMAGE_THUNK_DATA name_table,
67                                                PIMAGE_THUNK_DATA iat,
68                                                PIMAGE_THUNK_DATA bound_iat,
69                                                PIMAGE_THUNK_DATA unload_iat,
70                                                PVOID cookie);
71
72  // Callback to enumerate relocations.
73  // cookie is the value passed to the enumerate method.
74  // Returns true to continue the enumeration.
75  typedef bool (*EnumRelocsFunction)(const PEImage &image, WORD type,
76                                     PVOID address, PVOID cookie);
77
78  explicit PEImage(HMODULE module) : module_(module) {}
79  explicit PEImage(const void* module) {
80    module_ = reinterpret_cast<HMODULE>(const_cast<void*>(module));
81  }
82
83  // Gets the HMODULE for this object.
84  HMODULE module() const;
85
86  // Sets this object's HMODULE.
87  void set_module(HMODULE module);
88
89  // Checks if this symbol is actually an ordinal.
90  static bool IsOrdinal(LPCSTR name);
91
92  // Converts a named symbol to the corresponding ordinal.
93  static WORD ToOrdinal(LPCSTR name);
94
95  // Returns the DOS_HEADER for this PE.
96  PIMAGE_DOS_HEADER GetDosHeader() const;
97
98  // Returns the NT_HEADER for this PE.
99  PIMAGE_NT_HEADERS GetNTHeaders() const;
100
101  // Returns number of sections of this PE.
102  WORD GetNumSections() const;
103
104  // Returns the header for a given section.
105  // returns NULL if there is no such section.
106  PIMAGE_SECTION_HEADER GetSectionHeader(UINT section) const;
107
108  // Returns the size of a given directory entry.
109  DWORD GetImageDirectoryEntrySize(UINT directory) const;
110
111  // Returns the address of a given directory entry.
112  PVOID GetImageDirectoryEntryAddr(UINT directory) const;
113
114  // Returns the section header for a given address.
115  // Use: s = image.GetImageSectionFromAddr(a);
116  // Post: 's' is the section header of the section that contains 'a'
117  //       or NULL if there is no such section.
118  PIMAGE_SECTION_HEADER GetImageSectionFromAddr(PVOID address) const;
119
120  // Returns the section header for a given section.
121  PIMAGE_SECTION_HEADER GetImageSectionHeaderByName(LPCSTR section_name) const;
122
123  // Returns the first block of imports.
124  PIMAGE_IMPORT_DESCRIPTOR GetFirstImportChunk() const;
125
126  // Returns the exports directory.
127  PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const;
128
129  // Returns a given export entry.
130  // Use: e = image.GetExportEntry(f);
131  // Pre: 'f' is either a zero terminated string or ordinal
132  // Post: 'e' is a pointer to the export directory entry
133  //       that contains 'f's export RVA, or NULL if 'f'
134  //       is not exported from this image
135  PDWORD GetExportEntry(LPCSTR name) const;
136
137  // Returns the address for a given exported symbol.
138  // Use: p = image.GetProcAddress(f);
139  // Pre: 'f' is either a zero terminated string or ordinal.
140  // Post: if 'f' is a non-forwarded export from image, 'p' is
141  //       the exported function. If 'f' is a forwarded export
142  //       then p is the special value 0xFFFFFFFF. In this case
143  //       RVAToAddr(*GetExportEntry) can be used to resolve
144  //       the string that describes the forward.
145  FARPROC GetProcAddress(LPCSTR function_name) const;
146
147  // Retrieves the ordinal for a given exported symbol.
148  // Returns true if the symbol was found.
149  bool GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const;
150
151  // Enumerates PE sections.
152  // cookie is a generic cookie to pass to the callback.
153  // Returns true on success.
154  bool EnumSections(EnumSectionsFunction callback, PVOID cookie) const;
155
156  // Enumerates PE exports.
157  // cookie is a generic cookie to pass to the callback.
158  // Returns true on success.
159  bool EnumExports(EnumExportsFunction callback, PVOID cookie) const;
160
161  // Enumerates PE imports.
162  // cookie is a generic cookie to pass to the callback.
163  // Returns true on success.
164  bool EnumAllImports(EnumImportsFunction callback, PVOID cookie) const;
165
166  // Enumerates PE import blocks.
167  // cookie is a generic cookie to pass to the callback.
168  // Returns true on success.
169  bool EnumImportChunks(EnumImportChunksFunction callback, PVOID cookie) const;
170
171  // Enumerates the imports from a single PE import block.
172  // cookie is a generic cookie to pass to the callback.
173  // Returns true on success.
174  bool EnumOneImportChunk(EnumImportsFunction callback, LPCSTR module_name,
175                          PIMAGE_THUNK_DATA name_table, PIMAGE_THUNK_DATA iat,
176                          PVOID cookie) const;
177
178
179  // Enumerates PE delay imports.
180  // cookie is a generic cookie to pass to the callback.
181  // Returns true on success.
182  bool EnumAllDelayImports(EnumImportsFunction callback, PVOID cookie) const;
183
184  // Enumerates PE delay import blocks.
185  // cookie is a generic cookie to pass to the callback.
186  // Returns true on success.
187  bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
188                             PVOID cookie) const;
189
190  // Enumerates imports from a single PE delay import block.
191  // cookie is a generic cookie to pass to the callback.
192  // Returns true on success.
193  bool EnumOneDelayImportChunk(EnumImportsFunction callback,
194                               PImgDelayDescr delay_descriptor,
195                               LPCSTR module_name,
196                               PIMAGE_THUNK_DATA name_table,
197                               PIMAGE_THUNK_DATA iat,
198                               PIMAGE_THUNK_DATA bound_iat,
199                               PIMAGE_THUNK_DATA unload_iat,
200                               PVOID cookie) const;
201
202  // Enumerates PE relocation entries.
203  // cookie is a generic cookie to pass to the callback.
204  // Returns true on success.
205  bool EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const;
206
207  // Verifies the magic values on the PE file.
208  // Returns true if all values are correct.
209  bool VerifyMagic() const;
210
211  // Converts an rva value to the appropriate address.
212  virtual PVOID RVAToAddr(DWORD rva) const;
213
214  // Converts an rva value to an offset on disk.
215  // Returns true on success.
216  bool ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const;
217
218  // Converts an address to an offset on disk.
219  // Returns true on success.
220  bool ImageAddrToOnDiskOffset(LPVOID address, DWORD *on_disk_offset) const;
221
222 private:
223  HMODULE module_;
224};
225
226// This class is an extension to the PEImage class that allows working with PE
227// files mapped as data instead of as image file.
228class PEImageAsData : public PEImage {
229 public:
230  explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {}
231
232  virtual PVOID RVAToAddr(DWORD rva) const;
233};
234
235inline bool PEImage::IsOrdinal(LPCSTR name) {
236#pragma warning(push)
237#pragma warning(disable: 4311)
238  // This cast generates a warning because it is 32 bit specific.
239  return reinterpret_cast<DWORD>(name) <= 0xFFFF;
240#pragma warning(pop)
241}
242
243inline WORD PEImage::ToOrdinal(LPCSTR name) {
244  return reinterpret_cast<WORD>(name);
245}
246
247inline HMODULE PEImage::module() const {
248  return module_;
249}
250
251inline PIMAGE_IMPORT_DESCRIPTOR PEImage::GetFirstImportChunk() const {
252  return reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(
253             GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IMPORT));
254}
255
256inline PIMAGE_EXPORT_DIRECTORY PEImage::GetExportDirectory() const {
257  return reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
258             GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
259}
260
261}  // namespace win
262}  // namespace base
263
264#endif  // BASE_WIN_PE_IMAGE_H_
265