pe_assembler/types/
mod.rs

1#![doc = include_str!("readme.md")]
2
3pub use self::{
4    dos::DosHeader,
5    nt::NtHeader,
6    tables::{ExportTable, ImportTable},
7};
8use byteorder::{LittleEndian, ReadBytesExt};
9use gaia_types::helpers::Architecture;
10use serde::{Deserialize, Serialize};
11use std::{
12    fmt::{Display, Formatter},
13    io::Read,
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
374/// PE 信息结构
375///
376/// 提供 PE 文件的摘要信息,包含关键属性和统计信息。
377/// 这个结构用于快速获取文件的基本信息,而无需解析完整的头部结构。
378#[derive(Debug, Clone, Serialize, Deserialize)]
379pub struct PeInfo {
380    /// 目标架构类型,如 x86、x64、ARM 等
381    pub target_arch: Architecture,
382    /// 子系统类型,定义程序运行环境
383    pub subsystem: SubsystemType,
384    /// 程序入口点的 RVA(相对虚拟地址)
385    pub entry_point: u32,
386    /// 映像的首选加载地址
387    pub image_base: u64,
388    /// 文件中节的数量
389    pub section_count: u16,
390    /// 文件的总大小(以字节为单位)
391    pub file_size: u64,
392}
393
394/// 数据目录结构
395///
396/// 包含 PE 文件中各种数据目录的信息,如导入表、导出表、
397/// 资源表等。每个数据目录项包含一个RVA和大小。
398#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
399pub struct DataDirectory {
400    /// 数据目录的相对虚拟地址(RVA)
401    pub virtual_address: u32,
402    /// 数据目录的大小(以字节为单位)
403    pub size: u32,
404}
405
406impl DataDirectory {
407    /// 从 ExeReader 读取数据目录
408    pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
409        Ok(DataDirectory { virtual_address: reader.read_u32::<LittleEndian>()?, size: reader.read_u32::<LittleEndian>()? })
410    }
411}
412
413impl OptionalHeader {
414    /// 从 ExeReader 读取可选头
415    pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
416        let magic = reader.read_u16::<LittleEndian>()?;
417        let is_pe32_plus = magic == 0x020B;
418
419        let major_linker_version = reader.read_u8()?;
420        let minor_linker_version = reader.read_u8()?;
421        let size_of_code = reader.read_u32::<LittleEndian>()?;
422        let size_of_initialized_data = reader.read_u32::<LittleEndian>()?;
423        let size_of_uninitialized_data = reader.read_u32::<LittleEndian>()?;
424        let address_of_entry_point = reader.read_u32::<LittleEndian>()?;
425        let base_of_code = reader.read_u32::<LittleEndian>()?;
426
427        let (base_of_data, image_base) = if is_pe32_plus {
428            (None, reader.read_u64::<LittleEndian>()?)
429        }
430        else {
431            (Some(reader.read_u32::<LittleEndian>()?), reader.read_u32::<LittleEndian>()? as u64)
432        };
433
434        let section_alignment = reader.read_u32::<LittleEndian>()?;
435        let file_alignment = reader.read_u32::<LittleEndian>()?;
436        let major_operating_system_version = reader.read_u16::<LittleEndian>()?;
437        let minor_operating_system_version = reader.read_u16::<LittleEndian>()?;
438        let major_image_version = reader.read_u16::<LittleEndian>()?;
439        let minor_image_version = reader.read_u16::<LittleEndian>()?;
440        let major_subsystem_version = reader.read_u16::<LittleEndian>()?;
441        let minor_subsystem_version = reader.read_u16::<LittleEndian>()?;
442        let win32_version_value = reader.read_u32::<LittleEndian>()?;
443        let size_of_image = reader.read_u32::<LittleEndian>()?;
444        let size_of_headers = reader.read_u32::<LittleEndian>()?;
445        let checksum = reader.read_u32::<LittleEndian>()?;
446        let subsystem = reader.read_u16::<LittleEndian>()?.into();
447        let dll_characteristics = reader.read_u16::<LittleEndian>()?;
448
449        let (size_of_stack_reserve, size_of_stack_commit, size_of_heap_reserve, size_of_heap_commit) = if is_pe32_plus {
450            (
451                reader.read_u64::<LittleEndian>()?,
452                reader.read_u64::<LittleEndian>()?,
453                reader.read_u64::<LittleEndian>()?,
454                reader.read_u64::<LittleEndian>()?,
455            )
456        }
457        else {
458            (
459                reader.read_u32::<LittleEndian>()? as u64,
460                reader.read_u32::<LittleEndian>()? as u64,
461                reader.read_u32::<LittleEndian>()? as u64,
462                reader.read_u32::<LittleEndian>()? as u64,
463            )
464        };
465
466        let loader_flags = reader.read_u32::<LittleEndian>()?;
467        let number_of_rva_and_sizes = reader.read_u32::<LittleEndian>()?;
468
469        let mut data_directories = Vec::new();
470        for _ in 0..number_of_rva_and_sizes {
471            data_directories.push(DataDirectory::read(&mut reader)?);
472        }
473
474        Ok(OptionalHeader {
475            magic,
476            major_linker_version,
477            minor_linker_version,
478            size_of_code,
479            size_of_initialized_data,
480            size_of_uninitialized_data,
481            address_of_entry_point,
482            base_of_code,
483            base_of_data,
484            image_base,
485            section_alignment,
486            file_alignment,
487            major_operating_system_version,
488            minor_operating_system_version,
489            major_image_version,
490            minor_image_version,
491            major_subsystem_version,
492            minor_subsystem_version,
493            win32_version_value,
494            size_of_image,
495            size_of_headers,
496            checksum,
497            subsystem,
498            dll_characteristics,
499            size_of_stack_reserve,
500            size_of_stack_commit,
501            size_of_heap_reserve,
502            size_of_heap_commit,
503            loader_flags,
504            number_of_rva_and_sizes,
505            data_directories,
506        })
507    }
508}