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
14 #include <windows.h>
15
16 #include <stdint.h>
17
18 #if defined(_WIN32_WINNT_WIN8)
19 // The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
20 #undef FACILITY_VISUALCPP
21 #endif
22 #include <DelayIMP.h>
23
24 namespace base {
25 namespace win {
26
27 // This class is a wrapper for the Portable Executable File Format (PE).
28 // Its main purpose is to provide an easy way to work with imports and exports
29 // from a file, mapped in memory as image.
30 class PEImage {
31 public:
32 // Callback to enumerate sections.
33 // cookie is the value passed to the enumerate method.
34 // Returns true to continue the enumeration.
35 using EnumSectionsFunction =
36 bool (*)(const PEImage&, PIMAGE_SECTION_HEADER, PVOID, DWORD, PVOID);
37
38 // Callback to enumerate exports.
39 // function is the actual address of the symbol. If forward is not null, it
40 // contains the dll and symbol to forward this export to. cookie is the value
41 // passed to the enumerate method.
42 // Returns true to continue the enumeration.
43 using EnumExportsFunction =
44 bool (*)(const PEImage&, DWORD, DWORD, LPCSTR, PVOID, LPCSTR, PVOID);
45
46 // Callback to enumerate import blocks.
47 // name_table and iat point to the imports name table and address table for
48 // this block. cookie is the value passed to the enumerate method.
49 // Returns true to continue the enumeration.
50 using EnumImportChunksFunction = bool (*)(const PEImage&,
51 LPCSTR,
52 PIMAGE_THUNK_DATA,
53 PIMAGE_THUNK_DATA,
54 PVOID);
55
56 // Callback to enumerate imports.
57 // module is the dll that exports this symbol. cookie is the value passed to
58 // the enumerate method.
59 // Returns true to continue the enumeration.
60 using EnumImportsFunction = bool (*)(const PEImage&,
61 LPCSTR,
62 DWORD,
63 LPCSTR,
64 DWORD,
65 PIMAGE_THUNK_DATA,
66 PVOID);
67
68 // Callback to enumerate delayed import blocks.
69 // module is the dll that exports this block of symbols. cookie is the value
70 // passed to the enumerate method.
71 // Returns true to continue the enumeration.
72 using EnumDelayImportChunksFunction = bool (*)(const PEImage&,
73 PImgDelayDescr,
74 LPCSTR,
75 PIMAGE_THUNK_DATA,
76 PIMAGE_THUNK_DATA,
77 PVOID);
78
79 // Callback to enumerate relocations.
80 // cookie is the value passed to the enumerate method.
81 // Returns true to continue the enumeration.
82 using EnumRelocsFunction = bool (*)(const PEImage&, WORD, PVOID, PVOID);
83
PEImage(HMODULE module)84 explicit PEImage(HMODULE module) : module_(module) {}
PEImage(const void * module)85 explicit PEImage(const void* module) {
86 module_ = reinterpret_cast<HMODULE>(const_cast<void*>(module));
87 }
88
89 virtual ~PEImage() = default;
90
91 // Gets the HMODULE for this object.
92 HMODULE module() const;
93
94 // Sets this object's HMODULE.
95 void set_module(HMODULE module);
96
97 // Checks if this symbol is actually an ordinal.
98 static bool IsOrdinal(LPCSTR name);
99
100 // Converts a named symbol to the corresponding ordinal.
101 static WORD ToOrdinal(LPCSTR name);
102
103 // Returns the DOS_HEADER for this PE.
104 PIMAGE_DOS_HEADER GetDosHeader() const;
105
106 // Returns the NT_HEADER for this PE.
107 PIMAGE_NT_HEADERS GetNTHeaders() const;
108
109 // Returns number of sections of this PE.
110 WORD GetNumSections() const;
111
112 // Returns the header for a given section.
113 // returns NULL if there is no such section.
114 PIMAGE_SECTION_HEADER GetSectionHeader(UINT section) const;
115
116 // Returns the size of a given directory entry or 0 if |directory| is out of
117 // bounds.
118 DWORD GetImageDirectoryEntrySize(UINT directory) const;
119
120 // Returns the address of a given directory entry or NULL if |directory| is
121 // out of bounds.
122 PVOID GetImageDirectoryEntryAddr(UINT directory) const;
123
124 // Returns the section header for a given address.
125 // Use: s = image.GetImageSectionFromAddr(a);
126 // Post: 's' is the section header of the section that contains 'a'
127 // or NULL if there is no such section.
128 PIMAGE_SECTION_HEADER GetImageSectionFromAddr(PVOID address) const;
129
130 // Returns the section header for a given section.
131 PIMAGE_SECTION_HEADER GetImageSectionHeaderByName(LPCSTR section_name) const;
132
133 // Returns the first block of imports.
134 PIMAGE_IMPORT_DESCRIPTOR GetFirstImportChunk() const;
135
136 // Returns the exports directory.
137 PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const;
138
139 // Retrieves the contents of the image's CodeView debug entry, returning true
140 // if such an entry is found and is within a section mapped into the current
141 // process's memory. |guid|, |age|, and |pdb_filename| are each optional and
142 // may be NULL. |pdb_filename_length| is mandatory if |pdb_filename| is not
143 // NULL, as the latter is populated with a direct reference to a string in the
144 // image that is is not guaranteed to be terminated (note: informal
145 // documentation indicates that it should be terminated, but the data is
146 // untrusted). Furthermore, owing to its nature of being a string in the
147 // image, it is only valid while the image is mapped into the process, and the
148 // caller is not responsible for freeing it. |pdb_filename_length| is
149 // populated with the string length of |pdb_filename| (not including a
150 // terminator) and must be used rather than relying on |pdb_filename| being
151 // properly terminated.
152 bool GetDebugId(LPGUID guid,
153 LPDWORD age,
154 LPCSTR* pdb_filename,
155 size_t* pdb_filename_length) const;
156
157 // Returns a given export entry.
158 // Use: e = image.GetExportEntry(f);
159 // Pre: 'f' is either a zero terminated string or ordinal
160 // Post: 'e' is a pointer to the export directory entry
161 // that contains 'f's export RVA, or NULL if 'f'
162 // is not exported from this image
163 PDWORD GetExportEntry(LPCSTR name) const;
164
165 // Returns the address for a given exported symbol.
166 // Use: p = image.GetProcAddress(f);
167 // Pre: 'f' is either a zero terminated string or ordinal.
168 // Post: if 'f' is a non-forwarded export from image, 'p' is
169 // the exported function. If 'f' is a forwarded export
170 // then p is the special value -1. In this case
171 // RVAToAddr(*GetExportEntry) can be used to resolve
172 // the string that describes the forward.
173 FARPROC GetProcAddress(LPCSTR function_name) const;
174
175 // Retrieves the ordinal for a given exported symbol.
176 // Returns true if the symbol was found.
177 bool GetProcOrdinal(LPCSTR function_name, WORD* ordinal) const;
178
179 // Enumerates PE sections.
180 // cookie is a generic cookie to pass to the callback.
181 // Returns true on success.
182 bool EnumSections(EnumSectionsFunction callback, PVOID cookie) const;
183
184 // Enumerates PE exports.
185 // cookie is a generic cookie to pass to the callback.
186 // Returns true on success.
187 bool EnumExports(EnumExportsFunction callback, PVOID cookie) const;
188
189 // Enumerates PE imports.
190 // cookie is a generic cookie to pass to the callback.
191 // Returns true on success.
192 // Use |target_module_name| to ensure the callback is only invoked for the
193 // specified module.
194 bool EnumAllImports(EnumImportsFunction callback,
195 PVOID cookie,
196 LPCSTR target_module_name) const;
197
198 // Enumerates PE import blocks.
199 // cookie is a generic cookie to pass to the callback.
200 // Returns true on success.
201 // Use |target_module_name| to ensure the callback is only invoked for the
202 // specified module.
203 bool EnumImportChunks(EnumImportChunksFunction callback,
204 PVOID cookie,
205 LPCSTR target_module_name) const;
206
207 // Enumerates the imports from a single PE import block.
208 // cookie is a generic cookie to pass to the callback.
209 // Returns true on success.
210 bool EnumOneImportChunk(EnumImportsFunction callback,
211 LPCSTR module_name,
212 PIMAGE_THUNK_DATA name_table,
213 PIMAGE_THUNK_DATA iat,
214 PVOID cookie) const;
215
216 // Enumerates PE delay imports.
217 // cookie is a generic cookie to pass to the callback.
218 // Returns true on success.
219 // Use |target_module_name| to ensure the callback is only invoked for the
220 // specified module. If this parameter is non-null then all delayloaded
221 // imports are resolved when the target module is found.
222 bool EnumAllDelayImports(EnumImportsFunction callback,
223 PVOID cookie,
224 LPCSTR target_module_name) const;
225
226 // Enumerates PE delay import blocks.
227 // cookie is a generic cookie to pass to the callback.
228 // Returns true on success.
229 // Use |target_module_name| to ensure the callback is only invoked for the
230 // specified module. If this parameter is non-null then all delayloaded
231 // imports are resolved when the target module is found.
232 bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
233 PVOID cookie,
234 LPCSTR target_module_name) const;
235
236 // Enumerates imports from a single PE delay import block.
237 // cookie is a generic cookie to pass to the callback.
238 // Returns true on success.
239 bool EnumOneDelayImportChunk(EnumImportsFunction callback,
240 PImgDelayDescr delay_descriptor,
241 LPCSTR module_name,
242 PIMAGE_THUNK_DATA name_table,
243 PIMAGE_THUNK_DATA iat,
244 PVOID cookie) const;
245
246 // Enumerates PE relocation entries.
247 // cookie is a generic cookie to pass to the callback.
248 // Returns true on success.
249 bool EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const;
250
251 // Verifies the magic values on the PE file.
252 // Returns true if all values are correct.
253 bool VerifyMagic() const;
254
255 // Converts an rva value to the appropriate address.
256 virtual PVOID RVAToAddr(uintptr_t rva) const;
257
258 // Converts an rva value to an offset on disk.
259 // Returns true on success.
260 bool ImageRVAToOnDiskOffset(uintptr_t rva, DWORD* on_disk_offset) const;
261
262 // Converts an address to an offset on disk.
263 // Returns true on success.
264 bool ImageAddrToOnDiskOffset(LPVOID address, DWORD* on_disk_offset) const;
265
266 private:
267 // Returns a pointer to a data directory, or NULL if |directory| is out of
268 // range.
269 const IMAGE_DATA_DIRECTORY* GetDataDirectory(UINT directory) const;
270
271 HMODULE module_;
272 };
273
274 // This class is an extension to the PEImage class that allows working with PE
275 // files mapped as data instead of as image file.
276 class PEImageAsData : public PEImage {
277 public:
PEImageAsData(HMODULE hModule)278 explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {}
279
280 PVOID RVAToAddr(uintptr_t rva) const override;
281 };
282
IsOrdinal(LPCSTR name)283 inline bool PEImage::IsOrdinal(LPCSTR name) {
284 return reinterpret_cast<uintptr_t>(name) <= 0xFFFF;
285 }
286
ToOrdinal(LPCSTR name)287 inline WORD PEImage::ToOrdinal(LPCSTR name) {
288 return static_cast<WORD>(reinterpret_cast<intptr_t>(name));
289 }
290
module()291 inline HMODULE PEImage::module() const {
292 return module_;
293 }
294
GetFirstImportChunk()295 inline PIMAGE_IMPORT_DESCRIPTOR PEImage::GetFirstImportChunk() const {
296 return reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(
297 GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IMPORT));
298 }
299
GetExportDirectory()300 inline PIMAGE_EXPORT_DIRECTORY PEImage::GetExportDirectory() const {
301 return reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
302 GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
303 }
304
305 } // namespace win
306 } // namespace base
307
308 #endif // BASE_WIN_PE_IMAGE_H_
309