Skip to main content

pe_assembler/types/
mod.rs

1#![doc = include_str!("readme.md")]
2
3pub use self::{
4    dos::DosHeader,
5    nt::NtHeader,
6    tables::{ExportTable, ImportEntry, ImportTable},
7};
8use byteorder::{LittleEndian, ReadBytesExt};
9use gaia_types::helpers::Architecture;
10use serde::{Deserialize, Serialize};
11use std::{
12    fmt::{Display, Formatter},
13    io::{Read, Write},
14};
15
16pub mod coff;
17mod dos;
18mod nt;
19pub mod tables;
20
21pub use coff::*;
22use gaia_types::GaiaError;
23
24/// PE 子系统类型枚举
25///
26/// 定义了 Windows PE 文件可以使用的各种子系统类型,
27/// 这些类型决定了程序运行时的环境和依赖。
28#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
29pub enum SubsystemType {
30    /// 控制台应用程序,运行在控制台窗口中
31    Console,
32    /// Windows GUI 应用程序,具有图形界面
33    Windows,
34    /// 原生驱动程序,运行在核心态
35    Native,
36    /// POSIX 子系统应用程序
37    Posix,
38    /// Windows CE 子系统
39    WindowsCe,
40    /// EFI 应用程序
41    Efi,
42    /// EFI 启动服务驱动程序
43    EfiBootServiceDriver,
44    /// EFI 运行时驱动程序
45    EfiRuntimeDriver,
46    /// EFI ROM 映像
47    EfiRom,
48    /// Xbox 应用程序
49    Xbox,
50    /// Windows 启动应用程序
51    WindowsBootApplication,
52}
53
54impl Display for SubsystemType {
55    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
56        match self {
57            SubsystemType::Console => write!(f, "控制台应用程序"),
58            SubsystemType::Windows => write!(f, "Windows GUI 应用程序"),
59            SubsystemType::Native => write!(f, "原生驱动程序"),
60            SubsystemType::Posix => write!(f, "POSIX 子系统应用程序"),
61            SubsystemType::WindowsCe => write!(f, "Windows CE 子系统"),
62            SubsystemType::Efi => write!(f, "EFI 应用程序"),
63            SubsystemType::EfiBootServiceDriver => write!(f, "EFI 启动服务驱动程序"),
64            SubsystemType::EfiRuntimeDriver => write!(f, "EFI 运行时驱动程序"),
65            SubsystemType::EfiRom => write!(f, "EFI ROM 映像"),
66            SubsystemType::Xbox => write!(f, "Xbox 应用程序"),
67            SubsystemType::WindowsBootApplication => write!(f, "Windows 启动应用程序"),
68        }
69    }
70}
71
72impl From<u16> for SubsystemType {
73    /// 从 u16 值创建子系统类型
74    ///
75    /// # Arguments
76    /// * `value` - 子系统类型的数值
77    ///
78    /// # Returns
79    /// 返回对应的子系统类型,未知类型返回 Console
80    fn from(value: u16) -> Self {
81        match value {
82            1 => SubsystemType::Native,
83            2 => SubsystemType::Windows,
84            3 => SubsystemType::Console,
85            7 => SubsystemType::Posix,
86            9 => SubsystemType::WindowsCe,
87            10 => SubsystemType::Efi,
88            11 => SubsystemType::EfiBootServiceDriver,
89            12 => SubsystemType::EfiRuntimeDriver,
90            13 => SubsystemType::EfiRom,
91            14 => SubsystemType::Xbox,
92            16 => SubsystemType::WindowsBootApplication,
93            _ => SubsystemType::Console, // 默认值
94        }
95    }
96}
97
98impl Default for DataDirectory {
99    fn default() -> Self {
100        Self { virtual_address: 0, size: 0 }
101    }
102}
103
104/// 可选头结构
105///
106/// 包含 PE 文件的加载和运行时信息,如入口点地址、内存布局、
107/// 版本信息等。这个结构对于 Windows 加载器正确加载和执行程序至关重要。
108#[derive(Clone, Debug, Serialize, Deserialize)]
109pub struct OptionalHeader {
110    /// 魔数,标识 PE32 或 PE32+ 格式
111    pub magic: u16,
112    /// 链接器的主版本号
113    pub major_linker_version: u8,
114    /// 链接器的次版本号
115    pub minor_linker_version: u8,
116    /// 代码节的总大小(以字节为单位)
117    pub size_of_code: u32,
118    /// 已初始化数据的总大小
119    pub size_of_initialized_data: u32,
120    /// 未初始化数据的总大小
121    pub size_of_uninitialized_data: u32,
122    /// 程序入口点的 RVA(相对虚拟地址)
123    pub address_of_entry_point: u32,
124    /// 代码节的起始 RVA
125    pub base_of_code: u32,
126    /// 数据节的起始 RVA,仅 PE32 格式有效
127    pub base_of_data: Option<u32>, // Only for PE32
128    /// 映像的首选加载地址
129    pub image_base: u64,
130    /// 节在内存中的对齐粒度
131    pub section_alignment: u32,
132    /// 节在文件中的对齐粒度
133    pub file_alignment: u32,
134    /// 所需操作系统的主版本号
135    pub major_operating_system_version: u16,
136    /// 所需操作系统的次版本号
137    pub minor_operating_system_version: u16,
138    /// 映像的主版本号
139    pub major_image_version: u16,
140    /// 映像的次版本号
141    pub minor_image_version: u16,
142    /// 子系统的主版本号
143    pub major_subsystem_version: u16,
144    /// 子系统的次版本号
145    pub minor_subsystem_version: u16,
146    /// 保留字段,必须为 0
147    pub win32_version_value: u32,
148    /// 映像的总大小,包括所有头文件和节
149    pub size_of_image: u32,
150    /// 所有头文件的总大小
151    pub size_of_headers: u32,
152    /// 映像的校验和,用于内核模式和系统 DLL
153    pub checksum: u32,
154    /// 子系统类型,定义程序运行环境
155    pub subsystem: SubsystemType,
156    /// DLL 特征标志,描述 DLL 的各种属性
157    pub dll_characteristics: u16,
158    /// 为线程栈保留的虚拟内存大小
159    pub size_of_stack_reserve: u64,
160    /// 为线程栈提交的虚拟内存大小
161    pub size_of_stack_commit: u64,
162    /// 为进程堆保留的虚拟内存大小
163    pub size_of_heap_reserve: u64,
164    /// 为进程堆提交的虚拟内存大小
165    pub size_of_heap_commit: u64,
166    /// 保留字段,必须为 0
167    pub loader_flags: u32,
168    /// 数据目录表的条目数量
169    pub number_of_rva_and_sizes: u32,
170    /// 数据目录表,包含各种数据目录的信息
171    pub data_directories: Vec<DataDirectory>,
172}
173
174impl OptionalHeader {
175    /// 创建一个标准的可选头,适用于 .NET 程序
176    pub fn new(
177        entry_point: u32,
178        image_base: u64,
179        size_of_code: u32,
180        size_of_headers: u32,
181        size_of_image: u32,
182        subsystem: SubsystemType,
183    ) -> Self {
184        let mut data_directories = Vec::with_capacity(16);
185        // 初始化 16 个标准数据目录
186        for _ in 0..16 {
187            data_directories.push(DataDirectory::default());
188        }
189
190        Self {
191            magic: 0x020B, // PE32+
192            major_linker_version: 14,
193            minor_linker_version: 0,
194            size_of_code,
195            size_of_initialized_data: 0,
196            size_of_uninitialized_data: 0,
197            address_of_entry_point: entry_point,
198            base_of_code: 0x2000,
199            base_of_data: None, // PE32+ 不使用
200            image_base,
201            section_alignment: 0x2000,
202            file_alignment: 0x200,
203            major_operating_system_version: 6,
204            minor_operating_system_version: 0,
205            major_image_version: 0,
206            minor_image_version: 0,
207            major_subsystem_version: 6,
208            minor_subsystem_version: 0,
209            win32_version_value: 0,
210            size_of_image,
211            size_of_headers,
212            checksum: 0,
213            subsystem,
214            // 关闭 DYNAMIC_BASE 以确保固定映像基址 (0x400000),避免绝对地址失效
215            // 保留 NX_COMPAT、NO_SEH、TERMINAL_SERVER_AWARE
216            dll_characteristics: 0x8500, // NX_COMPAT | NO_SEH | TERMINAL_SERVER_AWARE
217            size_of_stack_reserve: 0x100000,
218            size_of_stack_commit: 0x1000,
219            size_of_heap_reserve: 0x100000,
220            size_of_heap_commit: 0x1000,
221            loader_flags: 0,
222            number_of_rva_and_sizes: 16,
223            data_directories,
224        }
225    }
226
227    /// 根据架构创建可选头
228    pub fn new_for_architecture(
229        architecture: &Architecture,
230        entry_point: u32,
231        image_base: u64,
232        size_of_code: u32,
233        size_of_headers: u32,
234        size_of_image: u32,
235        subsystem: SubsystemType,
236    ) -> Self {
237        let mut data_directories = Vec::with_capacity(16);
238        // 初始化 16 个标准数据目录
239        for _ in 0..16 {
240            data_directories.push(DataDirectory::default());
241        }
242
243        let (magic, base_of_data) = match architecture {
244            Architecture::X86 => (0x010B, Some(0x2000)), // PE32
245            Architecture::X86_64 => (0x020B, None),      // PE32+
246            _ => (0x010B, Some(0x2000)),                 // 默认为 PE32
247        };
248
249        Self {
250            magic,
251            major_linker_version: 14,
252            minor_linker_version: 0,
253            size_of_code,
254            size_of_initialized_data: 0,
255            size_of_uninitialized_data: 0,
256            address_of_entry_point: entry_point,
257            base_of_code: 0x1000,
258            base_of_data,
259            image_base,
260            section_alignment: 0x1000,
261            file_alignment: 0x200,
262            major_operating_system_version: 6,
263            minor_operating_system_version: 0,
264            major_image_version: 0,
265            minor_image_version: 0,
266            major_subsystem_version: 6,
267            minor_subsystem_version: 0,
268            win32_version_value: 0,
269            size_of_image,
270            size_of_headers,
271            checksum: 0,
272            subsystem,
273            dll_characteristics: 0x8160, // DYNAMIC_BASE | NX_COMPAT | NO_SEH | TERMINAL_SERVER_AWARE
274            size_of_stack_reserve: 0x100000,
275            size_of_stack_commit: 0x1000,
276            size_of_heap_reserve: 0x100000,
277            size_of_heap_commit: 0x1000,
278            loader_flags: 0,
279            number_of_rva_and_sizes: 16,
280            data_directories,
281        }
282    }
283}
284
285/// PE 头结构
286///
287/// 包含 PE 文件的所有头部信息,是 DOS 头、NT 头、COFF 头和可选头的组合。
288/// 这个结构提供了完整的 PE 文件元数据信息。
289#[derive(Clone, Debug, Serialize, Deserialize)]
290pub struct PeHeader {
291    /// DOS 头,包含 DOS 兼容性信息
292    pub dos_header: DosHeader,
293    /// NT 头,包含 PE 签名
294    pub nt_header: NtHeader,
295    /// COFF 头,包含目标文件信息
296    pub coff_header: CoffHeader,
297    /// 可选头,包含加载和运行时信息
298    pub optional_header: OptionalHeader,
299}
300
301/// PE 节结构
302///
303/// 包含 PE 文件中每个节的详细信息,包括节名、虚拟地址、大小等属性。
304/// 节是 PE 文件中的基本组织单位,不同的节包含不同类型的数据(如代码、数据、资源等)。
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct PeSection {
307    /// 节名称,最多8个字符
308    pub name: String,
309    /// 节在内存中的虚拟大小
310    pub virtual_size: u32,
311    /// 节在内存中的虚拟地址
312    pub virtual_address: u32,
313    /// 节在文件中的原始数据大小
314    pub size_of_raw_data: u32,
315    /// 节在文件中的原始数据指针
316    pub pointer_to_raw_data: u32,
317    /// 重定位表指针
318    pub pointer_to_relocations: u32,
319    /// 行号表指针
320    pub pointer_to_line_numbers: u32,
321    /// 重定位项数量
322    pub number_of_relocations: u16,
323    /// 行号数量
324    pub number_of_line_numbers: u16,
325    /// 节特征标志
326    pub characteristics: u32,
327    /// 节的原始数据
328    #[serde(skip_serializing_if = "Vec::is_empty")]
329    pub data: Vec<u8>,
330}
331
332/// PE 文件读取配置
333///
334/// 控制 PE 文件解析过程的行为,允许选择性解析不同的部分。
335/// 通过调整这些配置,可以在性能和功能之间取得平衡。
336#[derive(Debug, Clone, Copy)]
337pub struct ReadConfig {
338    /// 是否包含节数据,如果为 false 则只解析头部信息
339    pub include_sections: bool,
340    /// 是否验证校验和,验证会增加解析时间
341    pub validate_checksum: bool,
342    /// 是否解析导入表,导入表包含依赖的 DLL 信息
343    pub parse_imports: bool,
344    /// 是否解析导出表,导出表包含对外提供的函数信息
345    pub parse_exports: bool,
346}
347
348impl Default for ReadConfig {
349    /// 创建默认的读取配置
350    ///
351    /// 默认配置包含节数据、解析导入和导出表,但不验证校验和。
352    /// 这种配置在大多数情况下提供了良好的性能和功能平衡。
353    fn default() -> Self {
354        Self { include_sections: true, validate_checksum: false, parse_imports: true, parse_exports: true }
355    }
356}
357
358/// PE 程序结构
359///
360/// 表示一个完整的 PE(Portable Executable)程序,包含所有头部信息和节数据。
361/// 这是 PE 文件的最高级别抽象,包含了文件解析后的完整内容。
362#[derive(Debug, Clone, Serialize, Deserialize)]
363pub struct PeProgram {
364    /// PE 头部信息,包含 DOS 头、NT 头、COFF 头和可选头
365    pub header: PeHeader,
366    /// 所有节的集合,包含代码、数据、资源等
367    pub sections: Vec<PeSection>,
368    /// 导入表,包含程序依赖的外部函数和库
369    pub imports: ImportTable,
370    /// 导出表,包含程序向外提供的函数和符号
371    pub exports: ExportTable,
372}
373
374impl PeProgram {
375    /// 从原始机器码创建简单的可执行 PE 程序
376    pub fn create_executable(machine_code: Vec<u8>) -> Self {
377        let arch = Architecture::X86_64;
378        let machine = 0x8664; // X86_64
379        let section_count = 1;
380
381        // Optional Header
382        let entry_point = 0x1000;
383        let image_base = 0x400000;
384        let size_of_code = machine_code.len() as u32;
385        let size_of_headers = 0x200; // Minimal alignment
386        let size_of_image = 0x2000; // Headers + Section
387
388        let optional_header = OptionalHeader::new_for_architecture(
389            &arch,
390            entry_point,
391            image_base,
392            size_of_code,
393            size_of_headers,
394            size_of_image,
395            SubsystemType::Console,
396        );
397
398        let coff_header = CoffHeader::new(machine, section_count)
399            .with_optional_header_size(if arch == Architecture::X86_64 { 240 } else { 224 })
400            .with_characteristics(0x0022); // EXECUTABLE_IMAGE | LARGE_ADDRESS_AWARE
401
402        let header =
403            PeHeader { dos_header: DosHeader::default(), nt_header: NtHeader::default(), coff_header, optional_header };
404
405        let section = PeSection {
406            name: ".text".to_string(),
407            virtual_size: size_of_code,
408            virtual_address: 0x1000,
409            size_of_raw_data: (size_of_code + 0x1FF) & !0x1FF, // Align to 512
410            pointer_to_raw_data: 0x200,
411            pointer_to_relocations: 0,
412            pointer_to_line_numbers: 0,
413            number_of_relocations: 0,
414            number_of_line_numbers: 0,
415            characteristics: 0x60000020, // CODE | EXECUTE | READ
416            data: machine_code,
417        };
418
419        Self { header, sections: vec![section], imports: ImportTable::default(), exports: ExportTable::default() }
420    }
421
422    /// 为程序添加导入表并自动创建 .idata 节
423    pub fn with_imports(mut self, imports: ImportTable) -> Self {
424        if imports.entries.is_empty() {
425            return self;
426        }
427
428        self.imports = imports;
429
430        let is_64bit = self.header.optional_header.magic == 0x020B;
431        let pointer_size = if is_64bit { 8 } else { 4 };
432
433        // 1. 计算布局和 RVA
434        let base_rva = self.sections.last().map(|s| s.virtual_address + ((s.virtual_size + 0xFFF) & !0xFFF)).unwrap_or(0x1000);
435        let last_section_offset = self.sections.last().map(|s| s.pointer_to_raw_data + s.size_of_raw_data).unwrap_or(0x200);
436
437        // 导入描述符表 (IDT) 大小
438        let idt_size = (self.imports.entries.len() + 1) * 20;
439
440        let mut current_offset = idt_size;
441
442        // DLL 名称的相对偏移
443        let mut dll_name_offsets = Vec::new();
444        for entry in &self.imports.entries {
445            dll_name_offsets.push(current_offset);
446            current_offset += entry.dll_name.len() + 1;
447        }
448
449        // 对齐到 2 字节
450        if current_offset % 2 != 0 {
451            current_offset += 1;
452        }
453
454        // Hint/Name 的相对偏移
455        let mut function_name_offsets = Vec::new();
456        for entry in &self.imports.entries {
457            let mut entry_offsets = Vec::new();
458            for func in &entry.functions {
459                entry_offsets.push(current_offset);
460                // Hint (2 bytes) + Name + Null terminator (1 byte)
461                current_offset += 2 + func.len() + 1;
462                // 对齐到 2 字节
463                if current_offset % 2 != 0 {
464                    current_offset += 1;
465                }
466            }
467            function_name_offsets.push(entry_offsets);
468        }
469
470        // 对齐到指针大小
471        current_offset = (current_offset + pointer_size - 1) & !(pointer_size - 1);
472
473        // INT 相对偏移
474        let mut int_offsets = Vec::new();
475        for entry in &self.imports.entries {
476            int_offsets.push(current_offset);
477            current_offset += (entry.functions.len() + 1) * pointer_size;
478        }
479
480        // IAT 相对偏移
481        let mut iat_offsets = Vec::new();
482        for entry in &self.imports.entries {
483            iat_offsets.push(current_offset);
484            current_offset += (entry.functions.len() + 1) * pointer_size;
485        }
486
487        let idata_size = current_offset;
488        let idata_raw_size = (idata_size as u32 + 0x1FF) & !0x1FF;
489
490        // 2. 序列化数据
491        let mut data = vec![0u8; idata_raw_size as usize];
492        {
493            use byteorder::{LittleEndian, WriteBytesExt};
494            let mut cursor = std::io::Cursor::new(&mut data);
495
496            // 写入 IDT
497            for (i, _entry) in self.imports.entries.iter().enumerate() {
498                cursor.write_u32::<LittleEndian>(base_rva + int_offsets[i] as u32).unwrap(); // OriginalFirstThunk
499                cursor.write_u32::<LittleEndian>(0).unwrap(); // TimeDateStamp
500                cursor.write_u32::<LittleEndian>(0).unwrap(); // ForwarderChain
501                cursor.write_u32::<LittleEndian>(base_rva + dll_name_offsets[i] as u32).unwrap(); // Name
502                cursor.write_u32::<LittleEndian>(base_rva + iat_offsets[i] as u32).unwrap();
503                // FirstThunk (IAT)
504            }
505            // IDT 终止符已由 vec![0] 保证
506
507            // 写入 DLL 名称
508            for (i, entry) in self.imports.entries.iter().enumerate() {
509                cursor.set_position(dll_name_offsets[i] as u64);
510                cursor.write_all(entry.dll_name.as_bytes()).unwrap();
511                cursor.write_u8(0).unwrap();
512            }
513
514            // 写入 Hint/Name
515            for (i, entry) in self.imports.entries.iter().enumerate() {
516                for (j, func) in entry.functions.iter().enumerate() {
517                    cursor.set_position(function_name_offsets[i][j] as u64);
518                    cursor.write_u16::<LittleEndian>(0).unwrap(); // Hint
519                    cursor.write_all(func.as_bytes()).unwrap();
520                    cursor.write_u8(0).unwrap();
521                }
522            }
523
524            // 写入 INT 和 IAT (初始内容相同,都指向 Hint/Name)
525            for (i, entry) in self.imports.entries.iter().enumerate() {
526                for (j, _) in entry.functions.iter().enumerate() {
527                    let name_rva = base_rva + function_name_offsets[i][j] as u32;
528
529                    // INT
530                    cursor.set_position((int_offsets[i] + j * pointer_size) as u64);
531                    if is_64bit {
532                        cursor.write_u64::<LittleEndian>(name_rva as u64).unwrap();
533                    }
534                    else {
535                        cursor.write_u32::<LittleEndian>(name_rva).unwrap();
536                    }
537
538                    // IAT
539                    cursor.set_position((iat_offsets[i] + j * pointer_size) as u64);
540                    if is_64bit {
541                        cursor.write_u64::<LittleEndian>(name_rva as u64).unwrap();
542                    }
543                    else {
544                        cursor.write_u32::<LittleEndian>(name_rva).unwrap();
545                    }
546                }
547            }
548        }
549
550        let idata_section = PeSection {
551            name: ".idata".to_string(),
552            virtual_size: idata_size as u32,
553            virtual_address: base_rva,
554            size_of_raw_data: idata_raw_size,
555            pointer_to_raw_data: last_section_offset,
556            pointer_to_relocations: 0,
557            pointer_to_line_numbers: 0,
558            number_of_relocations: 0,
559            number_of_line_numbers: 0,
560            characteristics: 0xC0000040, // INITIALIZED_DATA | READ | WRITE
561            data,
562        };
563
564        self.sections.push(idata_section);
565        self.header.coff_header.number_of_sections = self.sections.len() as u16;
566
567        // 更新数据目录
568        if self.header.optional_header.data_directories.len() >= 2 {
569            self.header.optional_header.data_directories[1].virtual_address = base_rva;
570            self.header.optional_header.data_directories[1].size = idata_size as u32;
571        }
572
573        // IAT 目录 (索引 12)
574        if self.header.optional_header.data_directories.len() >= 13 {
575            // 简单起见,我们将整个 IAT 区域作为 IAT 目录。
576            // 实际上每个 DLL 都有自己的 IAT 范围。
577            let iat_start_offset = iat_offsets[0];
578            let iat_total_size = idata_size - iat_start_offset;
579            self.header.optional_header.data_directories[12].virtual_address = base_rva + iat_start_offset as u32;
580            self.header.optional_header.data_directories[12].size = iat_total_size as u32;
581        }
582
583        // 更新映像大小
584        self.header.optional_header.size_of_image = base_rva + ((idata_raw_size + 0xFFF) & !0xFFF);
585
586        self
587    }
588}
589
590/// PE 信息结构
591///
592/// 提供 PE 文件的摘要信息,包含关键属性和统计信息。
593/// 这个结构用于快速获取文件的基本信息,而无需解析完整的头部结构。
594#[derive(Debug, Clone, Serialize, Deserialize)]
595pub struct PeInfo {
596    /// 目标架构类型,如 x86、x64、ARM 等
597    pub target_arch: Architecture,
598    /// 子系统类型,定义程序运行环境
599    pub subsystem: SubsystemType,
600    /// 程序入口点的 RVA(相对虚拟地址)
601    pub entry_point: u32,
602    /// 映像的首选加载地址
603    pub image_base: u64,
604    /// 文件中节的数量
605    pub section_count: u16,
606    /// 文件的总大小(以字节为单位)
607    pub file_size: u64,
608}
609
610/// 数据目录结构
611///
612/// 包含 PE 文件中各种数据目录的信息,如导入表、导出表、
613/// 资源表等。每个数据目录项包含一个RVA和大小。
614#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
615pub struct DataDirectory {
616    /// 数据目录的相对虚拟地址(RVA)
617    pub virtual_address: u32,
618    /// 数据目录的大小(以字节为单位)
619    pub size: u32,
620}
621
622impl DataDirectory {
623    /// 从 ExeReader 读取数据目录
624    pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
625        Ok(DataDirectory { virtual_address: reader.read_u32::<LittleEndian>()?, size: reader.read_u32::<LittleEndian>()? })
626    }
627}
628
629impl OptionalHeader {
630    /// 从 ExeReader 读取可选头
631    pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
632        let magic = reader.read_u16::<LittleEndian>()?;
633        let is_pe32_plus = magic == 0x020B;
634
635        let major_linker_version = reader.read_u8()?;
636        let minor_linker_version = reader.read_u8()?;
637        let size_of_code = reader.read_u32::<LittleEndian>()?;
638        let size_of_initialized_data = reader.read_u32::<LittleEndian>()?;
639        let size_of_uninitialized_data = reader.read_u32::<LittleEndian>()?;
640        let address_of_entry_point = reader.read_u32::<LittleEndian>()?;
641        let base_of_code = reader.read_u32::<LittleEndian>()?;
642
643        let (base_of_data, image_base) = if is_pe32_plus {
644            (None, reader.read_u64::<LittleEndian>()?)
645        }
646        else {
647            (Some(reader.read_u32::<LittleEndian>()?), reader.read_u32::<LittleEndian>()? as u64)
648        };
649
650        let section_alignment = reader.read_u32::<LittleEndian>()?;
651        let file_alignment = reader.read_u32::<LittleEndian>()?;
652        let major_operating_system_version = reader.read_u16::<LittleEndian>()?;
653        let minor_operating_system_version = reader.read_u16::<LittleEndian>()?;
654        let major_image_version = reader.read_u16::<LittleEndian>()?;
655        let minor_image_version = reader.read_u16::<LittleEndian>()?;
656        let major_subsystem_version = reader.read_u16::<LittleEndian>()?;
657        let minor_subsystem_version = reader.read_u16::<LittleEndian>()?;
658        let win32_version_value = reader.read_u32::<LittleEndian>()?;
659        let size_of_image = reader.read_u32::<LittleEndian>()?;
660        let size_of_headers = reader.read_u32::<LittleEndian>()?;
661        let checksum = reader.read_u32::<LittleEndian>()?;
662        let subsystem = reader.read_u16::<LittleEndian>()?.into();
663        let dll_characteristics = reader.read_u16::<LittleEndian>()?;
664
665        let (size_of_stack_reserve, size_of_stack_commit, size_of_heap_reserve, size_of_heap_commit) = if is_pe32_plus {
666            (
667                reader.read_u64::<LittleEndian>()?,
668                reader.read_u64::<LittleEndian>()?,
669                reader.read_u64::<LittleEndian>()?,
670                reader.read_u64::<LittleEndian>()?,
671            )
672        }
673        else {
674            (
675                reader.read_u32::<LittleEndian>()? as u64,
676                reader.read_u32::<LittleEndian>()? as u64,
677                reader.read_u32::<LittleEndian>()? as u64,
678                reader.read_u32::<LittleEndian>()? as u64,
679            )
680        };
681
682        let loader_flags = reader.read_u32::<LittleEndian>()?;
683        let number_of_rva_and_sizes = reader.read_u32::<LittleEndian>()?;
684
685        let mut data_directories = Vec::new();
686        for _ in 0..number_of_rva_and_sizes {
687            data_directories.push(DataDirectory::read(&mut reader)?);
688        }
689
690        Ok(OptionalHeader {
691            magic,
692            major_linker_version,
693            minor_linker_version,
694            size_of_code,
695            size_of_initialized_data,
696            size_of_uninitialized_data,
697            address_of_entry_point,
698            base_of_code,
699            base_of_data,
700            image_base,
701            section_alignment,
702            file_alignment,
703            major_operating_system_version,
704            minor_operating_system_version,
705            major_image_version,
706            minor_image_version,
707            major_subsystem_version,
708            minor_subsystem_version,
709            win32_version_value,
710            size_of_image,
711            size_of_headers,
712            checksum,
713            subsystem,
714            dll_characteristics,
715            size_of_stack_reserve,
716            size_of_stack_commit,
717            size_of_heap_reserve,
718            size_of_heap_commit,
719            loader_flags,
720            number_of_rva_and_sizes,
721            data_directories,
722        })
723    }
724}