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