pe_assembler/types/
mod.rs

1pub use self::{
2    dos::DosHeader,
3    nt::NtHeader,
4    tables::{ExportTable, ImportTable},
5};
6use byteorder::{LittleEndian, ReadBytesExt};
7use gaia_types::helpers::Architecture;
8use serde::{Deserialize, Serialize};
9use std::{
10    fmt::{Display, Formatter},
11    io::{Read, Seek},
12};
13
14pub mod coff;
15mod dos;
16mod nt;
17pub mod tables;
18
19pub use coff::*;
20use gaia_types::GaiaError;
21
22/// PE 子系统类型枚举
23///
24/// 定义了 Windows PE 文件可以使用的各种子系统类型,
25/// 这些类型决定了程序运行时的环境和依赖。
26#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
27pub enum SubsystemType {
28    /// 控制台应用程序,运行在控制台窗口中
29    Console,
30    /// Windows GUI 应用程序,具有图形界面
31    Windows,
32    /// 原生驱动程序,运行在核心态
33    Native,
34    /// POSIX 子系统应用程序
35    Posix,
36    /// Windows CE 子系统
37    WindowsCe,
38    /// EFI 应用程序
39    Efi,
40    /// EFI 启动服务驱动程序
41    EfiBootServiceDriver,
42    /// EFI 运行时驱动程序
43    EfiRuntimeDriver,
44    /// EFI ROM 映像
45    EfiRom,
46    /// Xbox 应用程序
47    Xbox,
48    /// Windows 启动应用程序
49    WindowsBootApplication,
50}
51
52impl Display for SubsystemType {
53    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
54        match self {
55            SubsystemType::Console => write!(f, "控制台应用程序"),
56            SubsystemType::Windows => write!(f, "Windows GUI 应用程序"),
57            SubsystemType::Native => write!(f, "原生驱动程序"),
58            SubsystemType::Posix => write!(f, "POSIX 子系统应用程序"),
59            SubsystemType::WindowsCe => write!(f, "Windows CE 子系统"),
60            SubsystemType::Efi => write!(f, "EFI 应用程序"),
61            SubsystemType::EfiBootServiceDriver => write!(f, "EFI 启动服务驱动程序"),
62            SubsystemType::EfiRuntimeDriver => write!(f, "EFI 运行时驱动程序"),
63            SubsystemType::EfiRom => write!(f, "EFI ROM 映像"),
64            SubsystemType::Xbox => write!(f, "Xbox 应用程序"),
65            SubsystemType::WindowsBootApplication => write!(f, "Windows 启动应用程序"),
66        }
67    }
68}
69
70impl From<u16> for SubsystemType {
71    /// 从 u16 值创建子系统类型
72    ///
73    /// # Arguments
74    /// * `value` - 子系统类型的数值
75    ///
76    /// # Returns
77    /// 返回对应的子系统类型,未知类型返回 Console
78    fn from(value: u16) -> Self {
79        match value {
80            1 => SubsystemType::Native,
81            2 => SubsystemType::Windows,
82            3 => SubsystemType::Console,
83            7 => SubsystemType::Posix,
84            9 => SubsystemType::WindowsCe,
85            10 => SubsystemType::Efi,
86            11 => SubsystemType::EfiBootServiceDriver,
87            12 => SubsystemType::EfiRuntimeDriver,
88            13 => SubsystemType::EfiRom,
89            14 => SubsystemType::Xbox,
90            16 => SubsystemType::WindowsBootApplication,
91            _ => SubsystemType::Console, // 默认值
92        }
93    }
94}
95
96impl Default for DataDirectory {
97    fn default() -> Self {
98        Self { virtual_address: 0, size: 0 }
99    }
100}
101
102/// 可选头结构
103///
104/// 包含 PE 文件的加载和运行时信息,如入口点地址、内存布局、
105/// 版本信息等。这个结构对于 Windows 加载器正确加载和执行程序至关重要。
106#[derive(Clone, Debug, Serialize, Deserialize)]
107pub struct OptionalHeader {
108    /// 魔数,标识 PE32 或 PE32+ 格式
109    pub magic: u16,
110    /// 链接器的主版本号
111    pub major_linker_version: u8,
112    /// 链接器的次版本号
113    pub minor_linker_version: u8,
114    /// 代码节的总大小(以字节为单位)
115    pub size_of_code: u32,
116    /// 已初始化数据的总大小
117    pub size_of_initialized_data: u32,
118    /// 未初始化数据的总大小
119    pub size_of_uninitialized_data: u32,
120    /// 程序入口点的 RVA(相对虚拟地址)
121    pub address_of_entry_point: u32,
122    /// 代码节的起始 RVA
123    pub base_of_code: u32,
124    /// 数据节的起始 RVA,仅 PE32 格式有效
125    pub base_of_data: Option<u32>, // Only for PE32
126    /// 映像的首选加载地址
127    pub image_base: u64,
128    /// 节在内存中的对齐粒度
129    pub section_alignment: u32,
130    /// 节在文件中的对齐粒度
131    pub file_alignment: u32,
132    /// 所需操作系统的主版本号
133    pub major_operating_system_version: u16,
134    /// 所需操作系统的次版本号
135    pub minor_operating_system_version: u16,
136    /// 映像的主版本号
137    pub major_image_version: u16,
138    /// 映像的次版本号
139    pub minor_image_version: u16,
140    /// 子系统的主版本号
141    pub major_subsystem_version: u16,
142    /// 子系统的次版本号
143    pub minor_subsystem_version: u16,
144    /// 保留字段,必须为 0
145    pub win32_version_value: u32,
146    /// 映像的总大小,包括所有头文件和节
147    pub size_of_image: u32,
148    /// 所有头文件的总大小
149    pub size_of_headers: u32,
150    /// 映像的校验和,用于内核模式和系统 DLL
151    pub checksum: u32,
152    /// 子系统类型,定义程序运行环境
153    pub subsystem: SubsystemType,
154    /// DLL 特征标志,描述 DLL 的各种属性
155    pub dll_characteristics: u16,
156    /// 为线程栈保留的虚拟内存大小
157    pub size_of_stack_reserve: u64,
158    /// 为线程栈提交的虚拟内存大小
159    pub size_of_stack_commit: u64,
160    /// 为进程堆保留的虚拟内存大小
161    pub size_of_heap_reserve: u64,
162    /// 为进程堆提交的虚拟内存大小
163    pub size_of_heap_commit: u64,
164    /// 保留字段,必须为 0
165    pub loader_flags: u32,
166    /// 数据目录表的条目数量
167    pub number_of_rva_and_sizes: u32,
168    /// 数据目录表,包含各种数据目录的信息
169    pub data_directories: Vec<DataDirectory>,
170}
171
172impl OptionalHeader {
173    /// 创建一个标准的可选头,适用于 .NET 程序
174    pub fn new(
175        entry_point: u32,
176        image_base: u64,
177        size_of_code: u32,
178        size_of_headers: u32,
179        size_of_image: u32,
180        subsystem: SubsystemType,
181    ) -> Self {
182        let mut data_directories = Vec::with_capacity(16);
183        // 初始化 16 个标准数据目录
184        for _ in 0..16 {
185            data_directories.push(DataDirectory::default());
186        }
187
188        Self {
189            magic: 0x020B, // PE32+
190            major_linker_version: 14,
191            minor_linker_version: 0,
192            size_of_code,
193            size_of_initialized_data: 0,
194            size_of_uninitialized_data: 0,
195            address_of_entry_point: entry_point,
196            base_of_code: 0x2000,
197            base_of_data: None, // PE32+ 不使用
198            image_base,
199            section_alignment: 0x2000,
200            file_alignment: 0x200,
201            major_operating_system_version: 6,
202            minor_operating_system_version: 0,
203            major_image_version: 0,
204            minor_image_version: 0,
205            major_subsystem_version: 6,
206            minor_subsystem_version: 0,
207            win32_version_value: 0,
208            size_of_image,
209            size_of_headers,
210            checksum: 0,
211            subsystem,
212            // 关闭 DYNAMIC_BASE 以确保固定映像基址 (0x400000),避免绝对地址失效
213            // 保留 NX_COMPAT、NO_SEH、TERMINAL_SERVER_AWARE
214            dll_characteristics: 0x8500, // NX_COMPAT | NO_SEH | TERMINAL_SERVER_AWARE
215            size_of_stack_reserve: 0x100000,
216            size_of_stack_commit: 0x1000,
217            size_of_heap_reserve: 0x100000,
218            size_of_heap_commit: 0x1000,
219            loader_flags: 0,
220            number_of_rva_and_sizes: 16,
221            data_directories,
222        }
223    }
224
225    /// 根据架构创建可选头
226    pub fn new_for_architecture(
227        architecture: &Architecture,
228        entry_point: u32,
229        image_base: u64,
230        size_of_code: u32,
231        size_of_headers: u32,
232        size_of_image: u32,
233        subsystem: SubsystemType,
234    ) -> Self {
235        let mut data_directories = Vec::with_capacity(16);
236        // 初始化 16 个标准数据目录
237        for _ in 0..16 {
238            data_directories.push(DataDirectory::default());
239        }
240
241        let (magic, base_of_data) = match architecture {
242            Architecture::X86 => (0x010B, Some(0x2000)), // PE32
243            Architecture::X86_64 => (0x020B, None),      // PE32+
244            _ => (0x010B, Some(0x2000)),                 // 默认为 PE32
245        };
246
247        Self {
248            magic,
249            major_linker_version: 14,
250            minor_linker_version: 0,
251            size_of_code,
252            size_of_initialized_data: 0,
253            size_of_uninitialized_data: 0,
254            address_of_entry_point: entry_point,
255            base_of_code: 0x1000,
256            base_of_data,
257            image_base,
258            section_alignment: 0x1000,
259            file_alignment: 0x200,
260            major_operating_system_version: 6,
261            minor_operating_system_version: 0,
262            major_image_version: 0,
263            minor_image_version: 0,
264            major_subsystem_version: 6,
265            minor_subsystem_version: 0,
266            win32_version_value: 0,
267            size_of_image,
268            size_of_headers,
269            checksum: 0,
270            subsystem,
271            dll_characteristics: 0x8160, // DYNAMIC_BASE | NX_COMPAT | NO_SEH | TERMINAL_SERVER_AWARE
272            size_of_stack_reserve: 0x100000,
273            size_of_stack_commit: 0x1000,
274            size_of_heap_reserve: 0x100000,
275            size_of_heap_commit: 0x1000,
276            loader_flags: 0,
277            number_of_rva_and_sizes: 16,
278            data_directories,
279        }
280    }
281}
282
283/// PE 头结构
284///
285/// 包含 PE 文件的所有头部信息,是 DOS 头、NT 头、COFF 头和可选头的组合。
286/// 这个结构提供了完整的 PE 文件元数据信息。
287#[derive(Clone, Debug, Serialize, Deserialize)]
288pub struct PeHeader {
289    /// DOS 头,包含 DOS 兼容性信息
290    pub dos_header: DosHeader,
291    /// NT 头,包含 PE 签名
292    pub nt_header: NtHeader,
293    /// COFF 头,包含目标文件信息
294    pub coff_header: CoffHeader,
295    /// 可选头,包含加载和运行时信息
296    pub optional_header: OptionalHeader,
297}
298
299/// PE 节结构
300///
301/// 包含 PE 文件中每个节的详细信息,包括节名、虚拟地址、大小等属性。
302/// 节是 PE 文件中的基本组织单位,不同的节包含不同类型的数据(如代码、数据、资源等)。
303#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct PeSection {
305    /// 节名称,最多8个字符
306    pub name: String,
307    /// 节在内存中的虚拟大小
308    pub virtual_size: u32,
309    /// 节在内存中的虚拟地址
310    pub virtual_address: u32,
311    /// 节在文件中的原始数据大小
312    pub size_of_raw_data: u32,
313    /// 节在文件中的原始数据指针
314    pub pointer_to_raw_data: u32,
315    /// 重定位表指针
316    pub pointer_to_relocations: u32,
317    /// 行号表指针
318    pub pointer_to_line_numbers: u32,
319    /// 重定位项数量
320    pub number_of_relocations: u16,
321    /// 行号数量
322    pub number_of_line_numbers: u16,
323    /// 节特征标志
324    pub characteristics: u32,
325    /// 节的原始数据
326    #[serde(skip_serializing_if = "Vec::is_empty")]
327    pub data: Vec<u8>,
328}
329
330/// PE 文件读取配置
331///
332/// 控制 PE 文件解析过程的行为,允许选择性解析不同的部分。
333/// 通过调整这些配置,可以在性能和功能之间取得平衡。
334#[derive(Debug, Clone, Copy)]
335pub struct ReadConfig {
336    /// 是否包含节数据,如果为 false 则只解析头部信息
337    pub include_sections: bool,
338    /// 是否验证校验和,验证会增加解析时间
339    pub validate_checksum: bool,
340    /// 是否解析导入表,导入表包含依赖的 DLL 信息
341    pub parse_imports: bool,
342    /// 是否解析导出表,导出表包含对外提供的函数信息
343    pub parse_exports: bool,
344}
345
346impl Default for ReadConfig {
347    /// 创建默认的读取配置
348    ///
349    /// 默认配置包含节数据、解析导入和导出表,但不验证校验和。
350    /// 这种配置在大多数情况下提供了良好的性能和功能平衡。
351    fn default() -> Self {
352        Self { include_sections: true, validate_checksum: false, parse_imports: true, parse_exports: true }
353    }
354}
355
356/// PE 程序结构
357///
358/// 表示一个完整的 PE(Portable Executable)程序,包含所有头部信息和节数据。
359/// 这是 PE 文件的最高级别抽象,包含了文件解析后的完整内容。
360#[derive(Debug, Clone, Serialize, Deserialize)]
361pub struct PeProgram {
362    /// PE 头部信息,包含 DOS 头、NT 头、COFF 头和可选头
363    pub header: PeHeader,
364    /// 所有节的集合,包含代码、数据、资源等
365    pub sections: Vec<PeSection>,
366    /// 导入表,包含程序依赖的外部函数和库
367    pub imports: ImportTable,
368    /// 导出表,包含程序向外提供的函数和符号
369    pub exports: ExportTable,
370}
371
372/// PE 信息结构
373///
374/// 提供 PE 文件的摘要信息,包含关键属性和统计信息。
375/// 这个结构用于快速获取文件的基本信息,而无需解析完整的头部结构。
376#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct PeInfo {
378    /// 目标架构类型,如 x86、x64、ARM 等
379    pub target_arch: Architecture,
380    /// 子系统类型,定义程序运行环境
381    pub subsystem: SubsystemType,
382    /// 程序入口点的 RVA(相对虚拟地址)
383    pub entry_point: u32,
384    /// 映像的首选加载地址
385    pub image_base: u64,
386    /// 文件中节的数量
387    pub section_count: u16,
388    /// 文件的总大小(以字节为单位)
389    pub file_size: u64,
390}
391
392/// 数据目录结构
393///
394/// 包含 PE 文件中各种数据目录的信息,如导入表、导出表、
395/// 资源表等。每个数据目录项包含一个RVA和大小。
396#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
397pub struct DataDirectory {
398    /// 数据目录的相对虚拟地址(RVA)
399    pub virtual_address: u32,
400    /// 数据目录的大小(以字节为单位)
401    pub size: u32,
402}
403
404impl DataDirectory {
405    /// 从 ExeReader 读取数据目录
406    pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
407        Ok(DataDirectory { virtual_address: reader.read_u32::<LittleEndian>()?, size: reader.read_u32::<LittleEndian>()? })
408    }
409}
410
411impl OptionalHeader {
412    /// 从 ExeReader 读取可选头
413    pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
414        let magic = reader.read_u16::<LittleEndian>()?;
415        let is_pe32_plus = magic == 0x020B;
416
417        let major_linker_version = reader.read_u8()?;
418        let minor_linker_version = reader.read_u8()?;
419        let size_of_code = reader.read_u32::<LittleEndian>()?;
420        let size_of_initialized_data = reader.read_u32::<LittleEndian>()?;
421        let size_of_uninitialized_data = reader.read_u32::<LittleEndian>()?;
422        let address_of_entry_point = reader.read_u32::<LittleEndian>()?;
423        let base_of_code = reader.read_u32::<LittleEndian>()?;
424
425        let (base_of_data, image_base) = if is_pe32_plus {
426            (None, reader.read_u64::<LittleEndian>()?)
427        }
428        else {
429            (Some(reader.read_u32::<LittleEndian>()?), reader.read_u32::<LittleEndian>()? as u64)
430        };
431
432        let section_alignment = reader.read_u32::<LittleEndian>()?;
433        let file_alignment = reader.read_u32::<LittleEndian>()?;
434        let major_operating_system_version = reader.read_u16::<LittleEndian>()?;
435        let minor_operating_system_version = reader.read_u16::<LittleEndian>()?;
436        let major_image_version = reader.read_u16::<LittleEndian>()?;
437        let minor_image_version = reader.read_u16::<LittleEndian>()?;
438        let major_subsystem_version = reader.read_u16::<LittleEndian>()?;
439        let minor_subsystem_version = reader.read_u16::<LittleEndian>()?;
440        let win32_version_value = reader.read_u32::<LittleEndian>()?;
441        let size_of_image = reader.read_u32::<LittleEndian>()?;
442        let size_of_headers = reader.read_u32::<LittleEndian>()?;
443        let checksum = reader.read_u32::<LittleEndian>()?;
444        let subsystem = reader.read_u16::<LittleEndian>()?.into();
445        let dll_characteristics = reader.read_u16::<LittleEndian>()?;
446
447        let (size_of_stack_reserve, size_of_stack_commit, size_of_heap_reserve, size_of_heap_commit) = if is_pe32_plus {
448            (
449                reader.read_u64::<LittleEndian>()?,
450                reader.read_u64::<LittleEndian>()?,
451                reader.read_u64::<LittleEndian>()?,
452                reader.read_u64::<LittleEndian>()?,
453            )
454        }
455        else {
456            (
457                reader.read_u32::<LittleEndian>()? as u64,
458                reader.read_u32::<LittleEndian>()? as u64,
459                reader.read_u32::<LittleEndian>()? as u64,
460                reader.read_u32::<LittleEndian>()? as u64,
461            )
462        };
463
464        let loader_flags = reader.read_u32::<LittleEndian>()?;
465        let number_of_rva_and_sizes = reader.read_u32::<LittleEndian>()?;
466
467        let mut data_directories = Vec::new();
468        for _ in 0..number_of_rva_and_sizes {
469            data_directories.push(DataDirectory::read(&mut reader)?);
470        }
471
472        Ok(OptionalHeader {
473            magic,
474            major_linker_version,
475            minor_linker_version,
476            size_of_code,
477            size_of_initialized_data,
478            size_of_uninitialized_data,
479            address_of_entry_point,
480            base_of_code,
481            base_of_data,
482            image_base,
483            section_alignment,
484            file_alignment,
485            major_operating_system_version,
486            minor_operating_system_version,
487            major_image_version,
488            minor_image_version,
489            major_subsystem_version,
490            minor_subsystem_version,
491            win32_version_value,
492            size_of_image,
493            size_of_headers,
494            checksum,
495            subsystem,
496            dll_characteristics,
497            size_of_stack_reserve,
498            size_of_stack_commit,
499            size_of_heap_reserve,
500            size_of_heap_commit,
501            loader_flags,
502            number_of_rva_and_sizes,
503            data_directories,
504        })
505    }
506}