editpe/
types.rs

1//! Portable executable data types.
2//!
3//! These types are a one-to-one mapping of the data described in <https://docs.microsoft.com/en-us/windows/win32/debug/pe-format>
4
5use alloc::string::{String, ToString};
6use core::{mem, slice};
7
8use zerocopy::{FromBytes, Immutable, IntoBytes};
9
10#[repr(C, packed(1))]
11#[derive(
12    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
13)]
14pub struct VersionU8 {
15    pub major: u8,
16    pub minor: u8,
17}
18#[repr(C, packed(2))]
19#[derive(
20    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
21)]
22pub struct VersionU16 {
23    pub major: u16,
24    pub minor: u16,
25}
26#[repr(C, packed(4))]
27#[derive(
28    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
29)]
30pub struct VersionU32 {
31    pub major: u32,
32    pub minor: u32,
33}
34#[repr(C, packed(2))]
35#[derive(
36    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
37)]
38pub struct CoffHeader {
39    pub machine:                 u16,
40    pub number_of_sections:      u16,
41    pub time_date_stamp:         u32,
42    pub pointer_to_symbol_table: u32,
43    pub number_of_symbols:       u32,
44    pub size_of_optional_header: u16,
45    pub characteristics:         u16,
46}
47#[repr(C, packed(2))]
48#[derive(
49    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
50)]
51pub struct StandardHeader {
52    pub magic:                      u16,
53    pub linker_version:             VersionU8,
54    pub size_of_code:               u32,
55    pub size_of_initialized_data:   u32,
56    pub size_of_uninitialized_data: u32,
57    pub address_of_entry_point:     u32,
58    pub base_of_code:               u32,
59}
60#[repr(C)]
61#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, Default)]
62pub struct WindowsHeader<UXX> {
63    pub image_base:               UXX,
64    pub section_alignment:        u32,
65    pub file_alignment:           u32,
66    pub operating_system_version: VersionU16,
67    pub image_version:            VersionU16,
68    pub subsystem_version:        VersionU16,
69    pub win32_version_value:      u32,
70    pub size_of_image:            u32,
71    pub size_of_headers:          u32,
72    pub check_sum:                u32,
73    pub subsystem:                u16,
74    pub dll_characteristics:      u16,
75    pub size_of_stack_reserve:    UXX,
76    pub size_of_stack_commit:     UXX,
77    pub size_of_heap_reserve:     UXX,
78    pub size_of_heap_commit:      UXX,
79    pub loader_flags:             u32,
80    pub number_of_rva_and_sizes:  u32,
81}
82impl<UXX> WindowsHeader<UXX>
83where
84    UXX: IntoBytes,
85{
86    pub fn as_bytes(&self) -> &[u8] {
87        // manually implement this here because zerocopy doesn't support derive for generic types
88        unsafe {
89            let len = mem::size_of_val(self);
90            slice::from_raw_parts(self as *const Self as *const u8, len)
91        }
92    }
93}
94
95#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
96pub enum GenericWindowsHeader {
97    WindowsHeader32(WindowsHeader<u32>),
98    WindowsHeader64(WindowsHeader<u64>),
99}
100impl GenericWindowsHeader {
101    pub fn as_bytes(&self) -> &[u8] {
102        match self {
103            GenericWindowsHeader::WindowsHeader32(header) => header.as_bytes(),
104            GenericWindowsHeader::WindowsHeader64(header) => header.as_bytes(),
105        }
106    }
107
108    pub const fn section_alignment(&self) -> u32 {
109        match self {
110            GenericWindowsHeader::WindowsHeader32(header) => header.section_alignment,
111            GenericWindowsHeader::WindowsHeader64(header) => header.section_alignment,
112        }
113    }
114
115    pub const fn file_alignment(&self) -> u32 {
116        match self {
117            GenericWindowsHeader::WindowsHeader32(header) => header.file_alignment,
118            GenericWindowsHeader::WindowsHeader64(header) => header.file_alignment,
119        }
120    }
121
122    pub const fn operating_system_version(&self) -> VersionU16 {
123        match self {
124            GenericWindowsHeader::WindowsHeader32(header) => header.operating_system_version,
125            GenericWindowsHeader::WindowsHeader64(header) => header.operating_system_version,
126        }
127    }
128
129    pub const fn image_version(&self) -> VersionU16 {
130        match self {
131            GenericWindowsHeader::WindowsHeader32(header) => header.image_version,
132            GenericWindowsHeader::WindowsHeader64(header) => header.image_version,
133        }
134    }
135
136    pub const fn subsystem_version(&self) -> VersionU16 {
137        match self {
138            GenericWindowsHeader::WindowsHeader32(header) => header.subsystem_version,
139            GenericWindowsHeader::WindowsHeader64(header) => header.subsystem_version,
140        }
141    }
142
143    pub const fn win32_version_value(&self) -> u32 {
144        match self {
145            GenericWindowsHeader::WindowsHeader32(header) => header.win32_version_value,
146            GenericWindowsHeader::WindowsHeader64(header) => header.win32_version_value,
147        }
148    }
149
150    pub const fn size_of_image(&self) -> u32 {
151        match self {
152            GenericWindowsHeader::WindowsHeader32(header) => header.size_of_image,
153            GenericWindowsHeader::WindowsHeader64(header) => header.size_of_image,
154        }
155    }
156
157    pub const fn size_of_headers(&self) -> u32 {
158        match self {
159            GenericWindowsHeader::WindowsHeader32(header) => header.size_of_headers,
160            GenericWindowsHeader::WindowsHeader64(header) => header.size_of_headers,
161        }
162    }
163
164    pub const fn check_sum(&self) -> u32 {
165        match self {
166            GenericWindowsHeader::WindowsHeader32(header) => header.check_sum,
167            GenericWindowsHeader::WindowsHeader64(header) => header.check_sum,
168        }
169    }
170
171    pub const fn subsystem(&self) -> u16 {
172        match self {
173            GenericWindowsHeader::WindowsHeader32(header) => header.subsystem,
174            GenericWindowsHeader::WindowsHeader64(header) => header.subsystem,
175        }
176    }
177
178    pub const fn dll_characteristics(&self) -> u16 {
179        match self {
180            GenericWindowsHeader::WindowsHeader32(header) => header.dll_characteristics,
181            GenericWindowsHeader::WindowsHeader64(header) => header.dll_characteristics,
182        }
183    }
184
185    pub const fn loader_flags(&self) -> u32 {
186        match self {
187            GenericWindowsHeader::WindowsHeader32(header) => header.loader_flags,
188            GenericWindowsHeader::WindowsHeader64(header) => header.loader_flags,
189        }
190    }
191
192    pub const fn number_of_rva_and_sizes(&self) -> u32 {
193        match self {
194            GenericWindowsHeader::WindowsHeader32(header) => header.number_of_rva_and_sizes,
195            GenericWindowsHeader::WindowsHeader64(header) => header.number_of_rva_and_sizes,
196        }
197    }
198}
199
200#[repr(C, packed(4))]
201#[derive(
202    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
203)]
204pub struct ImageDataDirectory {
205    pub virtual_address: u32,
206    pub size:            u32,
207}
208
209#[repr(C, packed(4))]
210#[derive(
211    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
212)]
213pub struct SectionHeader {
214    pub name:                   u64,
215    pub virtual_size:           u32,
216    pub virtual_address:        u32,
217    pub size_of_raw_data:       u32,
218    pub pointer_to_raw_data:    u32,
219    pub pointer_to_relocations: u32,
220    pub pointer_to_linenumbers: u32,
221    pub number_of_relocations:  u16,
222    pub number_of_linenumbers:  u16,
223    pub characteristics:        u32,
224}
225
226impl SectionHeader {
227    pub fn name(&self) -> Option<String> {
228        let name = self.name.to_le_bytes();
229        let name = core::str::from_utf8(
230            &name[0..name.iter().position(|&c| c == b'\0').unwrap_or(name.len())],
231        )
232        .ok();
233        name.map(|name| name.to_string())
234    }
235}
236
237#[repr(C, packed(2))]
238#[derive(
239    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
240)]
241pub struct ResourceDirectoryTable {
242    pub characteristics:        u32,
243    pub time_date_stamp:        u32,
244    pub version:                VersionU16,
245    pub number_of_name_entries: u16,
246    pub number_of_id_entries:   u16,
247}
248
249#[repr(C, packed(4))]
250#[derive(
251    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
252)]
253pub struct ResourceDirectoryEntry {
254    pub name_offset_or_integer_id:         u32,
255    pub data_entry_or_subdirectory_offset: u32,
256}
257
258#[repr(C, packed(4))]
259#[derive(
260    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
261)]
262pub struct ResourceDataEntry {
263    pub data_rva: u32,
264    pub size:     u32,
265    pub codepage: u32,
266    pub reserved: u32,
267}
268
269#[repr(C, packed(2))]
270#[derive(
271    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
272)]
273pub struct IconDirectory {
274    pub reserved: u16,
275    pub type_:    u16,
276    pub count:    u16,
277}
278
279#[repr(C, packed(1))]
280#[derive(
281    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
282)]
283pub struct IconDirectoryEntry {
284    pub width:       u8,
285    pub height:      u8,
286    pub color_count: u8,
287    pub reserved:    u8,
288    pub planes:      u16,
289    pub bit_count:   u16,
290    pub bytes:       u32,
291    pub id:          u16,
292}
293
294#[repr(C, packed(4))]
295#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable)]
296pub struct FixedFileInfo {
297    pub signature:       u32,
298    pub struct_version:  VersionU16,
299    pub file_version:    VersionU32,
300    pub product_version: VersionU32,
301    pub file_flags_mask: u32,
302    pub file_flags:      u32,
303    pub file_os:         u32,
304    pub file_type:       u32,
305    pub file_subtype:    u32,
306    pub file_date:       u64,
307}
308impl Default for FixedFileInfo {
309    fn default() -> Self {
310        Self {
311            signature:       0xfeef04bd,
312            struct_version:  VersionU16 { major: 0, minor: 1 },
313            file_version:    VersionU32 { major: 1, minor: 0 },
314            product_version: VersionU32 { major: 1, minor: 0 },
315            file_flags_mask: 0x0000003f,
316            file_flags:      0x00000000,
317            file_os:         0x00040004,
318            file_type:       0x00000001,
319            file_subtype:    0x00000000,
320            file_date:       0x00000000,
321        }
322    }
323}
324
325#[repr(C, packed(2))]
326#[derive(
327    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, FromBytes, IntoBytes, Immutable, Default,
328)]
329pub struct VersionHeader {
330    pub length:       u16,
331    pub value_length: u16,
332    pub type_:        u16,
333}