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