pe_parser/optional.rs
1use bytemuck::{Pod, Zeroable, checked::{try_from_bytes}};
2use num_derive::FromPrimitive;
3use num_traits::FromPrimitive;
4use bitflags::bitflags;
5use core::{fmt, str};
6use crate::{prelude::*, Error};
7
8/// Magic values that determine if an Optional Header is
9/// PE32 (32-bit) or PE32+ (64-bit)
10#[derive(FromPrimitive, Debug)]
11#[repr(u16)]
12pub enum Magic {
13 /// Magic value for 32-bit PEs
14 PE32 = 0x10b,
15 /// Magic value for 64-bit PEs
16 PE64 = 0x20b
17}
18
19/// Struct containing basic information (address and size) of each table.
20#[derive(Copy, Clone, Pod, Zeroable, Default)]
21#[repr(C)]
22pub struct DataDirectories {
23 /// The export table (.edata) address and size. (Image Only)
24 pub export_table: DataDirectory,
25 /// The import table (.idata) address and size.
26 pub import_table: DataDirectory,
27 /// The resource table (.rsrc) address and size.
28 pub resource_table: DataDirectory,
29 /// The exception table (.pdata) address and size.
30 pub exception_table: DataDirectory,
31 /// The attribute certificate table address and size. (Image Only)
32 pub certificate_table: DataDirectory,
33 /// The base relocation table (.reloc) address and size. (Image Only)
34 pub base_relocation_table: DataDirectory,
35 /// The debug data (.debug) starting address and size.
36 pub debug: DataDirectory,
37 /// Reserved, must be 0.
38 pub architecture: DataDirectory,
39 /// The RVA of the value to be stored in the global pointer register.
40 /// The size member of this structure must be set to zero.
41 pub global_ptr: DataDirectory,
42 /// The thread local storage (TLS) table (.tls) address and size.
43 pub tls_table: DataDirectory,
44 /// The load configuration table address and size. (Image Only)
45 pub load_config_table: DataDirectory,
46 /// The bound import table address and size.
47 pub bound_import: DataDirectory,
48 /// The import address table address and size.
49 pub import_address_table: DataDirectory,
50 /// The delay import descriptor address and size. (Image Only)
51 pub delay_import_descriptor: DataDirectory,
52 /// The CLR runtime header (.cormeta) address and size. (Object Only
53 pub clr_runtime_header: DataDirectory,
54 /// Reserved, must be zero.
55 pub reserved: DataDirectory
56}
57
58impl fmt::Display for DataDirectories {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 writeln!(f, "Data Directories")?;
61 writeln!(f, "----------------")?;
62 writeln!(f, "Export Table: {:#010x} ({})", self.export_table.virtual_address, self.export_table.size)?;
63 writeln!(f, "Import Table: {:#010x} ({})", self.import_table.virtual_address, self.import_table.size)?;
64 writeln!(f, "Resource Table: {:#010x} ({})", self.resource_table.virtual_address, self.resource_table.size)?;
65 writeln!(f, "Exception Table: {:#010x} ({})", self.exception_table.virtual_address, self.exception_table.size)?;
66 writeln!(f, "Certificiate Table: {:#010x} ({})", self.certificate_table.virtual_address, self.certificate_table.size)?;
67 writeln!(f, "Base Relocation Table: {:#010x} ({})", self.base_relocation_table.virtual_address, self.base_relocation_table.size)?;
68 writeln!(f, "Debug: {:#010x} ({})", self.debug.virtual_address, self.debug.size)?;
69 writeln!(f, "Architecture: {:#010x} ({})", self.architecture.virtual_address, self.architecture.size)?;
70 writeln!(f, "Global Pointer: {:#010x} ({})", self.global_ptr.virtual_address, self.global_ptr.size)?;
71 writeln!(f, "TLS Table: {:#010x} ({})", self.tls_table.virtual_address, self.tls_table.size)?;
72 writeln!(f, "Load Config Table: {:#010x} ({})", self.load_config_table.virtual_address, self.load_config_table.size)?;
73 writeln!(f, "Bound Import: {:#010x} ({})", self.bound_import.virtual_address, self.bound_import.size)?;
74 writeln!(f, "Import Address Table: {:#010x} ({})", self.import_address_table.virtual_address, self.import_address_table.size)?;
75 writeln!(f, "Delay Import Descriptor: {:#010x} ({})", self.delay_import_descriptor.virtual_address, self.delay_import_descriptor.size)?;
76 writeln!(f, "CLR Runtime Header: {:#010x} ({})", self.clr_runtime_header.virtual_address, self.clr_runtime_header.size)?;
77 writeln!(f, "Reserved: {:#010x} ({})", self.reserved.virtual_address, self.reserved.size)?;
78
79 Ok(())
80 }
81}
82
83/// Each data directory gives the address and size of a table or string that Windows uses.
84/// These data directory entries are all loaded into memory so that the system can use them at run time.
85/// A data directory is an 8-byte field that has the following declaration:
86#[derive(Copy, Clone, Pod, Zeroable, Default)]
87#[repr(C)]
88pub struct DataDirectory {
89 /// RVA of the table. The RVA is the address of the table relative to the base address of the image when the table is loaded.
90 pub virtual_address: u32,
91 /// Size of the table in bytes.
92 pub size: u32
93}
94
95/// PE32 Optional Header (Image Only)
96#[derive(Copy, Clone, Pod, Zeroable, Default)]
97#[repr(C)]
98pub struct OptionalHeader32 {
99 /// The unsigned integer that identifies the state of the image file.
100 /// The most common number is 0x10B, which identifies it as a normal executable file.
101 /// 0x107 identifies it as a ROM image, and 0x20B identifies it as a PE32+ executable.
102 pub magic: u16,
103 /// The linker major version number.
104 pub major_linker_version: u8,
105 /// The linker minor version number.
106 pub minor_linker_version: u8,
107 /// The size of the code (text) section, or the sum of all code sections if there are multiple sections.
108 pub size_of_code: u32,
109 /// The size of the initialized data section, or the sum of all such sections if there are multiple data sections.
110 pub size_of_initialized_data: u32,
111 /// The size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections.
112 pub size_of_uninitialized_data: u32,
113 /// The address of the entry point relative to the image base when the executable file is loaded into memory.
114 /// For program images, this is the starting address.
115 /// For device drivers, this is the address of the initialization function.
116 /// An entry point is optional for DLLs. When no entry point is present, this field must be zero.
117 pub address_of_entry_point: u32,
118 /// The address that is relative to the image base of the beginning-of-code section when it is loaded into memory.
119 pub base_of_code: u32,
120 /// (PE32 Only) The address that is relative to the image base of the beginning-of-data section when it is loaded into memory.
121 pub base_of_data: u32,
122 /// The preferred address of the first byte of image when loaded into memory; must be a multiple of 64 K.
123 /// The default for DLLs is 0x10000000. The default for Windows CE EXEs is 0x00010000.
124 /// The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000.
125 pub image_base: u32,
126 /// The alignment (in bytes) of sections when they are loaded into memory.
127 /// It must be greater than or equal to `file_alignment`. The default is the page size for the architecture.
128 pub section_alignment: u32,
129 /// The alignment factor (in bytes) that is used to align the raw data of sections in the image file.
130 /// The value should be a power of 2 between 512 and 64 K, inclusive. The default is 512.
131 /// If the `section_alignment` is less than the architecture's page size, then `file_alignment` must match `section_alignment`.
132 pub file_alignment: u32,
133 /// The major version number of the required operating system.
134 pub major_operating_system_version: u16,
135 /// The minor version number of the required operating system.
136 pub minor_operating_system_version: u16,
137 /// The major version number of the image.
138 pub major_image_version: u16,
139 /// The minor version number of the image.
140 pub minor_image_version: u16,
141 /// The major version number of the subsystem.
142 pub major_subsystem_version: u16,
143 /// The minor version number of the subsystem.
144 pub minor_subsystem_version: u16,
145 /// Reserved, must be zero.
146 pub win32_version_value: u32,
147 /// The size (in bytes) of the image, including all headers, as the image is loaded in memory. It must be a multiple of `section_alignment`.
148 pub size_of_image: u32,
149 /// The combined size of an MS-DOS stub, PE header, and section headers rounded up to a multiple of `file_alignment`.
150 pub size_of_headers: u32,
151 /// The image file checksum. The algorithm for computing the checksum is incorporated into IMAGHELP.DLL.
152 /// The following are checked for validation at load time: all drivers, any DLL loaded at boot time, and any DLL that is loaded into a critical Windows process.
153 pub check_sum: u32,
154 /// The subsystem that is required to run this image.
155 pub subsystem: u16,
156 /// Bitflag characteristics that describe how a DLL should be loaded.
157 pub dll_characteristics: u16,
158 /// The size of the stack to reserve. Only `size_of_stack_commit` is committed; the rest is made available one page at a time until the reserve size is reached.
159 pub size_of_stack_reserve: u32,
160 /// The size of the stack to commit.
161 pub size_of_stack_commit: u32,
162 /// The size of the local heap space to reserve. Only `size_of_heap_commit` is committed; the rest is made available one page at a time until the reserve size is reached.
163 pub size_of_heap_reserve: u32,
164 /// The size of the local heap space to commit.
165 pub size_of_heap_commit: u32,
166 /// Reserved, must be zero.
167 pub loader_flags: u32,
168 /// The number of data-directory entries in the remainder of the optional header. Each describes a location and size.
169 pub number_of_rva_and_sizes: u32,
170 /// Struct containing basic information (address and size) of each table.
171 pub data_directories: DataDirectories
172}
173
174impl fmt::Display for OptionalHeader32 {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 let subsystem = self.get_subsystem()
177 .expect("Failed to get subsystem");
178 let dll_characteristics = self.get_dll_characteristics()
179 .expect("Failed to get DLL characteristics");
180
181 writeln!(f, "Optional Header")?;
182 writeln!(f, "---------------")?;
183 writeln!(f, "Magic: PE32")?;
184 writeln!(f, "Linker Version: {}.{}", self.major_linker_version, self.minor_linker_version)?;
185 writeln!(f, "Size of Code: {}", self.size_of_code)?;
186 writeln!(f, "Size of Initialized Data: {}", self.size_of_initialized_data)?;
187 writeln!(f, "Size of Uninitialized Data: {}", self.size_of_uninitialized_data)?;
188 writeln!(f, "Address of Entry Point: {:#010x}", self.address_of_entry_point)?;
189 writeln!(f, "Base of Code: {:#010x}", self.base_of_code)?;
190 writeln!(f, "Base of Data: {:#010x}", self.base_of_data)?;
191 writeln!(f, "Image Base: {:#010x}", self.image_base)?;
192 writeln!(f, "Section Alignment: {}", self.section_alignment)?;
193 writeln!(f, "File Alignment: {}", self.file_alignment)?;
194 writeln!(f, "Operating System Version: {}.{}", self.major_operating_system_version, self.minor_operating_system_version)?;
195 writeln!(f, "Image Version: {}.{}", self.major_image_version, self.minor_image_version)?;
196 writeln!(f, "Subsystem Version: {}.{}", self.major_subsystem_version, self.minor_linker_version)?;
197 writeln!(f, "Win32 Version Value: {}", self.win32_version_value)?;
198 writeln!(f, "Size of Image: {}", self.size_of_image)?;
199 writeln!(f, "Size of Headers: {}", self.size_of_headers)?;
200 writeln!(f, "CheckSum: {}", self.check_sum)?;
201 writeln!(f, "Subsystem: {:?}", subsystem)?;
202 writeln!(f, "DLL Characteristics: {}", dll_characteristics)?;
203 writeln!(f, "Size of Stack Reserve: {}", self.size_of_stack_reserve)?;
204 writeln!(f, "Size of Stack Commit: {}", self.size_of_stack_commit)?;
205 writeln!(f, "Size of Heap Reserve: {}", self.size_of_heap_reserve)?;
206 writeln!(f, "Size of Heap Commit: {}", self.size_of_heap_commit)?;
207 writeln!(f, "Loader Flags: {}", self.loader_flags)?;
208 writeln!(f, "Number of RVA and Sizes: {}", self.number_of_rva_and_sizes)?;
209 write!(f, "\n{}", self.data_directories)?;
210
211 Ok(())
212 }
213}
214
215/// PE32+ Optional Header (Image Only)
216#[derive(Copy, Clone, Pod, Zeroable, Default)]
217#[repr(C)]
218pub struct OptionalHeader64 {
219 /// The unsigned integer that identifies the state of the image file.
220 /// The most common number is 0x10B, which identifies it as a normal executable file.
221 /// 0x107 identifies it as a ROM image, and 0x20B identifies it as a PE32+ executable.
222 pub magic: u16,
223 /// The linker major version number.
224 pub major_linker_version: u8,
225 /// The linker minor version number.
226 pub minor_linker_version: u8,
227 /// The size of the code (text) section, or the sum of all code sections if there are multiple sections.
228 pub size_of_code: u32,
229 /// The size of the initialized data section, or the sum of all such sections if there are multiple data sections.
230 pub size_of_initialized_data: u32,
231 /// The size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections.
232 pub size_of_uninitialized_data: u32,
233 /// The address of the entry point relative to the image base when the executable file is loaded into memory.
234 /// For program images, this is the starting address.
235 /// For device drivers, this is the address of the initialization function.
236 /// An entry point is optional for DLLs. When no entry point is present, this field must be zero.
237 pub address_of_entry_point: u32,
238 /// The address that is relative to the image base of the beginning-of-code section when it is loaded into memory.
239 pub base_of_code: u32,
240 /// The preferred address of the first byte of image when loaded into memory; must be a multiple of 64 K.
241 /// The default for DLLs is 0x10000000. The default for Windows CE EXEs is 0x00010000.
242 /// The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000.
243 pub image_base: u64,
244 /// The alignment (in bytes) of sections when they are loaded into memory.
245 /// It must be greater than or equal to `file_alignment`. The default is the page size for the architecture.
246 pub section_alignment: u32,
247 /// The alignment factor (in bytes) that is used to align the raw data of sections in the image file.
248 /// The value should be a power of 2 between 512 and 64 K, inclusive. The default is 512.
249 /// If the `section_alignment` is less than the architecture's page size, then `file_alignment` must match `section_alignment`.
250 pub file_alignment: u32,
251 /// The major version number of the required operating system.
252 pub major_operating_system_version: u16,
253 /// The minor version number of the required operating system.
254 pub minor_operating_system_version: u16,
255 /// The major version number of the image.
256 pub major_image_version: u16,
257 /// The minor version number of the image.
258 pub minor_image_version: u16,
259 /// The major version number of the subsystem.
260 pub major_subsystem_version: u16,
261 /// The minor version number of the subsystem.
262 pub minor_subsystem_version: u16,
263 /// Reserved, must be zero.
264 pub win32_version_value: u32,
265 /// The size (in bytes) of the image, including all headers, as the image is loaded in memory. It must be a multiple of `section_alignment`.
266 pub size_of_image: u32,
267 /// The combined size of an MS-DOS stub, PE header, and section headers rounded up to a multiple of `file_alignment`.
268 pub size_of_headers: u32,
269 /// The image file checksum. The algorithm for computing the checksum is incorporated into IMAGHELP.DLL.
270 /// The following are checked for validation at load time: all drivers, any DLL loaded at boot time, and any DLL that is loaded into a critical Windows process.
271 pub check_sum: u32,
272 /// The subsystem that is required to run this image.
273 pub subsystem: u16,
274 /// Bitflag characteristics that describe how a DLL should be loaded.
275 pub dll_characteristics: u16,
276 /// The size of the stack to reserve. Only `size_of_stack_commit` is committed; the rest is made available one page at a time until the reserve size is reached.
277 pub size_of_stack_reserve: u64,
278 /// The size of the stack to commit.
279 pub size_of_stack_commit: u64,
280 /// The size of the local heap space to reserve. Only `size_of_heap_commit` is committed; the rest is made available one page at a time until the reserve size is reached.
281 pub size_of_heap_reserve: u64,
282 /// The size of the local heap space to commit.
283 pub size_of_heap_commit: u64,
284 /// Reserved, must be zero.
285 pub loader_flags: u32,
286 /// The number of data-directory entries in the remainder of the optional header. Each describes a location and size.
287 pub number_of_rva_and_sizes: u32,
288 /// Struct containing basic information (address and size) of each table.
289 pub data_directories: DataDirectories
290}
291
292impl fmt::Display for OptionalHeader64 {
293 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294 let subsystem = self.get_subsystem()
295 .expect("Failed to get subsystem");
296 let dll_characteristics = self.get_dll_characteristics()
297 .expect("Failed to get DLL characteristics");
298
299 writeln!(f, "Optional Header")?;
300 writeln!(f, "---------------")?;
301 writeln!(f, "Magic: PE32+")?;
302 writeln!(f, "Linker Version: {}.{}", self.major_linker_version, self.minor_linker_version)?;
303 writeln!(f, "Size of Code: {}", self.size_of_code)?;
304 writeln!(f, "Size of Initialized Data: {}", self.size_of_initialized_data)?;
305 writeln!(f, "Size of Uninitialized Data: {}", self.size_of_uninitialized_data)?;
306 writeln!(f, "Address of Entry Point: {:#010x}", self.address_of_entry_point)?;
307 writeln!(f, "Base of Code: {:#010x}", self.base_of_code)?;
308 writeln!(f, "Image Base: {:#010x}", self.image_base)?;
309 writeln!(f, "Section Alignment: {}", self.section_alignment)?;
310 writeln!(f, "File Alignment: {}", self.file_alignment)?;
311 writeln!(f, "Operating System Version: {}.{}", self.major_operating_system_version, self.minor_operating_system_version)?;
312 writeln!(f, "Image Version: {}.{}", self.major_image_version, self.minor_image_version)?;
313 writeln!(f, "Subsystem Version: {}.{}", self.major_subsystem_version, self.minor_linker_version)?;
314 writeln!(f, "Win32 Version Value: {}", self.win32_version_value)?;
315 writeln!(f, "Size of Image: {}", self.size_of_image)?;
316 writeln!(f, "Size of Headers: {}", self.size_of_headers)?;
317 writeln!(f, "CheckSum: {}", self.check_sum)?;
318 writeln!(f, "Subsystem: {:?}", subsystem)?;
319 writeln!(f, "DLL Characteristics: {}", dll_characteristics)?;
320 writeln!(f, "Size of Stack Reserve: {}", self.size_of_stack_reserve)?;
321 writeln!(f, "Size of Stack Commit: {}", self.size_of_stack_commit)?;
322 writeln!(f, "Size of Heap Reserve: {}", self.size_of_heap_reserve)?;
323 writeln!(f, "Size of Heap Commit: {}", self.size_of_heap_commit)?;
324 writeln!(f, "Loader Flags: {}", self.loader_flags)?;
325 writeln!(f, "Number of RVA and Sizes: {}", self.number_of_rva_and_sizes)?;
326 write!(f, "\n{}", self.data_directories)?;
327
328 Ok(())
329 }
330}
331
332/// The following values defined for the Subsystem field of the optional header
333/// determine which Windows subsystem (if any) is required to run the image.
334#[derive(FromPrimitive, Debug)]
335#[repr(u16)]
336pub enum Subsystem {
337 /// An unknown subsystem
338 Unknown = 0,
339 /// Device drivers and native Windows processes
340 Native = 1,
341 /// The Windows graphical user interface (GUI) subsystem
342 WindowsGUI = 2,
343 /// The Windows character subsystem
344 WindowsCUI = 3,
345 /// The OS/2 character subsystem
346 OS2CUI = 5,
347 /// The Posix character subsystem
348 PosixCUI = 7,
349 /// Native Win9x driver
350 NativeWindows = 8,
351 /// Windows CE
352 WindowsCEGUI = 9,
353 /// An Extensible Firmware Interface (EFI) application
354 EFIApplication = 10,
355 /// An EFI driver with boot services
356 EFIBootServiceDriver = 11,
357 /// An EFI driver with run-time services
358 EFIRuntimeDriver = 12,
359 /// An EFI ROM image
360 EFIROM = 13,
361 /// XBOX
362 XBOX = 14,
363 /// Windows boot application
364 WindowsBootApplication = 16
365}
366
367bitflags! {
368 /// Bitflags that contain various information about
369 /// how a given DLL should be loaded.
370 pub struct DLLCharacteristics: u16 {
371 /// Reserved, must be zero.
372 const IMAGE_DLLCHARACTERISTICS_RESERVED1 = 0x0001;
373 /// Reserved, must be zero.
374 const IMAGE_DLLCHARACTERISTICS_RESERVED2 = 0x0002;
375 /// Reserved, must be zero.
376 const IMAGE_DLLCHARACTERISTICS_RESERVED4 = 0x0004;
377 /// Reserved, must be zero.
378 const IMAGE_DLLCHARACTERISTICS_RESERVED8 = 0x0008;
379 /// Image can handle a high entropy 64-bit virtual address space.
380 const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020;
381 /// DLL can be relocated at load time.
382 const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040;
383 /// Code Integrity checks are enforced.
384 const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080;
385 /// Image is NX compatible.
386 const IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100;
387 /// Isolation aware, but do not isolate the image.
388 const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200;
389 /// Does not use structured exception (SE) handling.
390 /// No SE handler may be called in this image.
391 const IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400;
392 /// Do not bind the image.
393 const IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800;
394 /// Image must execute in an AppContainer.
395 const IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000;
396 /// A WDM driver.
397 const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000;
398 /// Image supports Control Flow Guard.
399 const IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000;
400 /// Terminal Server aware.
401 const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000;
402 }
403}
404
405// Allow DLL Characteristics flags to be easily printed
406impl fmt::Debug for DLLCharacteristics {
407 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
408 fmt::Debug::fmt(&self.0, f)
409 }
410}
411
412impl fmt::Display for DLLCharacteristics {
413 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
414 fmt::Display::fmt(&self.0, f)
415 }
416}
417
418impl str::FromStr for DLLCharacteristics {
419 type Err = bitflags::parser::ParseError;
420
421 fn from_str(flags: &str) -> Result<Self, Self::Err> {
422 Ok(Self(flags.parse()?))
423 }
424}
425
426/// Helper functions for optional header structs
427pub trait Optional: Sized {
428 /// Returns the subsystem as an enum
429 fn get_subsystem(&self) -> Option<Subsystem>;
430 /// Returns the DLL Characteristics as bitflags
431 fn get_dll_characteristics(&self) -> Option<DLLCharacteristics>;
432 /// Parse optional header (either PE32, or PE32+) starting at
433 /// the given offset.
434 fn parse_optional_header(binary: &[u8], offset: &mut usize) -> Result<Self, Error>;
435}
436
437impl Optional for OptionalHeader32 {
438 fn get_subsystem(&self) -> Option<Subsystem> {
439 Subsystem::from_u16(self.subsystem)
440 }
441
442 fn get_dll_characteristics(&self) -> Option<DLLCharacteristics> {
443 DLLCharacteristics::from_bits(self.dll_characteristics)
444 }
445
446 fn parse_optional_header(binary: &[u8], offset: &mut usize) -> Result<Self, Error> {
447 let size = size_of::<Self>();
448 let slice = match binary.get(*offset..*offset+size) {
449 Some(slice) => slice,
450 None => {
451 return Err(Error::OffsetOutOfRange);
452 }
453 };
454
455 let optional_header = try_from_bytes::<OptionalHeader32>(slice);
456 *offset += size;
457
458 match optional_header.copied() {
459 Ok(header) => {
460 Ok(header)
461 }
462 Err(_) => {
463 Err(Error::BadOptionalHeader)
464 }
465 }
466 }
467}
468
469impl Optional for OptionalHeader64 {
470 fn get_subsystem(&self) -> Option<Subsystem> {
471 Subsystem::from_u16(self.subsystem)
472 }
473
474 fn get_dll_characteristics(&self) -> Option<DLLCharacteristics> {
475 DLLCharacteristics::from_bits(self.dll_characteristics)
476 }
477
478 fn parse_optional_header(binary: &[u8], offset: &mut usize) -> Result<Self, Error> {
479 let size = size_of::<Self>();
480 let slice = match binary.get(*offset..*offset+size) {
481 Some(slice) => slice,
482 None => {
483 return Err(Error::OffsetOutOfRange);
484 }
485 };
486
487 let optional_header = try_from_bytes::<OptionalHeader64>(slice);
488 *offset += size;
489 match optional_header.copied() {
490 Ok(header) => {
491 Ok(header)
492 }
493 Err(_) => {
494 Err(Error::BadOptionalHeader)
495 }
496 }
497 }
498}