xref: /aosp_15_r20/external/cronet/base/win/pe_image_reader.cc (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 #include "base/win/pe_image_reader.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <wintrust.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <memory>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_math.h"
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker namespace base {
16*6777b538SAndroid Build Coastguard Worker namespace win {
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker // A class template of traits pertaining to IMAGE_OPTIONAL_HEADER{32,64}.
19*6777b538SAndroid Build Coastguard Worker template <class HEADER_TYPE>
20*6777b538SAndroid Build Coastguard Worker struct OptionalHeaderTraits {};
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker template <>
23*6777b538SAndroid Build Coastguard Worker struct OptionalHeaderTraits<IMAGE_OPTIONAL_HEADER32> {
24*6777b538SAndroid Build Coastguard Worker   static const PeImageReader::WordSize word_size = PeImageReader::WORD_SIZE_32;
25*6777b538SAndroid Build Coastguard Worker };
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker template <>
28*6777b538SAndroid Build Coastguard Worker struct OptionalHeaderTraits<IMAGE_OPTIONAL_HEADER64> {
29*6777b538SAndroid Build Coastguard Worker   static const PeImageReader::WordSize word_size = PeImageReader::WORD_SIZE_64;
30*6777b538SAndroid Build Coastguard Worker };
31*6777b538SAndroid Build Coastguard Worker 
32*6777b538SAndroid Build Coastguard Worker // A template for type-specific optional header implementations. This, in
33*6777b538SAndroid Build Coastguard Worker // conjunction with the OptionalHeader interface, effectively erases the
34*6777b538SAndroid Build Coastguard Worker // underlying structure type from the point of view of the PeImageReader.
35*6777b538SAndroid Build Coastguard Worker template <class OPTIONAL_HEADER_TYPE>
36*6777b538SAndroid Build Coastguard Worker class PeImageReader::OptionalHeaderImpl : public PeImageReader::OptionalHeader {
37*6777b538SAndroid Build Coastguard Worker  public:
38*6777b538SAndroid Build Coastguard Worker   using TraitsType = OptionalHeaderTraits<OPTIONAL_HEADER_TYPE>;
39*6777b538SAndroid Build Coastguard Worker 
OptionalHeaderImpl(const uint8_t * optional_header_start)40*6777b538SAndroid Build Coastguard Worker   explicit OptionalHeaderImpl(const uint8_t* optional_header_start)
41*6777b538SAndroid Build Coastguard Worker       : optional_header_(reinterpret_cast<const OPTIONAL_HEADER_TYPE*>(
42*6777b538SAndroid Build Coastguard Worker             optional_header_start)) {}
43*6777b538SAndroid Build Coastguard Worker 
44*6777b538SAndroid Build Coastguard Worker   OptionalHeaderImpl(const OptionalHeaderImpl&) = delete;
45*6777b538SAndroid Build Coastguard Worker   OptionalHeaderImpl& operator=(const OptionalHeaderImpl&) = delete;
46*6777b538SAndroid Build Coastguard Worker 
GetWordSize()47*6777b538SAndroid Build Coastguard Worker   WordSize GetWordSize() override { return TraitsType::word_size; }
48*6777b538SAndroid Build Coastguard Worker 
GetDataDirectoryOffset()49*6777b538SAndroid Build Coastguard Worker   size_t GetDataDirectoryOffset() override {
50*6777b538SAndroid Build Coastguard Worker     return offsetof(OPTIONAL_HEADER_TYPE, DataDirectory);
51*6777b538SAndroid Build Coastguard Worker   }
52*6777b538SAndroid Build Coastguard Worker 
GetDataDirectorySize()53*6777b538SAndroid Build Coastguard Worker   DWORD GetDataDirectorySize() override {
54*6777b538SAndroid Build Coastguard Worker     return optional_header_->NumberOfRvaAndSizes;
55*6777b538SAndroid Build Coastguard Worker   }
56*6777b538SAndroid Build Coastguard Worker 
GetDataDirectoryEntries()57*6777b538SAndroid Build Coastguard Worker   const IMAGE_DATA_DIRECTORY* GetDataDirectoryEntries() override {
58*6777b538SAndroid Build Coastguard Worker     return &optional_header_->DataDirectory[0];
59*6777b538SAndroid Build Coastguard Worker   }
60*6777b538SAndroid Build Coastguard Worker 
GetSizeOfImage()61*6777b538SAndroid Build Coastguard Worker   DWORD GetSizeOfImage() override { return optional_header_->SizeOfImage; }
62*6777b538SAndroid Build Coastguard Worker 
63*6777b538SAndroid Build Coastguard Worker  private:
64*6777b538SAndroid Build Coastguard Worker   raw_ptr<const OPTIONAL_HEADER_TYPE> optional_header_;
65*6777b538SAndroid Build Coastguard Worker };
66*6777b538SAndroid Build Coastguard Worker 
PeImageReader()67*6777b538SAndroid Build Coastguard Worker PeImageReader::PeImageReader() {}
68*6777b538SAndroid Build Coastguard Worker 
~PeImageReader()69*6777b538SAndroid Build Coastguard Worker PeImageReader::~PeImageReader() {
70*6777b538SAndroid Build Coastguard Worker   Clear();
71*6777b538SAndroid Build Coastguard Worker }
72*6777b538SAndroid Build Coastguard Worker 
Initialize(span<const uint8_t> image_data)73*6777b538SAndroid Build Coastguard Worker bool PeImageReader::Initialize(span<const uint8_t> image_data) {
74*6777b538SAndroid Build Coastguard Worker   image_data_ = image_data;
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   if (!ValidateDosHeader() || !ValidatePeSignature() ||
77*6777b538SAndroid Build Coastguard Worker       !ValidateCoffFileHeader() || !ValidateOptionalHeader() ||
78*6777b538SAndroid Build Coastguard Worker       !ValidateSectionHeaders()) {
79*6777b538SAndroid Build Coastguard Worker     Clear();
80*6777b538SAndroid Build Coastguard Worker     return false;
81*6777b538SAndroid Build Coastguard Worker   }
82*6777b538SAndroid Build Coastguard Worker 
83*6777b538SAndroid Build Coastguard Worker   return true;
84*6777b538SAndroid Build Coastguard Worker }
85*6777b538SAndroid Build Coastguard Worker 
GetWordSize()86*6777b538SAndroid Build Coastguard Worker PeImageReader::WordSize PeImageReader::GetWordSize() {
87*6777b538SAndroid Build Coastguard Worker   return optional_header_->GetWordSize();
88*6777b538SAndroid Build Coastguard Worker }
89*6777b538SAndroid Build Coastguard Worker 
GetDosHeader()90*6777b538SAndroid Build Coastguard Worker const IMAGE_DOS_HEADER* PeImageReader::GetDosHeader() {
91*6777b538SAndroid Build Coastguard Worker   DCHECK_NE((validation_state_ & VALID_DOS_HEADER), 0U);
92*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<const IMAGE_DOS_HEADER*>(image_data_.data());
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker 
GetCoffFileHeader()95*6777b538SAndroid Build Coastguard Worker const IMAGE_FILE_HEADER* PeImageReader::GetCoffFileHeader() {
96*6777b538SAndroid Build Coastguard Worker   DCHECK_NE((validation_state_ & VALID_COFF_FILE_HEADER), 0U);
97*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<const IMAGE_FILE_HEADER*>(
98*6777b538SAndroid Build Coastguard Worker       image_data_
99*6777b538SAndroid Build Coastguard Worker           .subspan(checked_cast<size_t>(GetDosHeader()->e_lfanew) +
100*6777b538SAndroid Build Coastguard Worker                    sizeof(DWORD))
101*6777b538SAndroid Build Coastguard Worker           .data());
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker 
GetOptionalHeaderData()104*6777b538SAndroid Build Coastguard Worker span<const uint8_t> PeImageReader::GetOptionalHeaderData() {
105*6777b538SAndroid Build Coastguard Worker   return make_span(GetOptionalHeaderStart(), GetOptionalHeaderSize());
106*6777b538SAndroid Build Coastguard Worker }
107*6777b538SAndroid Build Coastguard Worker 
GetNumberOfSections()108*6777b538SAndroid Build Coastguard Worker size_t PeImageReader::GetNumberOfSections() {
109*6777b538SAndroid Build Coastguard Worker   return GetCoffFileHeader()->NumberOfSections;
110*6777b538SAndroid Build Coastguard Worker }
111*6777b538SAndroid Build Coastguard Worker 
GetSectionHeaderAt(size_t index)112*6777b538SAndroid Build Coastguard Worker const IMAGE_SECTION_HEADER* PeImageReader::GetSectionHeaderAt(size_t index) {
113*6777b538SAndroid Build Coastguard Worker   DCHECK_NE((validation_state_ & VALID_SECTION_HEADERS), 0U);
114*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(index, GetNumberOfSections());
115*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<const IMAGE_SECTION_HEADER*>(
116*6777b538SAndroid Build Coastguard Worker       GetOptionalHeaderStart() + GetOptionalHeaderSize() +
117*6777b538SAndroid Build Coastguard Worker       (sizeof(IMAGE_SECTION_HEADER) * index));
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker 
GetExportSection()120*6777b538SAndroid Build Coastguard Worker span<const uint8_t> PeImageReader::GetExportSection() {
121*6777b538SAndroid Build Coastguard Worker   span<const uint8_t> data = GetImageData(IMAGE_DIRECTORY_ENTRY_EXPORT);
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker   // The export section data must be big enough for the export directory.
124*6777b538SAndroid Build Coastguard Worker   if (data.size() < sizeof(IMAGE_EXPORT_DIRECTORY)) {
125*6777b538SAndroid Build Coastguard Worker     return span<const uint8_t>();
126*6777b538SAndroid Build Coastguard Worker   }
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker   return data;
129*6777b538SAndroid Build Coastguard Worker }
130*6777b538SAndroid Build Coastguard Worker 
GetNumberOfDebugEntries()131*6777b538SAndroid Build Coastguard Worker size_t PeImageReader::GetNumberOfDebugEntries() {
132*6777b538SAndroid Build Coastguard Worker   return GetImageData(IMAGE_DIRECTORY_ENTRY_DEBUG).size() /
133*6777b538SAndroid Build Coastguard Worker          sizeof(IMAGE_DEBUG_DIRECTORY);
134*6777b538SAndroid Build Coastguard Worker }
135*6777b538SAndroid Build Coastguard Worker 
GetDebugEntry(size_t index,span<const uint8_t> & raw_data)136*6777b538SAndroid Build Coastguard Worker const IMAGE_DEBUG_DIRECTORY* PeImageReader::GetDebugEntry(
137*6777b538SAndroid Build Coastguard Worker     size_t index,
138*6777b538SAndroid Build Coastguard Worker     span<const uint8_t>& raw_data) {
139*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(index, GetNumberOfDebugEntries());
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker   // Get the debug directory.
142*6777b538SAndroid Build Coastguard Worker   span<const uint8_t> debug_directory_data =
143*6777b538SAndroid Build Coastguard Worker       GetImageData(IMAGE_DIRECTORY_ENTRY_DEBUG);
144*6777b538SAndroid Build Coastguard Worker   if (debug_directory_data.empty()) {
145*6777b538SAndroid Build Coastguard Worker     return nullptr;
146*6777b538SAndroid Build Coastguard Worker   }
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker   const IMAGE_DEBUG_DIRECTORY& entry =
149*6777b538SAndroid Build Coastguard Worker       reinterpret_cast<const IMAGE_DEBUG_DIRECTORY&>(
150*6777b538SAndroid Build Coastguard Worker           debug_directory_data[index * sizeof(IMAGE_DEBUG_DIRECTORY)]);
151*6777b538SAndroid Build Coastguard Worker   const uint8_t* debug_data = nullptr;
152*6777b538SAndroid Build Coastguard Worker   if (GetStructureAt(entry.PointerToRawData, entry.SizeOfData, &debug_data)) {
153*6777b538SAndroid Build Coastguard Worker     raw_data = make_span(debug_data, entry.SizeOfData);
154*6777b538SAndroid Build Coastguard Worker   }
155*6777b538SAndroid Build Coastguard Worker   return &entry;
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker 
EnumCertificates(EnumCertificatesCallback callback,void * context)158*6777b538SAndroid Build Coastguard Worker bool PeImageReader::EnumCertificates(EnumCertificatesCallback callback,
159*6777b538SAndroid Build Coastguard Worker                                      void* context) {
160*6777b538SAndroid Build Coastguard Worker   span<const uint8_t> data = GetImageData(IMAGE_DIRECTORY_ENTRY_SECURITY);
161*6777b538SAndroid Build Coastguard Worker   const size_t kWinCertificateSize = offsetof(WIN_CERTIFICATE, bCertificate);
162*6777b538SAndroid Build Coastguard Worker   while (!data.empty()) {
163*6777b538SAndroid Build Coastguard Worker     const WIN_CERTIFICATE* win_certificate =
164*6777b538SAndroid Build Coastguard Worker         reinterpret_cast<const WIN_CERTIFICATE*>(data.data());
165*6777b538SAndroid Build Coastguard Worker     if (kWinCertificateSize > data.size() ||
166*6777b538SAndroid Build Coastguard Worker         kWinCertificateSize > win_certificate->dwLength ||
167*6777b538SAndroid Build Coastguard Worker         win_certificate->dwLength > data.size()) {
168*6777b538SAndroid Build Coastguard Worker       return false;
169*6777b538SAndroid Build Coastguard Worker     }
170*6777b538SAndroid Build Coastguard Worker     if (!(*callback)(
171*6777b538SAndroid Build Coastguard Worker             win_certificate->wRevision, win_certificate->wCertificateType,
172*6777b538SAndroid Build Coastguard Worker             &win_certificate->bCertificate[0],
173*6777b538SAndroid Build Coastguard Worker             win_certificate->dwLength - kWinCertificateSize, context)) {
174*6777b538SAndroid Build Coastguard Worker       return false;
175*6777b538SAndroid Build Coastguard Worker     }
176*6777b538SAndroid Build Coastguard Worker     size_t padded_length = (win_certificate->dwLength + 7) & ~0x7u;
177*6777b538SAndroid Build Coastguard Worker     if (padded_length > data.size()) {
178*6777b538SAndroid Build Coastguard Worker       return false;
179*6777b538SAndroid Build Coastguard Worker     }
180*6777b538SAndroid Build Coastguard Worker     data = data.subspan(padded_length);
181*6777b538SAndroid Build Coastguard Worker   }
182*6777b538SAndroid Build Coastguard Worker   return true;
183*6777b538SAndroid Build Coastguard Worker }
184*6777b538SAndroid Build Coastguard Worker 
GetSizeOfImage()185*6777b538SAndroid Build Coastguard Worker DWORD PeImageReader::GetSizeOfImage() {
186*6777b538SAndroid Build Coastguard Worker   return optional_header_->GetSizeOfImage();
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker 
Clear()189*6777b538SAndroid Build Coastguard Worker void PeImageReader::Clear() {
190*6777b538SAndroid Build Coastguard Worker   image_data_ = raw_span<const uint8_t>();
191*6777b538SAndroid Build Coastguard Worker   validation_state_ = 0;
192*6777b538SAndroid Build Coastguard Worker   optional_header_.reset();
193*6777b538SAndroid Build Coastguard Worker }
194*6777b538SAndroid Build Coastguard Worker 
ValidateDosHeader()195*6777b538SAndroid Build Coastguard Worker bool PeImageReader::ValidateDosHeader() {
196*6777b538SAndroid Build Coastguard Worker   const IMAGE_DOS_HEADER* dos_header = nullptr;
197*6777b538SAndroid Build Coastguard Worker   if (!GetStructureAt(0, &dos_header) ||
198*6777b538SAndroid Build Coastguard Worker       dos_header->e_magic != IMAGE_DOS_SIGNATURE || dos_header->e_lfanew < 0) {
199*6777b538SAndroid Build Coastguard Worker     return false;
200*6777b538SAndroid Build Coastguard Worker   }
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker   validation_state_ |= VALID_DOS_HEADER;
203*6777b538SAndroid Build Coastguard Worker   return true;
204*6777b538SAndroid Build Coastguard Worker }
205*6777b538SAndroid Build Coastguard Worker 
ValidatePeSignature()206*6777b538SAndroid Build Coastguard Worker bool PeImageReader::ValidatePeSignature() {
207*6777b538SAndroid Build Coastguard Worker   const DWORD* signature = nullptr;
208*6777b538SAndroid Build Coastguard Worker   if (!GetStructureAt(static_cast<size_t>(GetDosHeader()->e_lfanew),
209*6777b538SAndroid Build Coastguard Worker                       &signature) ||
210*6777b538SAndroid Build Coastguard Worker       *signature != IMAGE_NT_SIGNATURE) {
211*6777b538SAndroid Build Coastguard Worker     return false;
212*6777b538SAndroid Build Coastguard Worker   }
213*6777b538SAndroid Build Coastguard Worker 
214*6777b538SAndroid Build Coastguard Worker   validation_state_ |= VALID_PE_SIGNATURE;
215*6777b538SAndroid Build Coastguard Worker   return true;
216*6777b538SAndroid Build Coastguard Worker }
217*6777b538SAndroid Build Coastguard Worker 
ValidateCoffFileHeader()218*6777b538SAndroid Build Coastguard Worker bool PeImageReader::ValidateCoffFileHeader() {
219*6777b538SAndroid Build Coastguard Worker   DCHECK_NE((validation_state_ & VALID_PE_SIGNATURE), 0U);
220*6777b538SAndroid Build Coastguard Worker   const IMAGE_FILE_HEADER* file_header = nullptr;
221*6777b538SAndroid Build Coastguard Worker   if (!GetStructureAt(static_cast<size_t>(GetDosHeader()->e_lfanew) +
222*6777b538SAndroid Build Coastguard Worker                           offsetof(IMAGE_NT_HEADERS32, FileHeader),
223*6777b538SAndroid Build Coastguard Worker                       &file_header)) {
224*6777b538SAndroid Build Coastguard Worker     return false;
225*6777b538SAndroid Build Coastguard Worker   }
226*6777b538SAndroid Build Coastguard Worker 
227*6777b538SAndroid Build Coastguard Worker   validation_state_ |= VALID_COFF_FILE_HEADER;
228*6777b538SAndroid Build Coastguard Worker   return true;
229*6777b538SAndroid Build Coastguard Worker }
230*6777b538SAndroid Build Coastguard Worker 
ValidateOptionalHeader()231*6777b538SAndroid Build Coastguard Worker bool PeImageReader::ValidateOptionalHeader() {
232*6777b538SAndroid Build Coastguard Worker   const IMAGE_FILE_HEADER* file_header = GetCoffFileHeader();
233*6777b538SAndroid Build Coastguard Worker   const size_t optional_header_offset =
234*6777b538SAndroid Build Coastguard Worker       static_cast<size_t>(GetDosHeader()->e_lfanew) +
235*6777b538SAndroid Build Coastguard Worker       offsetof(IMAGE_NT_HEADERS32, OptionalHeader);
236*6777b538SAndroid Build Coastguard Worker   const size_t optional_header_size = file_header->SizeOfOptionalHeader;
237*6777b538SAndroid Build Coastguard Worker   const WORD* optional_header_magic = nullptr;
238*6777b538SAndroid Build Coastguard Worker 
239*6777b538SAndroid Build Coastguard Worker   if (optional_header_size < sizeof(*optional_header_magic) ||
240*6777b538SAndroid Build Coastguard Worker       !GetStructureAt(optional_header_offset, &optional_header_magic)) {
241*6777b538SAndroid Build Coastguard Worker     return false;
242*6777b538SAndroid Build Coastguard Worker   }
243*6777b538SAndroid Build Coastguard Worker 
244*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<OptionalHeader> optional_header;
245*6777b538SAndroid Build Coastguard Worker   if (*optional_header_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
246*6777b538SAndroid Build Coastguard Worker     optional_header =
247*6777b538SAndroid Build Coastguard Worker         std::make_unique<OptionalHeaderImpl<IMAGE_OPTIONAL_HEADER32>>(
248*6777b538SAndroid Build Coastguard Worker             image_data_.subspan(optional_header_offset).data());
249*6777b538SAndroid Build Coastguard Worker   } else if (*optional_header_magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
250*6777b538SAndroid Build Coastguard Worker     optional_header =
251*6777b538SAndroid Build Coastguard Worker         std::make_unique<OptionalHeaderImpl<IMAGE_OPTIONAL_HEADER64>>(
252*6777b538SAndroid Build Coastguard Worker             image_data_.subspan(optional_header_offset).data());
253*6777b538SAndroid Build Coastguard Worker   } else {
254*6777b538SAndroid Build Coastguard Worker     return false;
255*6777b538SAndroid Build Coastguard Worker   }
256*6777b538SAndroid Build Coastguard Worker 
257*6777b538SAndroid Build Coastguard Worker   // Does all of the claimed optional header fit in the image?
258*6777b538SAndroid Build Coastguard Worker   if (optional_header_size > image_data_.size() - optional_header_offset) {
259*6777b538SAndroid Build Coastguard Worker     return false;
260*6777b538SAndroid Build Coastguard Worker   }
261*6777b538SAndroid Build Coastguard Worker 
262*6777b538SAndroid Build Coastguard Worker   // Is the claimed optional header big enough for everything but the dir?
263*6777b538SAndroid Build Coastguard Worker   if (optional_header->GetDataDirectoryOffset() > optional_header_size)
264*6777b538SAndroid Build Coastguard Worker     return false;
265*6777b538SAndroid Build Coastguard Worker 
266*6777b538SAndroid Build Coastguard Worker   // Is there enough room for all of the claimed directory entries?
267*6777b538SAndroid Build Coastguard Worker   if (optional_header->GetDataDirectorySize() >
268*6777b538SAndroid Build Coastguard Worker       ((optional_header_size - optional_header->GetDataDirectoryOffset()) /
269*6777b538SAndroid Build Coastguard Worker        sizeof(IMAGE_DATA_DIRECTORY))) {
270*6777b538SAndroid Build Coastguard Worker     return false;
271*6777b538SAndroid Build Coastguard Worker   }
272*6777b538SAndroid Build Coastguard Worker 
273*6777b538SAndroid Build Coastguard Worker   optional_header_.swap(optional_header);
274*6777b538SAndroid Build Coastguard Worker   validation_state_ |= VALID_OPTIONAL_HEADER;
275*6777b538SAndroid Build Coastguard Worker   return true;
276*6777b538SAndroid Build Coastguard Worker }
277*6777b538SAndroid Build Coastguard Worker 
ValidateSectionHeaders()278*6777b538SAndroid Build Coastguard Worker bool PeImageReader::ValidateSectionHeaders() {
279*6777b538SAndroid Build Coastguard Worker   const uint8_t* first_section_header =
280*6777b538SAndroid Build Coastguard Worker       GetOptionalHeaderStart() + GetOptionalHeaderSize();
281*6777b538SAndroid Build Coastguard Worker   const size_t number_of_sections = GetNumberOfSections();
282*6777b538SAndroid Build Coastguard Worker 
283*6777b538SAndroid Build Coastguard Worker   // Do all section headers fit in the image?
284*6777b538SAndroid Build Coastguard Worker   if (!GetStructureAt(
285*6777b538SAndroid Build Coastguard Worker           static_cast<size_t>(first_section_header - image_data_.data()),
286*6777b538SAndroid Build Coastguard Worker           number_of_sections * sizeof(IMAGE_SECTION_HEADER),
287*6777b538SAndroid Build Coastguard Worker           &first_section_header)) {
288*6777b538SAndroid Build Coastguard Worker     return false;
289*6777b538SAndroid Build Coastguard Worker   }
290*6777b538SAndroid Build Coastguard Worker 
291*6777b538SAndroid Build Coastguard Worker   validation_state_ |= VALID_SECTION_HEADERS;
292*6777b538SAndroid Build Coastguard Worker   return true;
293*6777b538SAndroid Build Coastguard Worker }
294*6777b538SAndroid Build Coastguard Worker 
GetOptionalHeaderStart()295*6777b538SAndroid Build Coastguard Worker const uint8_t* PeImageReader::GetOptionalHeaderStart() {
296*6777b538SAndroid Build Coastguard Worker   DCHECK_NE((validation_state_ & VALID_OPTIONAL_HEADER), 0U);
297*6777b538SAndroid Build Coastguard Worker   return image_data_
298*6777b538SAndroid Build Coastguard Worker       .subspan(checked_cast<size_t>(GetDosHeader()->e_lfanew) +
299*6777b538SAndroid Build Coastguard Worker                offsetof(IMAGE_NT_HEADERS32, OptionalHeader))
300*6777b538SAndroid Build Coastguard Worker       .data();
301*6777b538SAndroid Build Coastguard Worker }
302*6777b538SAndroid Build Coastguard Worker 
GetOptionalHeaderSize()303*6777b538SAndroid Build Coastguard Worker size_t PeImageReader::GetOptionalHeaderSize() {
304*6777b538SAndroid Build Coastguard Worker   return GetCoffFileHeader()->SizeOfOptionalHeader;
305*6777b538SAndroid Build Coastguard Worker }
306*6777b538SAndroid Build Coastguard Worker 
GetDataDirectoryEntryAt(size_t index)307*6777b538SAndroid Build Coastguard Worker const IMAGE_DATA_DIRECTORY* PeImageReader::GetDataDirectoryEntryAt(
308*6777b538SAndroid Build Coastguard Worker     size_t index) {
309*6777b538SAndroid Build Coastguard Worker   DCHECK_NE((validation_state_ & VALID_OPTIONAL_HEADER), 0U);
310*6777b538SAndroid Build Coastguard Worker   if (index >= optional_header_->GetDataDirectorySize())
311*6777b538SAndroid Build Coastguard Worker     return nullptr;
312*6777b538SAndroid Build Coastguard Worker   return &optional_header_->GetDataDirectoryEntries()[index];
313*6777b538SAndroid Build Coastguard Worker }
314*6777b538SAndroid Build Coastguard Worker 
FindSectionFromRva(uint32_t relative_address)315*6777b538SAndroid Build Coastguard Worker const IMAGE_SECTION_HEADER* PeImageReader::FindSectionFromRva(
316*6777b538SAndroid Build Coastguard Worker     uint32_t relative_address) {
317*6777b538SAndroid Build Coastguard Worker   const size_t number_of_sections = GetNumberOfSections();
318*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < number_of_sections; ++i) {
319*6777b538SAndroid Build Coastguard Worker     const IMAGE_SECTION_HEADER* section_header = GetSectionHeaderAt(i);
320*6777b538SAndroid Build Coastguard Worker     // Is the raw data present in the image? If no, optimistically keep looking.
321*6777b538SAndroid Build Coastguard Worker     const uint8_t* section_data = nullptr;
322*6777b538SAndroid Build Coastguard Worker     if (!GetStructureAt(section_header->PointerToRawData,
323*6777b538SAndroid Build Coastguard Worker                         section_header->SizeOfRawData, &section_data)) {
324*6777b538SAndroid Build Coastguard Worker       continue;
325*6777b538SAndroid Build Coastguard Worker     }
326*6777b538SAndroid Build Coastguard Worker     // Does the RVA lie on or after this section's start when mapped? If no,
327*6777b538SAndroid Build Coastguard Worker     // bail.
328*6777b538SAndroid Build Coastguard Worker     if (section_header->VirtualAddress > relative_address)
329*6777b538SAndroid Build Coastguard Worker       break;
330*6777b538SAndroid Build Coastguard Worker     // Does the RVA lie within the section when mapped? If no, keep looking.
331*6777b538SAndroid Build Coastguard Worker     size_t address_offset = relative_address - section_header->VirtualAddress;
332*6777b538SAndroid Build Coastguard Worker     if (address_offset > section_header->Misc.VirtualSize)
333*6777b538SAndroid Build Coastguard Worker       continue;
334*6777b538SAndroid Build Coastguard Worker     // We have a winner.
335*6777b538SAndroid Build Coastguard Worker     return section_header;
336*6777b538SAndroid Build Coastguard Worker   }
337*6777b538SAndroid Build Coastguard Worker   return nullptr;
338*6777b538SAndroid Build Coastguard Worker }
339*6777b538SAndroid Build Coastguard Worker 
GetImageData(size_t index)340*6777b538SAndroid Build Coastguard Worker span<const uint8_t> PeImageReader::GetImageData(size_t index) {
341*6777b538SAndroid Build Coastguard Worker   // Get the requested directory entry.
342*6777b538SAndroid Build Coastguard Worker   const IMAGE_DATA_DIRECTORY* entry = GetDataDirectoryEntryAt(index);
343*6777b538SAndroid Build Coastguard Worker   if (!entry)
344*6777b538SAndroid Build Coastguard Worker     return span<const uint8_t>();
345*6777b538SAndroid Build Coastguard Worker 
346*6777b538SAndroid Build Coastguard Worker   // The entry for the certificate table is special in that its address is a
347*6777b538SAndroid Build Coastguard Worker   // file pointer rather than an RVA.
348*6777b538SAndroid Build Coastguard Worker   if (index == IMAGE_DIRECTORY_ENTRY_SECURITY) {
349*6777b538SAndroid Build Coastguard Worker     // Does the data fit within the file.
350*6777b538SAndroid Build Coastguard Worker     if (entry->VirtualAddress > image_data_.size() ||
351*6777b538SAndroid Build Coastguard Worker         image_data_.size() - entry->VirtualAddress < entry->Size) {
352*6777b538SAndroid Build Coastguard Worker       return span<const uint8_t>();
353*6777b538SAndroid Build Coastguard Worker     }
354*6777b538SAndroid Build Coastguard Worker     return image_data_.subspan(entry->VirtualAddress, entry->Size);
355*6777b538SAndroid Build Coastguard Worker   }
356*6777b538SAndroid Build Coastguard Worker 
357*6777b538SAndroid Build Coastguard Worker   // Find the section containing the data.
358*6777b538SAndroid Build Coastguard Worker   const IMAGE_SECTION_HEADER* header =
359*6777b538SAndroid Build Coastguard Worker       FindSectionFromRva(entry->VirtualAddress);
360*6777b538SAndroid Build Coastguard Worker   if (!header)
361*6777b538SAndroid Build Coastguard Worker     return span<const uint8_t>();
362*6777b538SAndroid Build Coastguard Worker 
363*6777b538SAndroid Build Coastguard Worker   // Does the data fit within the section when mapped?
364*6777b538SAndroid Build Coastguard Worker   size_t data_offset = entry->VirtualAddress - header->VirtualAddress;
365*6777b538SAndroid Build Coastguard Worker   if (entry->Size > (header->Misc.VirtualSize - data_offset))
366*6777b538SAndroid Build Coastguard Worker     return span<const uint8_t>();
367*6777b538SAndroid Build Coastguard Worker 
368*6777b538SAndroid Build Coastguard Worker   // Is the data entirely present on disk (if not it's zeroed out when loaded)?
369*6777b538SAndroid Build Coastguard Worker   if (data_offset >= header->SizeOfRawData ||
370*6777b538SAndroid Build Coastguard Worker       header->SizeOfRawData - data_offset < entry->Size) {
371*6777b538SAndroid Build Coastguard Worker     return span<const uint8_t>();
372*6777b538SAndroid Build Coastguard Worker   }
373*6777b538SAndroid Build Coastguard Worker 
374*6777b538SAndroid Build Coastguard Worker   return image_data_.subspan(header->PointerToRawData + data_offset,
375*6777b538SAndroid Build Coastguard Worker                              entry->Size);
376*6777b538SAndroid Build Coastguard Worker }
377*6777b538SAndroid Build Coastguard Worker 
378*6777b538SAndroid Build Coastguard Worker }  // namespace win
379*6777b538SAndroid Build Coastguard Worker }  // namespace base
380