1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #ifndef SYZYGY_PE_PE_FILE_H_
16 : #define SYZYGY_PE_PE_FILE_H_
17 :
18 : #include <windows.h>
19 : #include <winnt.h>
20 : #include <map>
21 : #include <set>
22 : #include <string>
23 : #include <vector>
24 :
25 : #include "base/files/file_path.h"
26 : #include "sawbuck/sym_util/types.h"
27 : #include "syzygy/core/address.h"
28 : #include "syzygy/core/address_space.h"
29 : #include "syzygy/core/serialization.h"
30 : #include "syzygy/pe/pe_coff_file.h"
31 :
32 : namespace pe {
33 :
34 : // Traits of the PE address space.
35 : struct PEAddressSpaceTraits {
36 : // Native addresses for PE files: relative virtual addresses (RVAs).
37 : typedef core::RelativeAddress AddressType;
38 :
39 : // Native sizes for PE files.
40 : typedef size_t SizeType;
41 :
42 : // @returns an address different from all valid addresses for the
43 : // specified address type.
44 E : static const AddressType invalid_address() {
45 E : return AddressType::kInvalidAddress;
46 E : }
47 :
48 : // @returns the address at which to insert global headers.
49 E : static const AddressType header_address() {
50 E : return AddressType(0);
51 E : }
52 :
53 : // Return the RVA to which the section will be mapped when the
54 : // program is loaded.
55 : //
56 : // @param header the section header.
57 : // @returns the RVA of the section.
58 E : static AddressType GetSectionAddress(const IMAGE_SECTION_HEADER& header) {
59 E : return AddressType(header.VirtualAddress);
60 E : }
61 :
62 : // Return the number of bytes that will be occupied by the section
63 : // when the program is loaded, including any run-time padding.
64 : //
65 : // @param header the section header.
66 : // @returns the run-time size of the section.
67 E : static SizeType GetSectionSize(const IMAGE_SECTION_HEADER& header) {
68 E : return SizeType(header.Misc.VirtualSize);
69 E : }
70 : };
71 :
72 : // A raw, sparse, representation of a PE file. It offers a view of the
73 : // contents of the file as would be mapped into memory, if the program
74 : // were loaded.
75 : class PEFile : public PECoffFile<PEAddressSpaceTraits> {
76 : public:
77 : struct Signature;
78 :
79 : typedef core::AbsoluteAddress AbsoluteAddress;
80 : typedef core::FileOffsetAddress FileOffsetAddress;
81 : typedef core::RelativeAddress RelativeAddress;
82 :
83 : // A set of locations in the RVA address space where an address is
84 : // present and needs to be relocated.
85 : typedef std::set<RelativeAddress> RelocSet;
86 :
87 : // A map from locations in the RVA address space where an address is
88 : // present and needs to be relocated, to the absolute addresses they
89 : // refer to.
90 : typedef std::map<RelativeAddress, AbsoluteAddress> RelocMap;
91 :
92 : // Information about a single export.
93 : struct ExportInfo;
94 : typedef std::vector<ExportInfo> ExportInfoVector;
95 :
96 : // Information about a single import.
97 : struct ImportInfo;
98 : typedef std::vector<ImportInfo> ImportInfoVector;
99 :
100 : // Information about all imports for a given DLL.
101 : struct ImportDll;
102 : typedef std::vector<ImportDll> ImportDllVector;
103 :
104 : // Allow overloading of the following functions inherited from
105 : // PECoffFile.
106 : using PECoffFile<PEAddressSpaceTraits>::ReadImage;
107 : using PECoffFile<PEAddressSpaceTraits>::ReadImageString;
108 : using PECoffFile<PEAddressSpaceTraits>::GetImageData;
109 : using PECoffFile<PEAddressSpaceTraits>::Contains;
110 : using PECoffFile<PEAddressSpaceTraits>::GetSectionIndex;
111 : using PECoffFile<PEAddressSpaceTraits>::GetSectionHeader;
112 :
113 : // Construct a PEFile object not yet bound to any file.
114 : PEFile();
115 :
116 : // Destroy this PEFile object, invalidating all pointers obtained
117 : // through GetImageData(), or headers returned by corresponding
118 : // accessor methods.
119 : ~PEFile();
120 :
121 : // Read in the image file at @p path, making its data
122 : // available. A PE file reader may only read a single file.
123 : //
124 : // @param path the path to the file to read.
125 : // @returns true on success, false on error.
126 : bool Init(const base::FilePath& path);
127 :
128 : // Retrieve the signature of this PE file. May only be called after
129 : // a file has been read with Init().
130 : //
131 : // @param signature the object to copy the signature to.
132 : void GetSignature(Signature* signature) const;
133 :
134 : // Decode relocation information from the image, inserting the
135 : // results into @p relocs.
136 : //
137 : // TODO(siggi): Consider folding this member into ReadRelocs.
138 : //
139 : // @param relocs the set to which relocations are to be added.
140 : // @returns true on success, false on error.
141 : bool DecodeRelocs(RelocSet* relocs) const;
142 :
143 : // Retrieve relocation target addresses for the specified set of
144 : // relocations.
145 : //
146 : // @param relocs the set of relocations to look up.
147 : // @param reloc_values the map to which relocation--target pairs are
148 : // to be added.
149 : // @returns true on success, false on error.
150 : bool ReadRelocs(const RelocSet& relocs, RelocMap* reloc_values) const;
151 :
152 : // Decode import information from the image.
153 : //
154 : // @param imports where to place the decoded imports.
155 : // @returns true on success, false on error.
156 : bool DecodeImports(ImportDllVector* imports) const;
157 :
158 : // Decode export information from the image.
159 : //
160 : // @param exports where to place the decoded exports.
161 : // @returns true on success, false on error.
162 : bool DecodeExports(ExportInfoVector* exports) const;
163 :
164 : // Translate a relative address to an absolute address, based on the
165 : // preferred loading address of this PE file.
166 : //
167 : // @param rel the address to translate.
168 : // @param abs where to place the resulting address.
169 : // @returns true on success, false on error.
170 : bool Translate(RelativeAddress rel, AbsoluteAddress* abs) const;
171 :
172 : // Translate an absolute address to a relative address, based on the
173 : // preferred loading address of this PE file.
174 : //
175 : // @param abs the address to translate.
176 : // @param rel where to place the resulting address.
177 : // @returns true on success, false on error.
178 : bool Translate(AbsoluteAddress abs, RelativeAddress* rel) const;
179 :
180 : // Translate a file offset present in the on-disk file to the
181 : // relative address it maps to at run-time.
182 : //
183 : // @param offs the file offset to translate.
184 : // @param rel where to place the resulting address.
185 : // @returns true on success, false on error.
186 : bool Translate(FileOffsetAddress offs, RelativeAddress* rel) const;
187 :
188 : // Translate a relative address to the file offset it is mapped from
189 : // in the on-disk file.
190 : //
191 : // @param rel the address to translate.
192 : // @param offs where to place the resulting address.
193 : // @returns true on success, false on error.
194 : bool Translate(RelativeAddress rel, FileOffsetAddress* offs) const;
195 :
196 : // Absolute address wrappers around the same-named methods from
197 : // PECoffFile, which deal with relative addresses. Each of the
198 : // following method is equivalent to applying Translate() to the
199 : // absolute address then calling the corresponding RVA-based method.
200 : //
201 : // @see pe::PECoffFile @{
202 : bool ReadImage(AbsoluteAddress addr, void* data, size_t len) const;
203 : bool ReadImageString(AbsoluteAddress addr, std::string* str) const;
204 : const uint8* GetImageData(AbsoluteAddress addr, size_t len) const;
205 : uint8* GetImageData(AbsoluteAddress addr, size_t len);
206 : bool Contains(AbsoluteAddress addr, size_t len) const;
207 : size_t GetSectionIndex(AbsoluteAddress addr, size_t len) const;
208 : const IMAGE_SECTION_HEADER* GetSectionHeader(AbsoluteAddress addr,
209 : size_t len) const;
210 : // @}
211 :
212 : // Retrieve the index of the first section with the specified name.
213 : //
214 : // @param name the name of the section to look up.
215 : // @returns the index of the section, or kInvalidSection if none is
216 : // found.
217 : size_t GetSectionIndex(const char* name) const;
218 :
219 : // Retrieve a pointer to the header structure of the first section
220 : // with the specified name.
221 : //
222 : // @param name the name of the section to look up.
223 : // @returns a pointer to the header structure of the section, or
224 : // NULL if none is found.
225 : const IMAGE_SECTION_HEADER* GetSectionHeader(const char* name) const;
226 :
227 : // @returns a pointer to the DOS header structure of this PE file.
228 E : const IMAGE_DOS_HEADER* dos_header() const {
229 E : return dos_header_;
230 E : }
231 :
232 : // @returns a pointer to the NT headers structure of this PE file.
233 E : const IMAGE_NT_HEADERS* nt_headers() const {
234 E : return nt_headers_;
235 E : }
236 :
237 : // Subtract the preferred loading address of this PE file from the
238 : // specified displacement.
239 : //
240 : // @param abs_disp the value to translate.
241 : // @returns the new offset, relative to the preferred loading
242 : // address.
243 E : uint32 PEFile::AbsToRelDisplacement(uint32 abs_disp) const {
244 E : return abs_disp - nt_headers_->OptionalHeader.ImageBase;
245 E : }
246 :
247 : private:
248 : // Read all NT headers, including common COFF headers. Insert
249 : // a range covering all headers.
250 : //
251 : // @param file the input file stream.
252 : // @returns true on success, false on error.
253 : bool ReadHeaders(FILE* file);
254 :
255 : const IMAGE_DOS_HEADER* dos_header_;
256 : const IMAGE_NT_HEADERS* nt_headers_;
257 :
258 : DISALLOW_COPY_AND_ASSIGN(PEFile);
259 : };
260 :
261 : // A parsed PE file signature; a signature describes some module. It
262 : // offers access to the exploded components of the PE signature,
263 : // comparison, and serialization.
264 : struct PEFile::Signature {
265 : // Construct a default all-zero signature.
266 E : Signature() : module_size(0), module_time_date_stamp(0), module_checksum(0) {
267 E : }
268 :
269 : // Construct a signature from the specified module information.
270 : //
271 : // @param module_info the module information from which to extract
272 : // signature data.
273 : explicit Signature(const sym_util::ModuleInformation& module_info)
274 : : path(module_info.image_file_name),
275 : base_address(module_info.base_address),
276 : module_size(module_info.module_size),
277 : module_time_date_stamp(module_info.time_date_stamp),
278 E : module_checksum(module_info.image_checksum) {
279 E : }
280 :
281 : // The original module path, kept for convenience. This should
282 : // always be an absolute path.
283 : //
284 : // TODO(chrisha): Check that the path is absolute at all sites where this
285 : // path is used.
286 : std::wstring path;
287 :
288 : // The four signature components.
289 : // @{
290 : // The preferred loading address of the module.
291 : AbsoluteAddress base_address;
292 :
293 : // The on-disk size in bytes of the module file.
294 : size_t module_size;
295 :
296 : // The on-disk modification time of the module file.
297 : uint32 module_time_date_stamp;
298 :
299 : // A 32-bit checksum of the module file.
300 : uint32 module_checksum;
301 : // @}
302 :
303 : // Compare the specified signature with this one. Signatures are
304 : // consistent with one another if their four components match; paths
305 : // may differ.
306 : //
307 : // @param signature the signature to compare to.
308 : // @returns true if the signatures are consistent, false otherwise.
309 : bool IsConsistent(const Signature& signature) const;
310 :
311 : // Compare the specified signature with this one in the same way as
312 : // IsConsistent(), except that in addition signatures may differ.
313 : //
314 : // @param signature the signature to compare to.
315 : // @returns true if the signatures are consistent except possibly
316 : // for the signature, false otherwise.
317 : bool IsConsistentExceptForChecksum(const Signature& signature) const;
318 :
319 : // Compare the specified signature with this one. Signatures are
320 : // equal if their paths are the same and they are consistent.
321 : //
322 : // @param signature the signature to compare to.
323 : // @returns true if the signatures are equal, false otherwise.
324 : // @note We need an equality operator for serialization unittests.
325 E : bool operator==(const Signature& signature) const {
326 E : return path == signature.path && IsConsistent(signature);
327 E : }
328 :
329 : // Serialize this signature to @p out_archive.
330 : //
331 : // @param out_archive the archive to serialize to.
332 : // @returns true on success, false on error.
333 : bool Save(core::OutArchive* out_archive) const;
334 :
335 : // Deserializea a signature from @p in_archive, replacing the
336 : // contents of this structure.
337 : //
338 : // @param in_archive the archive to deserialize from.
339 : // @returns true on success, false on error.
340 : bool Load(core::InArchive* in_archive);
341 : };
342 :
343 : // A structure exposing information about a single export.
344 : struct PEFile::ExportInfo {
345 : // The address of the exported function.
346 : RelativeAddress function;
347 :
348 : // The name of the export, if any.
349 : std::string name;
350 :
351 : // The export forward string, if any.
352 : std::string forward;
353 :
354 : // The export ordinal.
355 : uint16 ordinal;
356 : };
357 :
358 : // A structure exposing information about a single import.
359 : struct PEFile::ImportInfo {
360 : // Construct an ImportInfo structure from its components.
361 : //
362 : // @param h the ordinal hint.
363 : // @param o the function ordinal.
364 : // @param n the function name.
365 : ImportInfo(uint16 h, uint16 o, const char* n)
366 : : hint(h),
367 : ordinal(o),
368 E : function(n) {
369 E : }
370 :
371 : // Construct an ImportInfo structure for a named function with no
372 : // ordinal information.
373 : //
374 : // @param function_name the function name.
375 : explicit ImportInfo(const char* function_name)
376 : : hint(0),
377 : ordinal(0),
378 : function(function_name) {
379 : }
380 :
381 : // Construct an ImportInfo structure for a function referenced by
382 : // ordinal.
383 : //
384 : // @param function_ordinal the function ordinal.
385 : explicit ImportInfo(uint16 function_ordinal)
386 : : hint(0),
387 : ordinal(function_ordinal) {
388 : }
389 :
390 : // Construct a default all-zero ImportInfo structure.
391 E : ImportInfo() : hint(0), ordinal(0) {
392 E : }
393 :
394 : // Compare the specified structure with this one. ImportInfo
395 : // structures are equal if their components are equal.
396 : //
397 : // @param o the structure to compare to.
398 : // @returns true if the signatures are equal, false otherwise.
399 E : bool operator==(const ImportInfo& o) const {
400 E : return hint == o.hint && ordinal == o.ordinal && function == o.function;
401 E : }
402 :
403 : // The loader ordinal hint for this import.
404 : uint16 hint;
405 :
406 : // The ordinal of the function if the function field is empty.
407 : uint16 ordinal;
408 :
409 : // The name of the function, or the empty string for imports by
410 : // ordinal.
411 : std::string function;
412 : };
413 :
414 : // A structure holding information about all imports from a given DLL.
415 : struct PEFile::ImportDll {
416 : // Construct a default empty ImportDll structure.
417 E : ImportDll() {
418 E : memset(&desc, 0, sizeof(desc));
419 E : desc.ForwarderChain = -1;
420 E : }
421 :
422 : // The import descriptor.
423 : IMAGE_IMPORT_DESCRIPTOR desc;
424 :
425 : // Name of the DLL imported.
426 : std::string name;
427 :
428 : // A vector of ImportInfo structures, one for each imported
429 : // function.
430 : ImportInfoVector functions;
431 : };
432 :
433 : } // namespace pe
434 :
435 : #endif // SYZYGY_PE_PE_FILE_H_
|