Skip to main content

vmi_os_windows/pe/
headers.rs

1//! On-disk PE header layouts.
2//!
3//! Mirrors the relevant `IMAGE_*` types from `object::pe` as
4//! `#[repr(C, packed)]` zerocopy structs and re-exports the PE constants.
5//! This is the only module in the crate that imports from the `object`
6//! crate. Everything else goes through [`crate::pe`].
7
8use object::ReadRef as _;
9pub use object::{
10    pe::{
11        IMAGE_DIRECTORY_ENTRY_ARCHITECTURE, IMAGE_DIRECTORY_ENTRY_BASERELOC,
12        IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
13        IMAGE_DIRECTORY_ENTRY_DEBUG, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
14        IMAGE_DIRECTORY_ENTRY_EXCEPTION, IMAGE_DIRECTORY_ENTRY_EXPORT,
15        IMAGE_DIRECTORY_ENTRY_GLOBALPTR, IMAGE_DIRECTORY_ENTRY_IAT, IMAGE_DIRECTORY_ENTRY_IMPORT,
16        IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, IMAGE_DIRECTORY_ENTRY_RESOURCE,
17        IMAGE_DIRECTORY_ENTRY_SECURITY, IMAGE_DIRECTORY_ENTRY_TLS, IMAGE_DOS_SIGNATURE,
18        IMAGE_NT_OPTIONAL_HDR32_MAGIC, IMAGE_NT_OPTIONAL_HDR64_MAGIC, IMAGE_NT_SIGNATURE,
19        IMAGE_NUMBEROF_DIRECTORY_ENTRIES, IMAGE_SIZEOF_SHORT_NAME,
20    },
21    // Intentional re-export: `Export`, `ExportTable` and `ExportTarget` are good as they are.
22    read::pe::{Export, ExportTable, ExportTarget},
23};
24
25/// CodeView debug directory type.
26pub const IMAGE_DEBUG_TYPE_CODEVIEW: u32 = ::object::pe::IMAGE_DEBUG_TYPE_CODEVIEW.0;
27
28use super::error::PeError;
29
30/// Reads an `object`-crate struct field as a native scalar.
31///
32/// `impl_struct!` calls `to_endian(LE)` on every source field. The trait
33/// covers both `object`'s endian wrappers (`U16<E, T>`, `U32<E, T>`, `U64<E, T>`,
34/// and arrays of those) and the raw types `object` stores natively because
35/// no `U8<E>` wrapper exists (`u8` and byte arrays).
36trait ToEndian<E>
37where
38    E: ::object::Endian,
39{
40    /// Native counterpart of `Self`.
41    type Output;
42
43    /// Returns `self` decoded with `endian`.
44    fn to_endian(&self, endian: E) -> Self::Output;
45}
46
47impl<E, T> ToEndian<E> for ::object::U16<E, T>
48where
49    E: ::object::Endian,
50    T: ::object::Wrap<Inner = u16> + Copy,
51{
52    type Output = u16;
53
54    fn to_endian(&self, endian: E) -> Self::Output {
55        (*self).get(endian).into_inner()
56    }
57}
58
59impl<E, T> ToEndian<E> for ::object::U32<E, T>
60where
61    E: ::object::Endian,
62    T: ::object::Wrap<Inner = u32> + Copy,
63{
64    type Output = u32;
65
66    fn to_endian(&self, endian: E) -> Self::Output {
67        (*self).get(endian).into_inner()
68    }
69}
70
71impl<E, T> ToEndian<E> for ::object::U64<E, T>
72where
73    E: ::object::Endian,
74    T: ::object::Wrap<Inner = u64> + Copy,
75{
76    type Output = u64;
77
78    fn to_endian(&self, endian: E) -> Self::Output {
79        (*self).get(endian).into_inner()
80    }
81}
82
83impl<E: ::object::Endian> ToEndian<E> for u8 {
84    type Output = u8;
85
86    fn to_endian(&self, _endian: E) -> Self::Output {
87        *self
88    }
89}
90
91impl<E: ::object::Endian, const N: usize> ToEndian<E> for [u8; N] {
92    type Output = [u8; N];
93
94    fn to_endian(&self, _endian: E) -> Self::Output {
95        *self
96    }
97}
98
99impl<E: ::object::Endian, const N: usize> ToEndian<E> for [::object::U16<E>; N] {
100    type Output = [u16; N];
101
102    fn to_endian(&self, endian: E) -> Self::Output {
103        std::array::from_fn(|i| self[i].get(endian))
104    }
105}
106
107/// Defines a `#[repr(C, packed)]` PE struct that mirrors an `object`-crate
108/// type and verifies the layout match at compile time.
109///
110/// Each invocation expands to:
111///
112/// - A struct with the requested fields, `#[repr(C, packed)]`, and the
113///   `zerocopy` derives needed for byte-level reads.
114/// - `impl From<SourceType> for $name` that decodes every field through
115///   [`ToEndian`].
116/// - Static asserts that `$name` and `SourceType` agree on size,
117///   alignment, and the offset of every field.
118///
119/// `#[from(SourceType)]` is required and must appear once. `#[derive(...)]`
120/// blocks are merged with the macro's own derives. Any other attributes
121/// pass through to the generated struct.
122///
123/// # Usage
124///
125/// ```ignore
126/// impl_struct! {
127///     /// Field descriptor for an export entry.
128///     #[derive(Debug, Clone, Copy)]
129///     #[from(::object::pe::ImageDataDirectory)]
130///     pub struct ImageDataDirectory {
131///         pub virtual_address: u32,
132///         pub size: u32,
133///     }
134/// }
135/// ```
136macro_rules! impl_struct {
137    //
138    // @parse - tokenize the attribute list before the struct body.
139    //
140    // Each arm matches one leading `#[...]`, appends it to the matching
141    // accumulator, and recurses with the rest. Specialized arms come
142    // before the catch-all so that `#[from]`, `#[doc]`, and `#[derive]`
143    // are recognized rather than forwarded blindly.
144    //
145
146    // Capture `#[from(SourceType)]`. Allowed once.
147    (@parse
148        from   = []
149        doc    = [$($doc:tt)*]
150        derive = [$($derive:tt)*]
151        attrs  = [$($attrs:tt)*]
152        rest   = [#[from($from:ty)] $($rest:tt)*]
153    ) => {
154        impl_struct!(@parse
155            from   = [$from]
156            doc    = [$($doc)*]
157            derive = [$($derive)*]
158            attrs  = [$($attrs)*]
159            rest   = [$($rest)*]
160        );
161    };
162
163    // Reject a duplicate `#[from(...)]`.
164    (@parse
165        from   = [$_first:ty]
166        doc    = [$($doc:tt)*]
167        derive = [$($derive:tt)*]
168        attrs  = [$($attrs:tt)*]
169        rest   = [#[from($_dup:ty)] $($rest:tt)*]
170    ) => {
171        compile_error!("impl_struct!: duplicate `#[from(...)]` attribute");
172    };
173
174    // Append a doc comment.
175    (@parse
176        from   = [$($from:tt)*]
177        doc    = [$($doc:tt)*]
178        derive = [$($derive:tt)*]
179        attrs  = [$($attrs:tt)*]
180        rest   = [#[doc = $d:literal] $($rest:tt)*]
181    ) => {
182        impl_struct!(@parse
183            from   = [$($from)*]
184            doc    = [$($doc)* #[doc = $d]]
185            derive = [$($derive)*]
186            attrs  = [$($attrs)*]
187            rest   = [$($rest)*]
188        );
189    };
190
191    // Merge a `#[derive(...)]` block into the running derive list.
192    (@parse
193        from   = [$($from:tt)*]
194        doc    = [$($doc:tt)*]
195        derive = [$($derive:tt)*]
196        attrs  = [$($attrs:tt)*]
197        rest   = [#[derive($($d:path),* $(,)?)] $($rest:tt)*]
198    ) => {
199        impl_struct!(@parse
200            from   = [$($from)*]
201            doc    = [$($doc)*]
202            derive = [$($derive)* $($d,)*]
203            attrs  = [$($attrs)*]
204            rest   = [$($rest)*]
205        );
206    };
207
208    // Forward any other `#[...]` to the generated struct verbatim.
209    (@parse
210        from   = [$($from:tt)*]
211        doc    = [$($doc:tt)*]
212        derive = [$($derive:tt)*]
213        attrs  = [$($attrs:tt)*]
214        rest   = [#[$attr:meta] $($rest:tt)*]
215    ) => {
216        impl_struct!(@parse
217            from   = [$($from)*]
218            doc    = [$($doc)*]
219            derive = [$($derive)*]
220            attrs  = [$($attrs)* #[$attr]]
221            rest   = [$($rest)*]
222        );
223    };
224
225    //
226    // @parse - terminal arms.
227    //
228    // Hit when `rest` consists of just `pub struct ...`. The first emits
229    // the struct, the `From` impl, and the layout asserts. The second
230    // errors out if `#[from(...)]` was never supplied.
231    //
232
233    (@parse
234        from   = [$from_ty:ty]
235        doc    = [$($doc:tt)*]
236        derive = [$($derive:tt)*]
237        attrs  = [$($attrs:tt)*]
238        rest   = [
239            $vis:vis struct $name:ident {
240                $(
241                    $(#[$field_attr:meta])*
242                    $field_vis:vis $field:ident : $field_ty:ty
243                ),* $(,)?
244            }
245        ]
246    ) => {
247        $($doc)*
248        #[derive(
249            $($derive)*
250            ::zerocopy::FromBytes,
251            ::zerocopy::IntoBytes,
252            ::zerocopy::Immutable,
253            ::zerocopy::KnownLayout,
254        )]
255        #[repr(C, packed)]
256        $($attrs)*
257        $vis struct $name {
258            $(
259                $(#[$field_attr])*
260                $field_vis $field: $field_ty,
261            )*
262        }
263
264        impl ::core::convert::From<$from_ty> for $name {
265            fn from(value: $from_ty) -> Self {
266                Self {
267                    $(
268                        $field: value.$field.to_endian(::object::LittleEndian),
269                    )*
270                }
271            }
272        }
273
274        const _: () = {
275            use ::core::mem::{align_of, size_of};
276
277            assert!(
278                size_of::<$name>() == size_of::<$from_ty>(),
279                concat!(stringify!($name), " size mismatch"),
280            );
281
282            assert!(
283                align_of::<$name>() == align_of::<$from_ty>(),
284                concat!(stringify!($name), " alignment mismatch"),
285            );
286        };
287
288        $(
289            const _: () = {
290                use ::core::mem::offset_of;
291
292                assert!(
293                    offset_of!($name, $field) == offset_of!($from_ty, $field),
294                    concat!(stringify!($name), " field offset mismatch: ", stringify!($field)),
295                );
296            };
297        )*
298    };
299
300    (@parse
301        from   = []
302        doc    = [$($doc:tt)*]
303        derive = [$($derive:tt)*]
304        attrs  = [$($attrs:tt)*]
305        rest   = [$vis:vis struct $name:ident { $($body:tt)* }]
306    ) => {
307        compile_error!(concat!(
308            "impl_struct!: missing `#[from(SourceType)]` attribute on `",
309            stringify!($name),
310            "`",
311        ));
312    };
313
314    //
315    // Entry arm.
316    //
317    // Placed last so any recursive call starting with `@parse` matches one
318    // of the arms above instead of falling through here. Seeds the muncher
319    // with empty accumulators so the user-facing call doesn't thread any
320    // bookkeeping arguments.
321    //
322
323    ($($input:tt)*) => {
324        impl_struct!(@parse
325            from   = []
326            doc    = []
327            derive = []
328            attrs  = []
329            rest   = [$($input)*]
330        );
331    };
332}
333
334impl_struct! {
335    /// MS-DOS executable header at the start of every PE file.
336    ///
337    /// Of the original DOS layout, only `e_magic` (must be `MZ`) and
338    /// `e_lfanew` (file offset of the NT headers) are used by the PE loader.
339    /// The rest is preserved for compatibility with the legacy format.
340    ///
341    /// # Implementation Details
342    ///
343    /// Corresponds to `_IMAGE_DOS_HEADER`.
344    #[derive(Debug, Clone, Copy)]
345    #[from(::object::pe::ImageDosHeader)]
346    pub struct ImageDosHeader {
347        /// DOS magic, must be `MZ` (`0x5A4D`).
348        pub e_magic: u16,
349
350        /// Bytes on the last page of the file.
351        pub e_cblp: u16,
352
353        /// Pages in the file.
354        pub e_cp: u16,
355
356        /// Relocation count.
357        pub e_crlc: u16,
358
359        /// Header size in 16-byte paragraphs.
360        pub e_cparhdr: u16,
361
362        /// Minimum extra paragraphs needed.
363        pub e_minalloc: u16,
364
365        /// Maximum extra paragraphs needed.
366        pub e_maxalloc: u16,
367
368        /// Initial relative SS value.
369        pub e_ss: u16,
370
371        /// Initial SP value.
372        pub e_sp: u16,
373
374        /// Header checksum.
375        pub e_csum: u16,
376
377        /// Initial IP value.
378        pub e_ip: u16,
379
380        /// Initial relative CS value.
381        pub e_cs: u16,
382
383        /// File offset of the relocation table.
384        pub e_lfarlc: u16,
385
386        /// Overlay number.
387        pub e_ovno: u16,
388
389        /// Reserved words.
390        pub e_res: [u16; 4],
391
392        /// OEM identifier qualifying `e_oeminfo`.
393        pub e_oemid: u16,
394
395        /// OEM information specific to `e_oemid`.
396        pub e_oeminfo: u16,
397
398        /// Reserved words.
399        pub e_res2: [u16; 10],
400
401        /// File offset of the NT headers.
402        pub e_lfanew: u32,
403    }
404}
405
406impl ImageDosHeader {
407    /// Parses the DOS header.
408    pub fn parse(data: &[u8], offset: &mut u64) -> Result<Self, PeError> {
409        let dos_header = data
410            .read_at::<::object::pe::ImageDosHeader>(0)
411            .copied()
412            .map_err(|_| PeError::InvalidDosHeader)?;
413
414        if dos_header.e_magic.get(::object::LittleEndian) != IMAGE_DOS_SIGNATURE {
415            return Err(PeError::InvalidDosMagic);
416        }
417
418        *offset = dos_header.nt_headers_offset() as u64;
419
420        Ok(dos_header.into())
421    }
422
423    /// Returns the file offset of the NT headers.
424    pub fn nt_headers_offset(&self) -> u32 {
425        self.e_lfanew
426    }
427}
428
429/// Top-level PE header pointed to by [`ImageDosHeader::e_lfanew`].
430///
431/// Identifies whether the image is 32-bit or 64-bit through the optional
432/// header magic.
433///
434/// # Implementation Details
435///
436/// Corresponds to `_IMAGE_NT_HEADERS32` or `_IMAGE_NT_HEADERS64`.
437#[derive(Debug, Clone, Copy)]
438pub struct ImageNtHeaders {
439    /// PE signature, `PE\0\0` (`0x00004550`).
440    pub signature: u32,
441
442    /// COFF file header.
443    pub file_header: ImageFileHeader,
444
445    /// PE32 or PE32+ optional header.
446    pub optional_header: ImageOptionalHeader,
447}
448
449impl ImageNtHeaders {
450    /// Parses the NT headers.
451    pub fn parse(data: &[u8], offset: &mut u64) -> Result<Self, PeError> {
452        let magic =
453            ::object::read::pe::optional_header_magic(data).map_err(|_| PeError::InvalidPeMagic)?;
454
455        match magic {
456            IMAGE_NT_OPTIONAL_HDR32_MAGIC => {
457                Self::parse_inner::<::object::pe::ImageNtHeaders32>(data, offset)
458            }
459            IMAGE_NT_OPTIONAL_HDR64_MAGIC => {
460                Self::parse_inner::<::object::pe::ImageNtHeaders64>(data, offset)
461            }
462            _ => Err(PeError::InvalidPeMagic),
463        }
464    }
465
466    fn parse_inner<Pe>(data: &[u8], offset: &mut u64) -> Result<Self, PeError>
467    where
468        Self: From<Pe>,
469        Pe: ::object::read::pe::ImageNtHeaders,
470    {
471        let nt_headers = data
472            .read::<Pe>(offset)
473            .copied()
474            .map_err(|_| PeError::InvalidNtHeaders)?;
475
476        if nt_headers.signature() != IMAGE_NT_SIGNATURE {
477            return Err(PeError::InvalidPeMagic);
478        }
479
480        if !nt_headers.is_valid_optional_magic() {
481            return Err(PeError::InvalidOptionalHeaderMagic);
482        }
483
484        Ok(nt_headers.into())
485    }
486}
487
488impl From<::object::pe::ImageNtHeaders32> for ImageNtHeaders {
489    fn from(value: ::object::pe::ImageNtHeaders32) -> Self {
490        Self {
491            signature: value.signature.get(::object::LittleEndian),
492            file_header: value.file_header.into(),
493            optional_header: value.optional_header.into(),
494        }
495    }
496}
497
498impl From<::object::pe::ImageNtHeaders64> for ImageNtHeaders {
499    fn from(value: ::object::pe::ImageNtHeaders64) -> Self {
500        Self {
501            signature: value.signature.get(::object::LittleEndian),
502            file_header: value.file_header.into(),
503            optional_header: value.optional_header.into(),
504        }
505    }
506}
507
508impl_struct! {
509    /// COFF file header that follows the PE signature in [`ImageNtHeaders`].
510    ///
511    /// # Implementation Details
512    ///
513    /// Corresponds to `_IMAGE_FILE_HEADER`.
514    #[derive(Debug, Clone, Copy)]
515    #[from(::object::pe::ImageFileHeader)]
516    pub struct ImageFileHeader {
517        /// Target machine architecture, `IMAGE_FILE_MACHINE_*`.
518        pub machine: u16,
519
520        /// Number of entries in the section table.
521        pub number_of_sections: u16,
522
523        /// Build timestamp, in Unix epoch seconds.
524        pub time_date_stamp: u32,
525
526        /// File offset of the COFF symbol table. Deprecated, zero in modern images.
527        pub pointer_to_symbol_table: u32,
528
529        /// Symbol table entry count. Deprecated, zero in modern images.
530        pub number_of_symbols: u32,
531
532        /// Size in bytes of the optional header that follows.
533        pub size_of_optional_header: u16,
534
535        /// `IMAGE_FILE_*` characteristic flags.
536        pub characteristics: u16,
537    }
538}
539
540impl_struct! {
541    /// PE32 optional header for 32-bit images.
542    ///
543    /// Layout differs from [`ImageOptionalHeader64`] in `image_base` and the
544    /// stack/heap size fields, which are 32-bit here, and in the presence
545    /// of `base_of_data`.
546    ///
547    /// # Implementation Details
548    ///
549    /// Corresponds to `_IMAGE_OPTIONAL_HEADER`.
550    #[derive(Debug, Clone, Copy)]
551    #[from(::object::pe::ImageOptionalHeader32)]
552    pub struct ImageOptionalHeader32 {
553        /// PE32 magic, `0x10b`.
554        pub magic: u16,
555
556        /// Linker version, major part.
557        pub major_linker_version: u8,
558
559        /// Linker version, minor part.
560        pub minor_linker_version: u8,
561
562        /// Combined size of all code sections, in bytes.
563        pub size_of_code: u32,
564
565        /// Combined size of all initialized data sections, in bytes.
566        pub size_of_initialized_data: u32,
567
568        /// Combined size of all uninitialized data sections, in bytes.
569        pub size_of_uninitialized_data: u32,
570
571        /// RVA of the entry point.
572        pub address_of_entry_point: u32,
573
574        /// RVA of the start of the code section.
575        pub base_of_code: u32,
576
577        /// RVA of the start of the data section.
578        pub base_of_data: u32,
579
580        /// Preferred load address.
581        pub image_base: u32,
582
583        /// Section alignment when loaded into memory, in bytes.
584        pub section_alignment: u32,
585
586        /// Section alignment within the file, in bytes.
587        pub file_alignment: u32,
588
589        /// Required OS version, major part.
590        pub major_operating_system_version: u16,
591
592        /// Required OS version, minor part.
593        pub minor_operating_system_version: u16,
594
595        /// Image version, major part.
596        pub major_image_version: u16,
597
598        /// Image version, minor part.
599        pub minor_image_version: u16,
600
601        /// Required subsystem version, major part.
602        pub major_subsystem_version: u16,
603
604        /// Required subsystem version, minor part.
605        pub minor_subsystem_version: u16,
606
607        /// Reserved, must be zero.
608        pub win32_version_value: u32,
609
610        /// Total size of the image when loaded, including headers.
611        pub size_of_image: u32,
612
613        /// Combined size of the DOS, NT, and section headers, file-aligned.
614        pub size_of_headers: u32,
615
616        /// Image checksum. Often zero outside system images.
617        pub check_sum: u32,
618
619        /// `IMAGE_SUBSYSTEM_*` value identifying the runtime environment.
620        pub subsystem: u16,
621
622        /// `IMAGE_DLLCHARACTERISTICS_*` flags.
623        pub dll_characteristics: u16,
624
625        /// Reserved stack size.
626        pub size_of_stack_reserve: u32,
627
628        /// Initial committed stack size.
629        pub size_of_stack_commit: u32,
630
631        /// Reserved heap size.
632        pub size_of_heap_reserve: u32,
633
634        /// Initial committed heap size.
635        pub size_of_heap_commit: u32,
636
637        /// Reserved, must be zero.
638        pub loader_flags: u32,
639
640        /// Length of the data directory array that follows the optional header.
641        pub number_of_rva_and_sizes: u32,
642    }
643}
644
645impl_struct! {
646    /// PE32+ optional header for 64-bit images.
647    ///
648    /// Layout differs from [`ImageOptionalHeader32`] in `image_base` and the
649    /// stack/heap size fields, which are 64-bit here, and in the absence
650    /// of `base_of_data`.
651    ///
652    /// # Implementation Details
653    ///
654    /// Corresponds to `_IMAGE_OPTIONAL_HEADER64`.
655    #[derive(Debug, Clone, Copy)]
656    #[from(::object::pe::ImageOptionalHeader64)]
657    pub struct ImageOptionalHeader64 {
658        /// PE32+ magic, `0x20b`.
659        pub magic: u16,
660
661        /// Linker version, major part.
662        pub major_linker_version: u8,
663
664        /// Linker version, minor part.
665        pub minor_linker_version: u8,
666
667        /// Combined size of all code sections, in bytes.
668        pub size_of_code: u32,
669
670        /// Combined size of all initialized data sections, in bytes.
671        pub size_of_initialized_data: u32,
672
673        /// Combined size of all uninitialized data sections, in bytes.
674        pub size_of_uninitialized_data: u32,
675
676        /// RVA of the entry point.
677        pub address_of_entry_point: u32,
678
679        /// RVA of the start of the code section.
680        pub base_of_code: u32,
681
682        /// Preferred load address.
683        pub image_base: u64,
684
685        /// Section alignment when loaded into memory, in bytes.
686        pub section_alignment: u32,
687
688        /// Section alignment within the file, in bytes.
689        pub file_alignment: u32,
690
691        /// Required OS version, major part.
692        pub major_operating_system_version: u16,
693
694        /// Required OS version, minor part.
695        pub minor_operating_system_version: u16,
696
697        /// Image version, major part.
698        pub major_image_version: u16,
699
700        /// Image version, minor part.
701        pub minor_image_version: u16,
702
703        /// Required subsystem version, major part.
704        pub major_subsystem_version: u16,
705
706        /// Required subsystem version, minor part.
707        pub minor_subsystem_version: u16,
708
709        /// Reserved, must be zero.
710        pub win32_version_value: u32,
711
712        /// Total size of the image when loaded, including headers.
713        pub size_of_image: u32,
714
715        /// Combined size of the DOS, NT, and section headers, file-aligned.
716        pub size_of_headers: u32,
717
718        /// Image checksum. Often zero outside system images.
719        pub check_sum: u32,
720
721        /// `IMAGE_SUBSYSTEM_*` value identifying the runtime environment.
722        pub subsystem: u16,
723
724        /// `IMAGE_DLLCHARACTERISTICS_*` flags.
725        pub dll_characteristics: u16,
726
727        /// Reserved stack size.
728        pub size_of_stack_reserve: u64,
729
730        /// Initial committed stack size.
731        pub size_of_stack_commit: u64,
732
733        /// Reserved heap size.
734        pub size_of_heap_reserve: u64,
735
736        /// Initial committed heap size.
737        pub size_of_heap_commit: u64,
738
739        /// Reserved, must be zero.
740        pub loader_flags: u32,
741
742        /// Length of the data directory array that follows the optional header.
743        pub number_of_rva_and_sizes: u32,
744    }
745}
746
747/// Optional header in either PE32 or PE32+ form.
748///
749/// Discriminated by the magic in [`ImageOptionalHeader::magic`].
750///
751/// # Implementation Details
752///
753/// Corresponds to `_IMAGE_OPTIONAL_HEADER` or `_IMAGE_OPTIONAL_HEADER64`.
754#[derive(Debug, Clone, Copy)]
755pub enum ImageOptionalHeader {
756    /// PE32 optional header (32-bit image).
757    ImageOptionalHeader32(ImageOptionalHeader32),
758
759    /// PE32+ optional header (64-bit image).
760    ImageOptionalHeader64(ImageOptionalHeader64),
761}
762
763impl From<::object::pe::ImageOptionalHeader32> for ImageOptionalHeader {
764    fn from(value: ::object::pe::ImageOptionalHeader32) -> Self {
765        Self::ImageOptionalHeader32(value.into())
766    }
767}
768
769impl From<::object::pe::ImageOptionalHeader64> for ImageOptionalHeader {
770    fn from(value: ::object::pe::ImageOptionalHeader64) -> Self {
771        Self::ImageOptionalHeader64(value.into())
772    }
773}
774
775impl ImageOptionalHeader {
776    /// Returns the magic identifying PE32 (`0x10b`) or PE32+ (`0x20b`).
777    pub fn magic(&self) -> u16 {
778        match self {
779            Self::ImageOptionalHeader32(hdr32) => hdr32.magic,
780            Self::ImageOptionalHeader64(hdr64) => hdr64.magic,
781        }
782    }
783
784    /// Returns the major linker version.
785    pub fn major_linker_version(&self) -> u8 {
786        match self {
787            Self::ImageOptionalHeader32(hdr32) => hdr32.major_linker_version,
788            Self::ImageOptionalHeader64(hdr64) => hdr64.major_linker_version,
789        }
790    }
791
792    /// Returns the minor linker version.
793    pub fn minor_linker_version(&self) -> u8 {
794        match self {
795            Self::ImageOptionalHeader32(hdr32) => hdr32.minor_linker_version,
796            Self::ImageOptionalHeader64(hdr64) => hdr64.minor_linker_version,
797        }
798    }
799
800    /// Returns the combined size of all code sections, in bytes.
801    pub fn size_of_code(&self) -> u32 {
802        match self {
803            Self::ImageOptionalHeader32(hdr32) => hdr32.size_of_code,
804            Self::ImageOptionalHeader64(hdr64) => hdr64.size_of_code,
805        }
806    }
807
808    /// Returns the combined size of all initialized data sections, in bytes.
809    pub fn size_of_initialized_data(&self) -> u32 {
810        match self {
811            Self::ImageOptionalHeader32(hdr32) => hdr32.size_of_initialized_data,
812            Self::ImageOptionalHeader64(hdr64) => hdr64.size_of_initialized_data,
813        }
814    }
815
816    /// Returns the combined size of all uninitialized data sections, in bytes.
817    pub fn size_of_uninitialized_data(&self) -> u32 {
818        match self {
819            Self::ImageOptionalHeader32(hdr32) => hdr32.size_of_uninitialized_data,
820            Self::ImageOptionalHeader64(hdr64) => hdr64.size_of_uninitialized_data,
821        }
822    }
823
824    /// Returns the RVA of the entry point.
825    ///
826    /// When the image is loaded, this is the actual memory address.
827    pub fn address_of_entry_point(&self) -> u32 {
828        match self {
829            Self::ImageOptionalHeader32(hdr32) => hdr32.address_of_entry_point,
830            Self::ImageOptionalHeader64(hdr64) => hdr64.address_of_entry_point,
831        }
832    }
833
834    /// Returns the RVA of the start of the code section.
835    pub fn base_of_code(&self) -> u32 {
836        match self {
837            Self::ImageOptionalHeader32(hdr32) => hdr32.base_of_code,
838            Self::ImageOptionalHeader64(hdr64) => hdr64.base_of_code,
839        }
840    }
841
842    /// Returns the RVA of the start of the data section (PE32 only).
843    pub fn base_of_data(&self) -> Option<u32> {
844        match self {
845            Self::ImageOptionalHeader32(hdr32) => Some(hdr32.base_of_data),
846            Self::ImageOptionalHeader64(_) => None,
847        }
848    }
849
850    /// Returns the preferred load address in memory.
851    ///
852    /// The actual base address may change due to ASLR or conflicts.
853    pub fn image_base(&self) -> u64 {
854        match self {
855            Self::ImageOptionalHeader32(hdr32) => hdr32.image_base.into(),
856            Self::ImageOptionalHeader64(hdr64) => hdr64.image_base,
857        }
858    }
859
860    /// Returns the section alignment in memory, in bytes.
861    ///
862    /// This may change when the image is loaded by the OS.
863    pub fn section_alignment(&self) -> u32 {
864        match self {
865            Self::ImageOptionalHeader32(hdr32) => hdr32.section_alignment,
866            Self::ImageOptionalHeader64(hdr64) => hdr64.section_alignment,
867        }
868    }
869
870    /// Returns the section alignment on disk, in bytes.
871    pub fn file_alignment(&self) -> u32 {
872        match self {
873            Self::ImageOptionalHeader32(hdr32) => hdr32.file_alignment,
874            Self::ImageOptionalHeader64(hdr64) => hdr64.file_alignment,
875        }
876    }
877
878    /// Returns the major operating system version required.
879    pub fn major_operating_system_version(&self) -> u16 {
880        match self {
881            Self::ImageOptionalHeader32(hdr32) => hdr32.major_operating_system_version,
882            Self::ImageOptionalHeader64(hdr64) => hdr64.major_operating_system_version,
883        }
884    }
885
886    /// Returns the minor operating system version required.
887    pub fn minor_operating_system_version(&self) -> u16 {
888        match self {
889            Self::ImageOptionalHeader32(hdr32) => hdr32.minor_operating_system_version,
890            Self::ImageOptionalHeader64(hdr64) => hdr64.minor_operating_system_version,
891        }
892    }
893
894    /// Returns the major image version.
895    pub fn major_image_version(&self) -> u16 {
896        match self {
897            Self::ImageOptionalHeader32(hdr32) => hdr32.major_image_version,
898            Self::ImageOptionalHeader64(hdr64) => hdr64.major_image_version,
899        }
900    }
901
902    /// Returns the minor image version.
903    pub fn minor_image_version(&self) -> u16 {
904        match self {
905            Self::ImageOptionalHeader32(hdr32) => hdr32.minor_image_version,
906            Self::ImageOptionalHeader64(hdr64) => hdr64.minor_image_version,
907        }
908    }
909
910    /// Returns the major subsystem version.
911    pub fn major_subsystem_version(&self) -> u16 {
912        match self {
913            Self::ImageOptionalHeader32(hdr32) => hdr32.major_subsystem_version,
914            Self::ImageOptionalHeader64(hdr64) => hdr64.major_subsystem_version,
915        }
916    }
917
918    /// Returns the minor subsystem version.
919    pub fn minor_subsystem_version(&self) -> u16 {
920        match self {
921            Self::ImageOptionalHeader32(hdr32) => hdr32.minor_subsystem_version,
922            Self::ImageOptionalHeader64(hdr64) => hdr64.minor_subsystem_version,
923        }
924    }
925
926    /// Returns the reserved Windows version value (should be zero).
927    pub fn win32_version_value(&self) -> u32 {
928        match self {
929            Self::ImageOptionalHeader32(hdr32) => hdr32.win32_version_value,
930            Self::ImageOptionalHeader64(hdr64) => hdr64.win32_version_value,
931        }
932    }
933
934    /// Returns the total size of the image in memory, including headers.
935    pub fn size_of_image(&self) -> u32 {
936        match self {
937            Self::ImageOptionalHeader32(hdr32) => hdr32.size_of_image,
938            Self::ImageOptionalHeader64(hdr64) => hdr64.size_of_image,
939        }
940    }
941
942    /// Returns the size of all headers (DOS header, PE header, section table).
943    pub fn size_of_headers(&self) -> u32 {
944        match self {
945            Self::ImageOptionalHeader32(hdr32) => hdr32.size_of_headers,
946            Self::ImageOptionalHeader64(hdr64) => hdr64.size_of_headers,
947        }
948    }
949
950    /// Returns the checksum of the image.
951    pub fn check_sum(&self) -> u32 {
952        match self {
953            Self::ImageOptionalHeader32(hdr32) => hdr32.check_sum,
954            Self::ImageOptionalHeader64(hdr64) => hdr64.check_sum,
955        }
956    }
957
958    /// Returns the `IMAGE_SUBSYSTEM_*` value identifying the runtime environment.
959    pub fn subsystem(&self) -> u16 {
960        match self {
961            Self::ImageOptionalHeader32(hdr32) => hdr32.subsystem,
962            Self::ImageOptionalHeader64(hdr64) => hdr64.subsystem,
963        }
964    }
965
966    /// Returns the `IMAGE_DLLCHARACTERISTICS_*` flags.
967    pub fn dll_characteristics(&self) -> u16 {
968        match self {
969            Self::ImageOptionalHeader32(hdr32) => hdr32.dll_characteristics,
970            Self::ImageOptionalHeader64(hdr64) => hdr64.dll_characteristics,
971        }
972    }
973
974    /// Returns the reserved stack size.
975    pub fn size_of_stack_reserve(&self) -> u64 {
976        match self {
977            Self::ImageOptionalHeader32(hdr32) => hdr32.size_of_stack_reserve.into(),
978            Self::ImageOptionalHeader64(hdr64) => hdr64.size_of_stack_reserve,
979        }
980    }
981
982    /// Returns the committed stack size.
983    pub fn size_of_stack_commit(&self) -> u64 {
984        match self {
985            Self::ImageOptionalHeader32(hdr32) => hdr32.size_of_stack_commit.into(),
986            Self::ImageOptionalHeader64(hdr64) => hdr64.size_of_stack_commit,
987        }
988    }
989
990    /// Returns the reserved heap size.
991    pub fn size_of_heap_reserve(&self) -> u64 {
992        match self {
993            Self::ImageOptionalHeader32(hdr32) => hdr32.size_of_heap_reserve.into(),
994            Self::ImageOptionalHeader64(hdr64) => hdr64.size_of_heap_reserve,
995        }
996    }
997
998    /// Returns the committed heap size.
999    pub fn size_of_heap_commit(&self) -> u64 {
1000        match self {
1001            Self::ImageOptionalHeader32(hdr32) => hdr32.size_of_heap_commit.into(),
1002            Self::ImageOptionalHeader64(hdr64) => hdr64.size_of_heap_commit,
1003        }
1004    }
1005
1006    /// Returns the reserved loader flags (should be zero).
1007    pub fn loader_flags(&self) -> u32 {
1008        match self {
1009            Self::ImageOptionalHeader32(hdr32) => hdr32.loader_flags,
1010            Self::ImageOptionalHeader64(hdr64) => hdr64.loader_flags,
1011        }
1012    }
1013
1014    /// Returns the number of data directories in the optional header.
1015    pub fn number_of_rva_and_sizes(&self) -> u32 {
1016        match self {
1017            Self::ImageOptionalHeader32(hdr32) => hdr32.number_of_rva_and_sizes,
1018            Self::ImageOptionalHeader64(hdr64) => hdr64.number_of_rva_and_sizes,
1019        }
1020    }
1021
1022    /// Returns the size of the optional header.
1023    pub fn size(&self) -> usize {
1024        match self {
1025            Self::ImageOptionalHeader32(_) => size_of::<ImageOptionalHeader32>(),
1026            Self::ImageOptionalHeader64(_) => size_of::<ImageOptionalHeader64>(),
1027        }
1028    }
1029}
1030
1031impl_struct! {
1032    /// Single entry in the PE section table.
1033    ///
1034    /// # Implementation Details
1035    ///
1036    /// Corresponds to `_IMAGE_SECTION_HEADER`.
1037    #[derive(Debug, Clone, Copy)]
1038    #[from(::object::pe::ImageSectionHeader)]
1039    pub struct ImageSectionHeader {
1040        /// Section name, null-padded to 8 bytes.
1041        pub name: [u8; IMAGE_SIZEOF_SHORT_NAME],
1042
1043        /// Section size in memory before alignment.
1044        pub virtual_size: u32,
1045
1046        /// RVA of the section when loaded.
1047        pub virtual_address: u32,
1048
1049        /// Size of the section's raw data in the file, file-aligned.
1050        pub size_of_raw_data: u32,
1051
1052        /// File offset of the section's raw data.
1053        pub pointer_to_raw_data: u32,
1054
1055        /// File offset of the relocation table. Zero for executables.
1056        pub pointer_to_relocations: u32,
1057
1058        /// File offset of the COFF line numbers. Zero in modern images.
1059        pub pointer_to_linenumbers: u32,
1060
1061        /// Relocation entry count. Zero for executables.
1062        pub number_of_relocations: u16,
1063
1064        /// Line-number entry count. Zero in modern images.
1065        pub number_of_linenumbers: u16,
1066
1067        /// `IMAGE_SCN_*` flags.
1068        pub characteristics: u32,
1069    }
1070}
1071
1072//
1073// The methods on `ImageSectionHeader` in this impl block (including their
1074// documentation) are copied from the `object` crate v0.39.1, Copyright (c)
1075// 2015 The Gimli Developers, used under the MIT license. See NOTICES at the
1076// repo root for the full license text.
1077//
1078
1079impl ImageSectionHeader {
1080    /// Returns the offset and size of the section in a PE file.
1081    ///
1082    /// The size of the range will be the minimum of the file size and virtual
1083    /// size.
1084    pub fn pe_file_range(&self) -> (u32, u32) {
1085        // Pointer and size will be zero for uninitialized data.
1086        // We don't need to validate this.
1087        let offset = self.pointer_to_raw_data;
1088        let size = std::cmp::min(self.virtual_size, self.size_of_raw_data);
1089        (offset, size)
1090    }
1091
1092    /// Returns the file offset of the given virtual address, and the remaining
1093    /// size up to the end of the section.
1094    ///
1095    /// Returns `None` if the section does not contain the address.
1096    pub fn pe_file_range_at(&self, va: u32) -> Option<(u32, u32)> {
1097        let section_va = self.virtual_address;
1098        let offset = va.checked_sub(section_va)?;
1099        let (section_offset, section_size) = self.pe_file_range();
1100
1101        // Address must be within section (and not at its end).
1102        if offset < section_size {
1103            Some((section_offset.checked_add(offset)?, section_size - offset))
1104        }
1105        else {
1106            None
1107        }
1108    }
1109
1110    /// Returns the section data in a PE file.
1111    ///
1112    /// The length of the data will be the minimum of the file size and virtual size.
1113    pub fn pe_data<'data>(&self, data: &'data [u8]) -> Option<&'data [u8]> {
1114        let (offset, size) = self.pe_file_range();
1115        data.read_bytes_at(offset.into(), size.into()).ok()
1116    }
1117
1118    /// Returns the data starting at the given virtual address, up to the end
1119    /// of the section.
1120    ///
1121    /// Ignores sections with invalid data.
1122    ///
1123    /// Returns `None` if the section does not contain the address.
1124    pub fn pe_data_at<'data>(&self, data: &'data [u8], va: u32) -> Option<&'data [u8]> {
1125        let (offset, size) = self.pe_file_range_at(va)?;
1126        data.read_bytes_at(offset.into(), size.into()).ok()
1127    }
1128}
1129
1130impl_struct! {
1131    /// Single entry in the data directory array of the optional header.
1132    ///
1133    /// Locates a standard PE table such as the export, import, or exception
1134    /// directory by RVA and size.
1135    ///
1136    /// # Implementation Details
1137    ///
1138    /// Corresponds to `_IMAGE_DATA_DIRECTORY`.
1139    #[derive(Debug, Clone, Copy)]
1140    #[from(::object::pe::ImageDataDirectory)]
1141    pub struct ImageDataDirectory {
1142        /// RVA of the table.
1143        pub virtual_address: u32,
1144
1145        /// Table size in bytes.
1146        pub size: u32,
1147    }
1148}
1149
1150impl_struct! {
1151    /// Single entry in the debug directory.
1152    ///
1153    /// # Implementation Details
1154    ///
1155    /// Corresponds to `_IMAGE_DEBUG_DIRECTORY`.
1156    #[derive(Debug, Clone, Copy)]
1157    #[from(::object::pe::ImageDebugDirectory)]
1158    pub struct ImageDebugDirectory {
1159        /// Reserved, must be zero.
1160        pub characteristics: u32,
1161
1162        /// Build timestamp, in Unix epoch seconds.
1163        pub time_date_stamp: u32,
1164
1165        /// Debug data format version, major part.
1166        pub major_version: u16,
1167
1168        /// Debug data format version, minor part.
1169        pub minor_version: u16,
1170
1171        /// `IMAGE_DEBUG_TYPE_*` identifying the debug data format.
1172        pub typ: u32,
1173
1174        /// Size of the debug data, in bytes.
1175        pub size_of_data: u32,
1176
1177        /// RVA of the debug data when loaded.
1178        pub address_of_raw_data: u32,
1179
1180        /// File offset of the debug data.
1181        pub pointer_to_raw_data: u32,
1182    }
1183}
1184
1185impl_struct! {
1186    /// Single entry in the `.pdata` exception directory.
1187    ///
1188    /// Maps a function's RVA range to its `UNWIND_INFO`.
1189    ///
1190    /// # Implementation Details
1191    ///
1192    /// Corresponds to `_IMAGE_RUNTIME_FUNCTION_ENTRY`.
1193    #[derive(Debug, Clone, Copy)]
1194    #[from(::object::pe::ImageRuntimeFunctionEntry)]
1195    pub struct ImageRuntimeFunctionEntry {
1196        /// Function start RVA.
1197        pub begin_address: u32,
1198
1199        /// Function end RVA, exclusive.
1200        pub end_address: u32,
1201
1202        /// RVA of the function's `UNWIND_INFO`.
1203        pub unwind_info_address_or_data: u32,
1204    }
1205}