xref: /aosp_15_r20/external/cronet/base/win/pe_image_reader.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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