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