1 | use alloc::vec::Vec; |
2 | use core::fmt::Debug; |
3 | use core::{mem, str}; |
4 | |
5 | use core::convert::TryInto; |
6 | |
7 | use crate::read::coff::{CoffCommon, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SymbolTable}; |
8 | use crate::read::{ |
9 | self, Architecture, ComdatKind, Error, Export, FileFlags, Import, NoDynamicRelocationIterator, |
10 | Object, ObjectComdat, ObjectKind, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, |
11 | }; |
12 | use crate::{pe, ByteString, Bytes, CodeView, LittleEndian as LE, Pod, SubArchitecture, U32}; |
13 | |
14 | use super::{ |
15 | DataDirectories, ExportTable, ImageThunkData, ImportTable, PeSection, PeSectionIterator, |
16 | PeSegment, PeSegmentIterator, RichHeaderInfo, SectionTable, |
17 | }; |
18 | |
19 | /// A PE32 (32-bit) image file. |
20 | /// |
21 | /// This is a file that starts with [`pe::ImageNtHeaders32`], and corresponds |
22 | /// to [`crate::FileKind::Pe32`]. |
23 | pub type PeFile32<'data, R = &'data [u8]> = PeFile<'data, pe::ImageNtHeaders32, R>; |
24 | /// A PE32+ (64-bit) image file. |
25 | /// |
26 | /// This is a file that starts with [`pe::ImageNtHeaders64`], and corresponds |
27 | /// to [`crate::FileKind::Pe64`]. |
28 | pub type PeFile64<'data, R = &'data [u8]> = PeFile<'data, pe::ImageNtHeaders64, R>; |
29 | |
30 | /// A PE image file. |
31 | /// |
32 | /// Most functionality is provided by the [`Object`] trait implementation. |
33 | #[derive (Debug)] |
34 | pub struct PeFile<'data, Pe, R = &'data [u8]> |
35 | where |
36 | Pe: ImageNtHeaders, |
37 | R: ReadRef<'data>, |
38 | { |
39 | pub(super) dos_header: &'data pe::ImageDosHeader, |
40 | pub(super) nt_headers: &'data Pe, |
41 | pub(super) data_directories: DataDirectories<'data>, |
42 | pub(super) common: CoffCommon<'data, R>, |
43 | pub(super) data: R, |
44 | } |
45 | |
46 | impl<'data, Pe, R> PeFile<'data, Pe, R> |
47 | where |
48 | Pe: ImageNtHeaders, |
49 | R: ReadRef<'data>, |
50 | { |
51 | /// Parse the raw PE file data. |
52 | pub fn parse(data: R) -> Result<Self> { |
53 | let dos_header = pe::ImageDosHeader::parse(data)?; |
54 | let mut offset = dos_header.nt_headers_offset().into(); |
55 | let (nt_headers, data_directories) = Pe::parse(data, &mut offset)?; |
56 | let sections = nt_headers.sections(data, offset)?; |
57 | let coff_symbols = nt_headers.symbols(data); |
58 | let image_base = nt_headers.optional_header().image_base(); |
59 | |
60 | Ok(PeFile { |
61 | dos_header, |
62 | nt_headers, |
63 | data_directories, |
64 | common: CoffCommon { |
65 | sections, |
66 | // The PE file format deprecates the COFF symbol table (https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#coff-file-header-object-and-image) |
67 | // We do not want to prevent parsing the rest of the PE file for a corrupt COFF header, but rather return an empty symbol table |
68 | symbols: coff_symbols.unwrap_or_default(), |
69 | image_base, |
70 | }, |
71 | data, |
72 | }) |
73 | } |
74 | |
75 | /// Returns this binary data. |
76 | pub fn data(&self) -> R { |
77 | self.data |
78 | } |
79 | |
80 | /// Return the DOS header of this file. |
81 | pub fn dos_header(&self) -> &'data pe::ImageDosHeader { |
82 | self.dos_header |
83 | } |
84 | |
85 | /// Return the NT Headers of this file. |
86 | pub fn nt_headers(&self) -> &'data Pe { |
87 | self.nt_headers |
88 | } |
89 | |
90 | /// Returns information about the rich header of this file (if any). |
91 | pub fn rich_header_info(&self) -> Option<RichHeaderInfo<'_>> { |
92 | RichHeaderInfo::parse(self.data, self.dos_header.nt_headers_offset().into()) |
93 | } |
94 | |
95 | /// Returns the section table of this binary. |
96 | pub fn section_table(&self) -> SectionTable<'data> { |
97 | self.common.sections |
98 | } |
99 | |
100 | /// Returns the data directories of this file. |
101 | pub fn data_directories(&self) -> DataDirectories<'data> { |
102 | self.data_directories |
103 | } |
104 | |
105 | /// Returns the data directory at the given index. |
106 | pub fn data_directory(&self, id: usize) -> Option<&'data pe::ImageDataDirectory> { |
107 | self.data_directories.get(id) |
108 | } |
109 | |
110 | /// Returns the export table of this file. |
111 | /// |
112 | /// The export table is located using the data directory. |
113 | pub fn export_table(&self) -> Result<Option<ExportTable<'data>>> { |
114 | self.data_directories |
115 | .export_table(self.data, &self.common.sections) |
116 | } |
117 | |
118 | /// Returns the import table of this file. |
119 | /// |
120 | /// The import table is located using the data directory. |
121 | pub fn import_table(&self) -> Result<Option<ImportTable<'data>>> { |
122 | self.data_directories |
123 | .import_table(self.data, &self.common.sections) |
124 | } |
125 | |
126 | pub(super) fn section_alignment(&self) -> u64 { |
127 | u64::from(self.nt_headers.optional_header().section_alignment()) |
128 | } |
129 | } |
130 | |
131 | impl<'data, Pe, R> read::private::Sealed for PeFile<'data, Pe, R> |
132 | where |
133 | Pe: ImageNtHeaders, |
134 | R: ReadRef<'data>, |
135 | { |
136 | } |
137 | |
138 | impl<'data, 'file, Pe, R> Object<'data, 'file> for PeFile<'data, Pe, R> |
139 | where |
140 | 'data: 'file, |
141 | Pe: ImageNtHeaders, |
142 | R: 'file + ReadRef<'data>, |
143 | { |
144 | type Segment = PeSegment<'data, 'file, Pe, R>; |
145 | type SegmentIterator = PeSegmentIterator<'data, 'file, Pe, R>; |
146 | type Section = PeSection<'data, 'file, Pe, R>; |
147 | type SectionIterator = PeSectionIterator<'data, 'file, Pe, R>; |
148 | type Comdat = PeComdat<'data, 'file, Pe, R>; |
149 | type ComdatIterator = PeComdatIterator<'data, 'file, Pe, R>; |
150 | type Symbol = CoffSymbol<'data, 'file, R>; |
151 | type SymbolIterator = CoffSymbolIterator<'data, 'file, R>; |
152 | type SymbolTable = CoffSymbolTable<'data, 'file, R>; |
153 | type DynamicRelocationIterator = NoDynamicRelocationIterator; |
154 | |
155 | fn architecture(&self) -> Architecture { |
156 | match self.nt_headers.file_header().machine.get(LE) { |
157 | pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm, |
158 | pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64, |
159 | pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386, |
160 | pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64, |
161 | _ => Architecture::Unknown, |
162 | } |
163 | } |
164 | |
165 | fn sub_architecture(&self) -> Option<SubArchitecture> { |
166 | match self.nt_headers.file_header().machine.get(LE) { |
167 | pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC), |
168 | _ => None, |
169 | } |
170 | } |
171 | |
172 | #[inline ] |
173 | fn is_little_endian(&self) -> bool { |
174 | // Only little endian is supported. |
175 | true |
176 | } |
177 | |
178 | #[inline ] |
179 | fn is_64(&self) -> bool { |
180 | self.nt_headers.is_type_64() |
181 | } |
182 | |
183 | fn kind(&self) -> ObjectKind { |
184 | let characteristics = self.nt_headers.file_header().characteristics.get(LE); |
185 | if characteristics & pe::IMAGE_FILE_DLL != 0 { |
186 | ObjectKind::Dynamic |
187 | } else if characteristics & pe::IMAGE_FILE_SYSTEM != 0 { |
188 | ObjectKind::Unknown |
189 | } else { |
190 | ObjectKind::Executable |
191 | } |
192 | } |
193 | |
194 | fn segments(&'file self) -> PeSegmentIterator<'data, 'file, Pe, R> { |
195 | PeSegmentIterator { |
196 | file: self, |
197 | iter: self.common.sections.iter(), |
198 | } |
199 | } |
200 | |
201 | fn section_by_name_bytes( |
202 | &'file self, |
203 | section_name: &[u8], |
204 | ) -> Option<PeSection<'data, 'file, Pe, R>> { |
205 | self.common |
206 | .sections |
207 | .section_by_name(self.common.symbols.strings(), section_name) |
208 | .map(|(index, section)| PeSection { |
209 | file: self, |
210 | index: SectionIndex(index), |
211 | section, |
212 | }) |
213 | } |
214 | |
215 | fn section_by_index( |
216 | &'file self, |
217 | index: SectionIndex, |
218 | ) -> Result<PeSection<'data, 'file, Pe, R>> { |
219 | let section = self.common.sections.section(index.0)?; |
220 | Ok(PeSection { |
221 | file: self, |
222 | index, |
223 | section, |
224 | }) |
225 | } |
226 | |
227 | fn sections(&'file self) -> PeSectionIterator<'data, 'file, Pe, R> { |
228 | PeSectionIterator { |
229 | file: self, |
230 | iter: self.common.sections.iter().enumerate(), |
231 | } |
232 | } |
233 | |
234 | fn comdats(&'file self) -> PeComdatIterator<'data, 'file, Pe, R> { |
235 | PeComdatIterator { file: self } |
236 | } |
237 | |
238 | fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<CoffSymbol<'data, 'file, R>> { |
239 | let symbol = self.common.symbols.symbol(index.0)?; |
240 | Ok(CoffSymbol { |
241 | file: &self.common, |
242 | index, |
243 | symbol, |
244 | }) |
245 | } |
246 | |
247 | fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R> { |
248 | CoffSymbolIterator { |
249 | file: &self.common, |
250 | index: 0, |
251 | } |
252 | } |
253 | |
254 | fn symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R>> { |
255 | Some(CoffSymbolTable { file: &self.common }) |
256 | } |
257 | |
258 | fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R> { |
259 | CoffSymbolIterator { |
260 | file: &self.common, |
261 | // Hack: don't return any. |
262 | index: self.common.symbols.len(), |
263 | } |
264 | } |
265 | |
266 | fn dynamic_symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R>> { |
267 | None |
268 | } |
269 | |
270 | fn dynamic_relocations(&'file self) -> Option<NoDynamicRelocationIterator> { |
271 | None |
272 | } |
273 | |
274 | fn imports(&self) -> Result<Vec<Import<'data>>> { |
275 | let mut imports = Vec::new(); |
276 | if let Some(import_table) = self.import_table()? { |
277 | let mut import_descs = import_table.descriptors()?; |
278 | while let Some(import_desc) = import_descs.next()? { |
279 | let library = import_table.name(import_desc.name.get(LE))?; |
280 | let mut first_thunk = import_desc.original_first_thunk.get(LE); |
281 | if first_thunk == 0 { |
282 | first_thunk = import_desc.first_thunk.get(LE); |
283 | } |
284 | let mut thunks = import_table.thunks(first_thunk)?; |
285 | while let Some(thunk) = thunks.next::<Pe>()? { |
286 | if !thunk.is_ordinal() { |
287 | let (_hint, name) = import_table.hint_name(thunk.address())?; |
288 | imports.push(Import { |
289 | library: ByteString(library), |
290 | name: ByteString(name), |
291 | }); |
292 | } |
293 | } |
294 | } |
295 | } |
296 | Ok(imports) |
297 | } |
298 | |
299 | fn exports(&self) -> Result<Vec<Export<'data>>> { |
300 | let mut exports = Vec::new(); |
301 | if let Some(export_table) = self.export_table()? { |
302 | for (name_pointer, address_index) in export_table.name_iter() { |
303 | let name = export_table.name_from_pointer(name_pointer)?; |
304 | let address = export_table.address_by_index(address_index.into())?; |
305 | if !export_table.is_forward(address) { |
306 | exports.push(Export { |
307 | name: ByteString(name), |
308 | address: self.common.image_base.wrapping_add(address.into()), |
309 | }) |
310 | } |
311 | } |
312 | } |
313 | Ok(exports) |
314 | } |
315 | |
316 | fn pdb_info(&self) -> Result<Option<CodeView<'_>>> { |
317 | let data_dir = match self.data_directory(pe::IMAGE_DIRECTORY_ENTRY_DEBUG) { |
318 | Some(data_dir) => data_dir, |
319 | None => return Ok(None), |
320 | }; |
321 | let debug_data = data_dir.data(self.data, &self.common.sections).map(Bytes)?; |
322 | let debug_data_size = data_dir.size.get(LE) as usize; |
323 | |
324 | let count = debug_data_size / mem::size_of::<pe::ImageDebugDirectory>(); |
325 | let rem = debug_data_size % mem::size_of::<pe::ImageDebugDirectory>(); |
326 | if rem != 0 || count < 1 { |
327 | return Err(Error("Invalid PE debug dir size" )); |
328 | } |
329 | |
330 | let debug_dirs = debug_data |
331 | .read_slice_at::<pe::ImageDebugDirectory>(0, count) |
332 | .read_error("Invalid PE debug dir size" )?; |
333 | |
334 | for debug_dir in debug_dirs { |
335 | if debug_dir.typ.get(LE) != pe::IMAGE_DEBUG_TYPE_CODEVIEW { |
336 | continue; |
337 | } |
338 | |
339 | let info = self |
340 | .data |
341 | .read_slice_at::<u8>( |
342 | debug_dir.pointer_to_raw_data.get(LE) as u64, |
343 | debug_dir.size_of_data.get(LE) as usize, |
344 | ) |
345 | .read_error("Invalid CodeView Info address" )?; |
346 | |
347 | let mut info = Bytes(info); |
348 | |
349 | let sig = info |
350 | .read_bytes(4) |
351 | .read_error("Invalid CodeView signature" )?; |
352 | if sig.0 != b"RSDS" { |
353 | continue; |
354 | } |
355 | |
356 | let guid: [u8; 16] = info |
357 | .read_bytes(16) |
358 | .read_error("Invalid CodeView GUID" )? |
359 | .0 |
360 | .try_into() |
361 | .unwrap(); |
362 | |
363 | let age = info.read::<U32<LE>>().read_error("Invalid CodeView Age" )?; |
364 | |
365 | let path = info |
366 | .read_string() |
367 | .read_error("Invalid CodeView file path" )?; |
368 | |
369 | return Ok(Some(CodeView { |
370 | path: ByteString(path), |
371 | guid, |
372 | age: age.get(LE), |
373 | })); |
374 | } |
375 | Ok(None) |
376 | } |
377 | |
378 | fn has_debug_symbols(&self) -> bool { |
379 | self.section_by_name(".debug_info" ).is_some() |
380 | } |
381 | |
382 | fn relative_address_base(&self) -> u64 { |
383 | self.common.image_base |
384 | } |
385 | |
386 | fn entry(&self) -> u64 { |
387 | u64::from(self.nt_headers.optional_header().address_of_entry_point()) |
388 | .wrapping_add(self.common.image_base) |
389 | } |
390 | |
391 | fn flags(&self) -> FileFlags { |
392 | FileFlags::Coff { |
393 | characteristics: self.nt_headers.file_header().characteristics.get(LE), |
394 | } |
395 | } |
396 | } |
397 | |
398 | /// An iterator for the COMDAT section groups in a [`PeFile32`]. |
399 | pub type PeComdatIterator32<'data, 'file, R = &'data [u8]> = |
400 | PeComdatIterator<'data, 'file, pe::ImageNtHeaders32, R>; |
401 | /// An iterator for the COMDAT section groups in a [`PeFile64`]. |
402 | pub type PeComdatIterator64<'data, 'file, R = &'data [u8]> = |
403 | PeComdatIterator<'data, 'file, pe::ImageNtHeaders64, R>; |
404 | |
405 | /// An iterator for the COMDAT section groups in a [`PeFile`]. |
406 | /// |
407 | /// This is a stub that doesn't implement any functionality. |
408 | #[derive (Debug)] |
409 | pub struct PeComdatIterator<'data, 'file, Pe, R = &'data [u8]> |
410 | where |
411 | Pe: ImageNtHeaders, |
412 | R: ReadRef<'data>, |
413 | { |
414 | #[allow (unused)] |
415 | file: &'file PeFile<'data, Pe, R>, |
416 | } |
417 | |
418 | impl<'data, 'file, Pe, R> Iterator for PeComdatIterator<'data, 'file, Pe, R> |
419 | where |
420 | Pe: ImageNtHeaders, |
421 | R: ReadRef<'data>, |
422 | { |
423 | type Item = PeComdat<'data, 'file, Pe, R>; |
424 | |
425 | #[inline ] |
426 | fn next(&mut self) -> Option<Self::Item> { |
427 | None |
428 | } |
429 | } |
430 | |
431 | /// A COMDAT section group in a [`PeFile32`]. |
432 | pub type PeComdat32<'data, 'file, R = &'data [u8]> = |
433 | PeComdat<'data, 'file, pe::ImageNtHeaders32, R>; |
434 | /// A COMDAT section group in a [`PeFile64`]. |
435 | pub type PeComdat64<'data, 'file, R = &'data [u8]> = |
436 | PeComdat<'data, 'file, pe::ImageNtHeaders64, R>; |
437 | |
438 | /// A COMDAT section group in a [`PeFile`]. |
439 | /// |
440 | /// This is a stub that doesn't implement any functionality. |
441 | #[derive (Debug)] |
442 | pub struct PeComdat<'data, 'file, Pe, R = &'data [u8]> |
443 | where |
444 | Pe: ImageNtHeaders, |
445 | R: ReadRef<'data>, |
446 | { |
447 | #[allow (unused)] |
448 | file: &'file PeFile<'data, Pe, R>, |
449 | } |
450 | |
451 | impl<'data, 'file, Pe, R> read::private::Sealed for PeComdat<'data, 'file, Pe, R> |
452 | where |
453 | Pe: ImageNtHeaders, |
454 | R: ReadRef<'data>, |
455 | { |
456 | } |
457 | |
458 | impl<'data, 'file, Pe, R> ObjectComdat<'data> for PeComdat<'data, 'file, Pe, R> |
459 | where |
460 | Pe: ImageNtHeaders, |
461 | R: ReadRef<'data>, |
462 | { |
463 | type SectionIterator = PeComdatSectionIterator<'data, 'file, Pe, R>; |
464 | |
465 | #[inline ] |
466 | fn kind(&self) -> ComdatKind { |
467 | unreachable!(); |
468 | } |
469 | |
470 | #[inline ] |
471 | fn symbol(&self) -> SymbolIndex { |
472 | unreachable!(); |
473 | } |
474 | |
475 | #[inline ] |
476 | fn name_bytes(&self) -> Result<&[u8]> { |
477 | unreachable!(); |
478 | } |
479 | |
480 | #[inline ] |
481 | fn name(&self) -> Result<&str> { |
482 | unreachable!(); |
483 | } |
484 | |
485 | #[inline ] |
486 | fn sections(&self) -> Self::SectionIterator { |
487 | unreachable!(); |
488 | } |
489 | } |
490 | |
491 | /// An iterator for the sections in a COMDAT section group in a [`PeFile32`]. |
492 | pub type PeComdatSectionIterator32<'data, 'file, R = &'data [u8]> = |
493 | PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>; |
494 | /// An iterator for the sections in a COMDAT section group in a [`PeFile64`]. |
495 | pub type PeComdatSectionIterator64<'data, 'file, R = &'data [u8]> = |
496 | PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>; |
497 | |
498 | /// An iterator for the sections in a COMDAT section group in a [`PeFile`]. |
499 | /// |
500 | /// This is a stub that doesn't implement any functionality. |
501 | #[derive (Debug)] |
502 | pub struct PeComdatSectionIterator<'data, 'file, Pe, R = &'data [u8]> |
503 | where |
504 | Pe: ImageNtHeaders, |
505 | R: ReadRef<'data>, |
506 | { |
507 | #[allow (unused)] |
508 | file: &'file PeFile<'data, Pe, R>, |
509 | } |
510 | |
511 | impl<'data, 'file, Pe, R> Iterator for PeComdatSectionIterator<'data, 'file, Pe, R> |
512 | where |
513 | Pe: ImageNtHeaders, |
514 | R: ReadRef<'data>, |
515 | { |
516 | type Item = SectionIndex; |
517 | |
518 | fn next(&mut self) -> Option<Self::Item> { |
519 | None |
520 | } |
521 | } |
522 | |
523 | impl pe::ImageDosHeader { |
524 | /// Read the DOS header. |
525 | /// |
526 | /// Also checks that the `e_magic` field in the header is valid. |
527 | pub fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> { |
528 | // DOS header comes first. |
529 | let dos_header: &ImageDosHeader = dataResult<&ImageDosHeader, ()> |
530 | .read_at::<pe::ImageDosHeader>(offset:0) |
531 | .read_error("Invalid DOS header size or alignment" )?; |
532 | if dos_header.e_magic.get(LE) != pe::IMAGE_DOS_SIGNATURE { |
533 | return Err(Error("Invalid DOS magic" )); |
534 | } |
535 | Ok(dos_header) |
536 | } |
537 | |
538 | /// Return the file offset of the nt_headers. |
539 | #[inline ] |
540 | pub fn nt_headers_offset(&self) -> u32 { |
541 | self.e_lfanew.get(LE) |
542 | } |
543 | } |
544 | |
545 | /// Find the optional header and read its `magic` field. |
546 | /// |
547 | /// It can be useful to know this magic value before trying to |
548 | /// fully parse the NT headers. |
549 | pub fn optional_header_magic<'data, R: ReadRef<'data>>(data: R) -> Result<u16> { |
550 | let dos_header: &ImageDosHeader = pe::ImageDosHeader::parse(data)?; |
551 | // NT headers are at an offset specified in the DOS header. |
552 | let offset: u64 = dos_header.nt_headers_offset().into(); |
553 | // It doesn't matter which NT header type is used for the purpose |
554 | // of reading the optional header magic. |
555 | let nt_headers: &ImageNtHeaders32 = dataResult<&ImageNtHeaders32, …> |
556 | .read_at::<pe::ImageNtHeaders32>(offset) |
557 | .read_error("Invalid NT headers offset, size, or alignment" )?; |
558 | if nt_headers.signature() != pe::IMAGE_NT_SIGNATURE { |
559 | return Err(Error("Invalid PE magic" )); |
560 | } |
561 | Ok(nt_headers.optional_header().magic()) |
562 | } |
563 | |
564 | /// A trait for generic access to [`pe::ImageNtHeaders32`] and [`pe::ImageNtHeaders64`]. |
565 | #[allow (missing_docs)] |
566 | pub trait ImageNtHeaders: Debug + Pod { |
567 | type ImageOptionalHeader: ImageOptionalHeader; |
568 | type ImageThunkData: ImageThunkData; |
569 | |
570 | /// Return true if this type is a 64-bit header. |
571 | /// |
572 | /// This is a property of the type, not a value in the header data. |
573 | fn is_type_64(&self) -> bool; |
574 | |
575 | /// Return true if the magic field in the optional header is valid. |
576 | fn is_valid_optional_magic(&self) -> bool; |
577 | |
578 | /// Return the signature |
579 | fn signature(&self) -> u32; |
580 | |
581 | /// Return the file header. |
582 | fn file_header(&self) -> &pe::ImageFileHeader; |
583 | |
584 | /// Return the optional header. |
585 | fn optional_header(&self) -> &Self::ImageOptionalHeader; |
586 | |
587 | // Provided methods. |
588 | |
589 | /// Read the NT headers, including the data directories. |
590 | /// |
591 | /// `data` must be for the entire file. |
592 | /// |
593 | /// `offset` must be headers offset, which can be obtained from [`pe::ImageDosHeader::nt_headers_offset`]. |
594 | /// It is updated to point after the optional header, which is where the section headers are located. |
595 | /// |
596 | /// Also checks that the `signature` and `magic` fields in the headers are valid. |
597 | fn parse<'data, R: ReadRef<'data>>( |
598 | data: R, |
599 | offset: &mut u64, |
600 | ) -> read::Result<(&'data Self, DataDirectories<'data>)> { |
601 | // Note that this does not include the data directories in the optional header. |
602 | let nt_headers = data |
603 | .read::<Self>(offset) |
604 | .read_error("Invalid PE headers offset or size" )?; |
605 | if nt_headers.signature() != pe::IMAGE_NT_SIGNATURE { |
606 | return Err(Error("Invalid PE magic" )); |
607 | } |
608 | if !nt_headers.is_valid_optional_magic() { |
609 | return Err(Error("Invalid PE optional header magic" )); |
610 | } |
611 | |
612 | // Read the rest of the optional header, and then read the data directories from that. |
613 | let optional_data_size = |
614 | u64::from(nt_headers.file_header().size_of_optional_header.get(LE)) |
615 | .checked_sub(mem::size_of::<Self::ImageOptionalHeader>() as u64) |
616 | .read_error("PE optional header size is too small" )?; |
617 | let optional_data = data |
618 | .read_bytes(offset, optional_data_size) |
619 | .read_error("Invalid PE optional header size" )?; |
620 | let data_directories = DataDirectories::parse( |
621 | optional_data, |
622 | nt_headers.optional_header().number_of_rva_and_sizes(), |
623 | )?; |
624 | |
625 | Ok((nt_headers, data_directories)) |
626 | } |
627 | |
628 | /// Read the section table. |
629 | /// |
630 | /// `data` must be for the entire file. |
631 | /// `offset` must be after the optional file header. |
632 | #[inline ] |
633 | fn sections<'data, R: ReadRef<'data>>( |
634 | &self, |
635 | data: R, |
636 | offset: u64, |
637 | ) -> read::Result<SectionTable<'data>> { |
638 | SectionTable::parse(self.file_header(), data, offset) |
639 | } |
640 | |
641 | /// Read the COFF symbol table and string table. |
642 | /// |
643 | /// `data` must be the entire file data. |
644 | #[inline ] |
645 | fn symbols<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<SymbolTable<'data, R>> { |
646 | SymbolTable::parse(self.file_header(), data) |
647 | } |
648 | } |
649 | |
650 | /// A trait for generic access to [`pe::ImageOptionalHeader32`] and [`pe::ImageOptionalHeader64`]. |
651 | #[allow (missing_docs)] |
652 | pub trait ImageOptionalHeader: Debug + Pod { |
653 | // Standard fields. |
654 | fn magic(&self) -> u16; |
655 | fn major_linker_version(&self) -> u8; |
656 | fn minor_linker_version(&self) -> u8; |
657 | fn size_of_code(&self) -> u32; |
658 | fn size_of_initialized_data(&self) -> u32; |
659 | fn size_of_uninitialized_data(&self) -> u32; |
660 | fn address_of_entry_point(&self) -> u32; |
661 | fn base_of_code(&self) -> u32; |
662 | fn base_of_data(&self) -> Option<u32>; |
663 | |
664 | // NT additional fields. |
665 | fn image_base(&self) -> u64; |
666 | fn section_alignment(&self) -> u32; |
667 | fn file_alignment(&self) -> u32; |
668 | fn major_operating_system_version(&self) -> u16; |
669 | fn minor_operating_system_version(&self) -> u16; |
670 | fn major_image_version(&self) -> u16; |
671 | fn minor_image_version(&self) -> u16; |
672 | fn major_subsystem_version(&self) -> u16; |
673 | fn minor_subsystem_version(&self) -> u16; |
674 | fn win32_version_value(&self) -> u32; |
675 | fn size_of_image(&self) -> u32; |
676 | fn size_of_headers(&self) -> u32; |
677 | fn check_sum(&self) -> u32; |
678 | fn subsystem(&self) -> u16; |
679 | fn dll_characteristics(&self) -> u16; |
680 | fn size_of_stack_reserve(&self) -> u64; |
681 | fn size_of_stack_commit(&self) -> u64; |
682 | fn size_of_heap_reserve(&self) -> u64; |
683 | fn size_of_heap_commit(&self) -> u64; |
684 | fn loader_flags(&self) -> u32; |
685 | fn number_of_rva_and_sizes(&self) -> u32; |
686 | } |
687 | |
688 | impl ImageNtHeaders for pe::ImageNtHeaders32 { |
689 | type ImageOptionalHeader = pe::ImageOptionalHeader32; |
690 | type ImageThunkData = pe::ImageThunkData32; |
691 | |
692 | #[inline ] |
693 | fn is_type_64(&self) -> bool { |
694 | false |
695 | } |
696 | |
697 | #[inline ] |
698 | fn is_valid_optional_magic(&self) -> bool { |
699 | self.optional_header.magic.get(LE) == pe::IMAGE_NT_OPTIONAL_HDR32_MAGIC |
700 | } |
701 | |
702 | #[inline ] |
703 | fn signature(&self) -> u32 { |
704 | self.signature.get(LE) |
705 | } |
706 | |
707 | #[inline ] |
708 | fn file_header(&self) -> &pe::ImageFileHeader { |
709 | &self.file_header |
710 | } |
711 | |
712 | #[inline ] |
713 | fn optional_header(&self) -> &Self::ImageOptionalHeader { |
714 | &self.optional_header |
715 | } |
716 | } |
717 | |
718 | impl ImageOptionalHeader for pe::ImageOptionalHeader32 { |
719 | #[inline ] |
720 | fn magic(&self) -> u16 { |
721 | self.magic.get(LE) |
722 | } |
723 | |
724 | #[inline ] |
725 | fn major_linker_version(&self) -> u8 { |
726 | self.major_linker_version |
727 | } |
728 | |
729 | #[inline ] |
730 | fn minor_linker_version(&self) -> u8 { |
731 | self.minor_linker_version |
732 | } |
733 | |
734 | #[inline ] |
735 | fn size_of_code(&self) -> u32 { |
736 | self.size_of_code.get(LE) |
737 | } |
738 | |
739 | #[inline ] |
740 | fn size_of_initialized_data(&self) -> u32 { |
741 | self.size_of_initialized_data.get(LE) |
742 | } |
743 | |
744 | #[inline ] |
745 | fn size_of_uninitialized_data(&self) -> u32 { |
746 | self.size_of_uninitialized_data.get(LE) |
747 | } |
748 | |
749 | #[inline ] |
750 | fn address_of_entry_point(&self) -> u32 { |
751 | self.address_of_entry_point.get(LE) |
752 | } |
753 | |
754 | #[inline ] |
755 | fn base_of_code(&self) -> u32 { |
756 | self.base_of_code.get(LE) |
757 | } |
758 | |
759 | #[inline ] |
760 | fn base_of_data(&self) -> Option<u32> { |
761 | Some(self.base_of_data.get(LE)) |
762 | } |
763 | |
764 | #[inline ] |
765 | fn image_base(&self) -> u64 { |
766 | self.image_base.get(LE).into() |
767 | } |
768 | |
769 | #[inline ] |
770 | fn section_alignment(&self) -> u32 { |
771 | self.section_alignment.get(LE) |
772 | } |
773 | |
774 | #[inline ] |
775 | fn file_alignment(&self) -> u32 { |
776 | self.file_alignment.get(LE) |
777 | } |
778 | |
779 | #[inline ] |
780 | fn major_operating_system_version(&self) -> u16 { |
781 | self.major_operating_system_version.get(LE) |
782 | } |
783 | |
784 | #[inline ] |
785 | fn minor_operating_system_version(&self) -> u16 { |
786 | self.minor_operating_system_version.get(LE) |
787 | } |
788 | |
789 | #[inline ] |
790 | fn major_image_version(&self) -> u16 { |
791 | self.major_image_version.get(LE) |
792 | } |
793 | |
794 | #[inline ] |
795 | fn minor_image_version(&self) -> u16 { |
796 | self.minor_image_version.get(LE) |
797 | } |
798 | |
799 | #[inline ] |
800 | fn major_subsystem_version(&self) -> u16 { |
801 | self.major_subsystem_version.get(LE) |
802 | } |
803 | |
804 | #[inline ] |
805 | fn minor_subsystem_version(&self) -> u16 { |
806 | self.minor_subsystem_version.get(LE) |
807 | } |
808 | |
809 | #[inline ] |
810 | fn win32_version_value(&self) -> u32 { |
811 | self.win32_version_value.get(LE) |
812 | } |
813 | |
814 | #[inline ] |
815 | fn size_of_image(&self) -> u32 { |
816 | self.size_of_image.get(LE) |
817 | } |
818 | |
819 | #[inline ] |
820 | fn size_of_headers(&self) -> u32 { |
821 | self.size_of_headers.get(LE) |
822 | } |
823 | |
824 | #[inline ] |
825 | fn check_sum(&self) -> u32 { |
826 | self.check_sum.get(LE) |
827 | } |
828 | |
829 | #[inline ] |
830 | fn subsystem(&self) -> u16 { |
831 | self.subsystem.get(LE) |
832 | } |
833 | |
834 | #[inline ] |
835 | fn dll_characteristics(&self) -> u16 { |
836 | self.dll_characteristics.get(LE) |
837 | } |
838 | |
839 | #[inline ] |
840 | fn size_of_stack_reserve(&self) -> u64 { |
841 | self.size_of_stack_reserve.get(LE).into() |
842 | } |
843 | |
844 | #[inline ] |
845 | fn size_of_stack_commit(&self) -> u64 { |
846 | self.size_of_stack_commit.get(LE).into() |
847 | } |
848 | |
849 | #[inline ] |
850 | fn size_of_heap_reserve(&self) -> u64 { |
851 | self.size_of_heap_reserve.get(LE).into() |
852 | } |
853 | |
854 | #[inline ] |
855 | fn size_of_heap_commit(&self) -> u64 { |
856 | self.size_of_heap_commit.get(LE).into() |
857 | } |
858 | |
859 | #[inline ] |
860 | fn loader_flags(&self) -> u32 { |
861 | self.loader_flags.get(LE) |
862 | } |
863 | |
864 | #[inline ] |
865 | fn number_of_rva_and_sizes(&self) -> u32 { |
866 | self.number_of_rva_and_sizes.get(LE) |
867 | } |
868 | } |
869 | |
870 | impl ImageNtHeaders for pe::ImageNtHeaders64 { |
871 | type ImageOptionalHeader = pe::ImageOptionalHeader64; |
872 | type ImageThunkData = pe::ImageThunkData64; |
873 | |
874 | #[inline ] |
875 | fn is_type_64(&self) -> bool { |
876 | true |
877 | } |
878 | |
879 | #[inline ] |
880 | fn is_valid_optional_magic(&self) -> bool { |
881 | self.optional_header.magic.get(LE) == pe::IMAGE_NT_OPTIONAL_HDR64_MAGIC |
882 | } |
883 | |
884 | #[inline ] |
885 | fn signature(&self) -> u32 { |
886 | self.signature.get(LE) |
887 | } |
888 | |
889 | #[inline ] |
890 | fn file_header(&self) -> &pe::ImageFileHeader { |
891 | &self.file_header |
892 | } |
893 | |
894 | #[inline ] |
895 | fn optional_header(&self) -> &Self::ImageOptionalHeader { |
896 | &self.optional_header |
897 | } |
898 | } |
899 | |
900 | impl ImageOptionalHeader for pe::ImageOptionalHeader64 { |
901 | #[inline ] |
902 | fn magic(&self) -> u16 { |
903 | self.magic.get(LE) |
904 | } |
905 | |
906 | #[inline ] |
907 | fn major_linker_version(&self) -> u8 { |
908 | self.major_linker_version |
909 | } |
910 | |
911 | #[inline ] |
912 | fn minor_linker_version(&self) -> u8 { |
913 | self.minor_linker_version |
914 | } |
915 | |
916 | #[inline ] |
917 | fn size_of_code(&self) -> u32 { |
918 | self.size_of_code.get(LE) |
919 | } |
920 | |
921 | #[inline ] |
922 | fn size_of_initialized_data(&self) -> u32 { |
923 | self.size_of_initialized_data.get(LE) |
924 | } |
925 | |
926 | #[inline ] |
927 | fn size_of_uninitialized_data(&self) -> u32 { |
928 | self.size_of_uninitialized_data.get(LE) |
929 | } |
930 | |
931 | #[inline ] |
932 | fn address_of_entry_point(&self) -> u32 { |
933 | self.address_of_entry_point.get(LE) |
934 | } |
935 | |
936 | #[inline ] |
937 | fn base_of_code(&self) -> u32 { |
938 | self.base_of_code.get(LE) |
939 | } |
940 | |
941 | #[inline ] |
942 | fn base_of_data(&self) -> Option<u32> { |
943 | None |
944 | } |
945 | |
946 | #[inline ] |
947 | fn image_base(&self) -> u64 { |
948 | self.image_base.get(LE) |
949 | } |
950 | |
951 | #[inline ] |
952 | fn section_alignment(&self) -> u32 { |
953 | self.section_alignment.get(LE) |
954 | } |
955 | |
956 | #[inline ] |
957 | fn file_alignment(&self) -> u32 { |
958 | self.file_alignment.get(LE) |
959 | } |
960 | |
961 | #[inline ] |
962 | fn major_operating_system_version(&self) -> u16 { |
963 | self.major_operating_system_version.get(LE) |
964 | } |
965 | |
966 | #[inline ] |
967 | fn minor_operating_system_version(&self) -> u16 { |
968 | self.minor_operating_system_version.get(LE) |
969 | } |
970 | |
971 | #[inline ] |
972 | fn major_image_version(&self) -> u16 { |
973 | self.major_image_version.get(LE) |
974 | } |
975 | |
976 | #[inline ] |
977 | fn minor_image_version(&self) -> u16 { |
978 | self.minor_image_version.get(LE) |
979 | } |
980 | |
981 | #[inline ] |
982 | fn major_subsystem_version(&self) -> u16 { |
983 | self.major_subsystem_version.get(LE) |
984 | } |
985 | |
986 | #[inline ] |
987 | fn minor_subsystem_version(&self) -> u16 { |
988 | self.minor_subsystem_version.get(LE) |
989 | } |
990 | |
991 | #[inline ] |
992 | fn win32_version_value(&self) -> u32 { |
993 | self.win32_version_value.get(LE) |
994 | } |
995 | |
996 | #[inline ] |
997 | fn size_of_image(&self) -> u32 { |
998 | self.size_of_image.get(LE) |
999 | } |
1000 | |
1001 | #[inline ] |
1002 | fn size_of_headers(&self) -> u32 { |
1003 | self.size_of_headers.get(LE) |
1004 | } |
1005 | |
1006 | #[inline ] |
1007 | fn check_sum(&self) -> u32 { |
1008 | self.check_sum.get(LE) |
1009 | } |
1010 | |
1011 | #[inline ] |
1012 | fn subsystem(&self) -> u16 { |
1013 | self.subsystem.get(LE) |
1014 | } |
1015 | |
1016 | #[inline ] |
1017 | fn dll_characteristics(&self) -> u16 { |
1018 | self.dll_characteristics.get(LE) |
1019 | } |
1020 | |
1021 | #[inline ] |
1022 | fn size_of_stack_reserve(&self) -> u64 { |
1023 | self.size_of_stack_reserve.get(LE) |
1024 | } |
1025 | |
1026 | #[inline ] |
1027 | fn size_of_stack_commit(&self) -> u64 { |
1028 | self.size_of_stack_commit.get(LE) |
1029 | } |
1030 | |
1031 | #[inline ] |
1032 | fn size_of_heap_reserve(&self) -> u64 { |
1033 | self.size_of_heap_reserve.get(LE) |
1034 | } |
1035 | |
1036 | #[inline ] |
1037 | fn size_of_heap_commit(&self) -> u64 { |
1038 | self.size_of_heap_commit.get(LE) |
1039 | } |
1040 | |
1041 | #[inline ] |
1042 | fn loader_flags(&self) -> u32 { |
1043 | self.loader_flags.get(LE) |
1044 | } |
1045 | |
1046 | #[inline ] |
1047 | fn number_of_rva_and_sizes(&self) -> u32 { |
1048 | self.number_of_rva_and_sizes.get(LE) |
1049 | } |
1050 | } |
1051 | |