1 // Copyright 2014 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 #ifndef BASE_WIN_PE_IMAGE_READER_H_ 6 #define BASE_WIN_PE_IMAGE_READER_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 #include <windows.h> 11 12 #include <memory> 13 14 #include "base/base_export.h" 15 16 namespace base { 17 namespace win { 18 19 // Parses headers and various data from a PE image. This parser is safe for use 20 // on untrusted data and works on PE files with different bitness from the 21 // current process. The PeImageReader is initialized after construction by 22 // passing the address and size of a PE file that has been read into memory - 23 // not loaded by the OS as an image. Parsing of a PE file that has been loaded 24 // as an image can be done with PEImage. 25 class BASE_EXPORT PeImageReader { 26 public: 27 enum WordSize { 28 WORD_SIZE_32, 29 WORD_SIZE_64, 30 }; 31 32 // A callback invoked by EnumCertificates once for each attribute certificate 33 // entry in the image's attribute certificate table. |revision| and 34 // |certificate_type| identify the contents of |certificate_data| (which is of 35 // |certificate_data_size| bytes). |context| is the value provided by the 36 // caller to EnumCertificates(). Implementations must return true to continue 37 // the enumeration, or false to abort. 38 using EnumCertificatesCallback = bool (*)(uint16_t revision, 39 uint16_t certificate_type, 40 const uint8_t* certificate_data, 41 size_t certificate_data_size, 42 void* context); 43 44 PeImageReader(); 45 46 PeImageReader(const PeImageReader&) = delete; 47 PeImageReader& operator=(const PeImageReader&) = delete; 48 49 ~PeImageReader(); 50 51 // Returns false if the given data does not appear to be a valid PE image. 52 bool Initialize(const uint8_t* image_data, size_t image_size); 53 54 // Returns the machine word size for the image. 55 WordSize GetWordSize(); 56 57 const IMAGE_DOS_HEADER* GetDosHeader(); 58 const IMAGE_FILE_HEADER* GetCoffFileHeader(); 59 60 // Returns a pointer to the optional header and its size. 61 const uint8_t* GetOptionalHeaderData(size_t* optional_data_size); 62 size_t GetNumberOfSections(); 63 const IMAGE_SECTION_HEADER* GetSectionHeaderAt(size_t index); 64 65 // Returns a pointer to the image's export data (.edata) section and its size, 66 // or nullptr if the section is not present. 67 const uint8_t* GetExportSection(size_t* section_size); 68 69 size_t GetNumberOfDebugEntries(); 70 const IMAGE_DEBUG_DIRECTORY* GetDebugEntry(size_t index, 71 const uint8_t** raw_data, 72 size_t* raw_data_size); 73 74 // Invokes |callback| once per attribute certificate entry. |context| is a 75 // caller-specific value that is passed to |callback|. Returns true if all 76 // certificate entries are visited (even if there are no such entries) and 77 // |callback| returns true for each. Conversely, returns |false| if |callback| 78 // returns false or if the image is malformed in any way. 79 bool EnumCertificates(EnumCertificatesCallback callback, void* context); 80 81 // Returns the size of the image file. 82 DWORD GetSizeOfImage(); 83 84 private: 85 // Bits indicating what portions of the image have been validated. 86 enum ValidationStages { 87 VALID_DOS_HEADER = 1 << 0, 88 VALID_PE_SIGNATURE = 1 << 1, 89 VALID_COFF_FILE_HEADER = 1 << 2, 90 VALID_OPTIONAL_HEADER = 1 << 3, 91 VALID_SECTION_HEADERS = 1 << 4, 92 }; 93 94 // An interface to an image's optional header. 95 class OptionalHeader { 96 public: 97 virtual ~OptionalHeader() = default; 98 99 virtual WordSize GetWordSize() = 0; 100 101 // Returns the offset of the DataDirectory member relative to the start of 102 // the optional header. 103 virtual size_t GetDataDirectoryOffset() = 0; 104 105 // Returns the number of entries in the data directory. 106 virtual DWORD GetDataDirectorySize() = 0; 107 108 // Returns a pointer to the first data directory entry. 109 virtual const IMAGE_DATA_DIRECTORY* GetDataDirectoryEntries() = 0; 110 111 // Returns the size of the image file. 112 virtual DWORD GetSizeOfImage() = 0; 113 }; 114 115 template <class OPTIONAL_HEADER_TYPE> 116 class OptionalHeaderImpl; 117 118 void Clear(); 119 bool ValidateDosHeader(); 120 bool ValidatePeSignature(); 121 bool ValidateCoffFileHeader(); 122 bool ValidateOptionalHeader(); 123 bool ValidateSectionHeaders(); 124 125 // Return a pointer to the first byte of the image's optional header. 126 const uint8_t* GetOptionalHeaderStart(); 127 size_t GetOptionalHeaderSize(); 128 129 // Returns the desired directory entry, or nullptr if |index| is out of 130 // bounds. 131 const IMAGE_DATA_DIRECTORY* GetDataDirectoryEntryAt(size_t index); 132 133 // Returns the header for the section that contains the given address, or 134 // nullptr if the address is out of bounds or the image does not contain the 135 // section. 136 const IMAGE_SECTION_HEADER* FindSectionFromRva(uint32_t relative_address); 137 138 // Returns a pointer to the |data_length| bytes referenced by the |index|'th 139 // data directory entry. 140 const uint8_t* GetImageData(size_t index, size_t* data_length); 141 142 // Populates |structure| with a pointer to a desired structure of type T at 143 // the given offset if the image is sufficiently large to contain it. Returns 144 // false if the structure does not fully fit within the image at the given 145 // offset. 146 template <typename T> GetStructureAt(size_t offset,const T ** structure)147 bool GetStructureAt(size_t offset, const T** structure) { 148 return GetStructureAt(offset, sizeof(**structure), structure); 149 } 150 151 // Populates |structure| with a pointer to a desired structure of type T at 152 // the given offset if the image is sufficiently large to contain 153 // |structure_size| bytes. Returns false if the structure does not fully fit 154 // within the image at the given offset. 155 template <typename T> GetStructureAt(size_t offset,size_t structure_size,const T ** structure)156 bool GetStructureAt(size_t offset, 157 size_t structure_size, 158 const T** structure) { 159 if (offset > image_size_) 160 return false; 161 if (structure_size > image_size_ - offset) 162 return false; 163 *structure = reinterpret_cast<const T*>(image_data_ + offset); 164 return true; 165 } 166 167 const uint8_t* image_data_ = nullptr; 168 size_t image_size_ = 0; 169 uint32_t validation_state_ = 0; 170 std::unique_ptr<OptionalHeader> optional_header_; 171 }; 172 173 } // namespace win 174 } // namespace base 175 176 #endif // BASE_WIN_PE_IMAGE_READER_H_ 177