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