pe_assembler/helpers/pe_reader/
mod.rs

1use crate::types::{
2    CoffHeader, DosHeader, ExportTable, ImportTable, NtHeader, OptionalHeader, PeHeader, PeInfo, PeProgram, PeSection,
3    SectionHeader,
4};
5use byteorder::LittleEndian;
6use gaia_types::{helpers::Architecture, BinaryReader, GaiaError};
7use std::io::{Read, Seek};
8
9/// PE 文件读取器的通用 trait
10pub trait PeReader<R: Read + Seek> {
11    /// 获取二进制读取器的可变引用
12    fn get_viewer(&mut self) -> &mut BinaryReader<R, LittleEndian>;
13
14    /// 获取诊断信息的可变引用
15    fn add_diagnostics(&mut self, error: impl Into<GaiaError>);
16
17    /// 获取缓存的节头信息
18    fn get_cached_section_headers(&self) -> Option<&Vec<SectionHeader>>;
19
20    /// 设置缓存的节头信息
21    fn set_cached_section_headers(&mut self, headers: Vec<SectionHeader>);
22
23    /// 读取 PE 头部信息(通用实现)
24    fn read_header_once(&mut self) -> Result<&PeHeader, GaiaError>;
25
26    /// 解析 PE 头部(通用实现)
27    fn read_header_force(&mut self) -> Result<PeHeader, GaiaError> {
28        // 保存当前位置
29        let original_pos = self.get_viewer().get_position();
30
31        // 重置到文件开头
32        self.get_viewer().set_position(0)?;
33
34        // 读取 DOS 头
35        let dos_header = DosHeader::read(self.get_viewer())?;
36
37        // 验证 DOS 签名 (MZ)
38        if dos_header.e_magic != 0x5A4D {
39            let error = GaiaError::invalid_data("无效的 DOS 签名 (MZ)");
40            self.add_diagnostics(error);
41        }
42
43        // 跳转到 NT 头位置
44        self.get_viewer().set_position(dos_header.e_lfanew as u64)?;
45
46        // 读取 NT 头
47        let nt_header = NtHeader::read(self.get_viewer())?;
48
49        // 验证 PE 签名 (PE\0\0)
50        if nt_header.signature != 0x00004550 {
51            let error = GaiaError::invalid_data("无效的 PE 签名 (PE)");
52            self.add_diagnostics(error);
53        }
54
55        // 读取 COFF 头
56        let coff_header = CoffHeader::read(self.get_viewer())?;
57
58        // 验证 COFF 头中的节数量
59        if coff_header.number_of_sections == 0 {
60            let error = GaiaError::invalid_data("PE 文件必须至少有一个节");
61            self.add_diagnostics(error);
62        }
63
64        // 读取可选头
65        let optional_header = OptionalHeader::read(self.get_viewer())?;
66
67        // 验证可选头的魔数
68        match optional_header.magic {
69            0x10b => {} // PE32
70            0x20b => {} // PE32+
71            _ => {
72                let error = GaiaError::invalid_data("无效的可选头魔数");
73                self.add_diagnostics(error);
74                return Err(GaiaError::invalid_data("无效的可选头魔数"));
75            }
76        }
77
78        // 恢复原始位置
79        self.get_viewer().set_position(original_pos)?;
80
81        Ok(PeHeader { dos_header, nt_header, coff_header, optional_header })
82    }
83
84    /// 读取节头信息(通用实现)
85    fn read_section_headers(&mut self) -> Result<Vec<SectionHeader>, GaiaError> {
86        if let Some(sections) = self.get_cached_section_headers() {
87            return Ok(sections.clone());
88        }
89
90        // 先读取主头部
91        let header = self.read_header_once()?.clone();
92        let original_pos = self.get_viewer().get_position();
93
94        // 读取节头部
95        let mut section_headers = Vec::with_capacity(header.coff_header.number_of_sections as usize);
96
97        // 定位到节头部位置
98        let section_header_offset = header.dos_header.e_lfanew as u64
99            + 4 // PE signature
100            + std::mem::size_of::<CoffHeader>() as u64
101            + header.coff_header.size_of_optional_header as u64;
102
103        self.get_viewer().set_position(section_header_offset)?;
104
105        for _ in 0..header.coff_header.number_of_sections {
106            let section_header = SectionHeader::read(self.get_viewer())?;
107            section_headers.push(section_header);
108        }
109
110        // 恢复原始位置
111        self.get_viewer().set_position(original_pos)?;
112
113        self.set_cached_section_headers(section_headers.clone());
114        Ok(section_headers)
115    }
116
117    /// 将 RVA 转换为文件偏移(通用实现)
118    fn rva_to_file_offset(&self, rva: u32, sections: &[PeSection]) -> Result<u32, GaiaError> {
119        for section in sections {
120            if rva >= section.virtual_address && rva < section.virtual_address + section.virtual_size {
121                let offset_in_section = rva - section.virtual_address;
122                return Ok(section.pointer_to_raw_data + offset_in_section);
123            }
124        }
125        Err(GaiaError::invalid_data(&format!("无法将 RVA 0x{:08X} 转换为文件偏移", rva)))
126    }
127
128    /// 从节头读取节数据(通用实现)
129    fn read_section_from_header(&mut self, header: &SectionHeader) -> Result<PeSection, GaiaError> {
130        let name = String::from_utf8_lossy(&header.name).trim_end_matches('\0').to_string();
131        let viewer = self.get_viewer();
132
133        let mut data = Vec::new();
134        if header.size_of_raw_data > 0 && header.pointer_to_raw_data > 0 {
135            let original_pos = viewer.get_position();
136            viewer.set_position(header.pointer_to_raw_data as u64)?;
137            data.resize(header.size_of_raw_data as usize, 0);
138            viewer.read_exact(&mut data)?;
139            viewer.set_position(original_pos)?;
140        }
141
142        Ok(PeSection {
143            name,
144            virtual_size: header.virtual_size,
145            virtual_address: header.virtual_address,
146            size_of_raw_data: header.size_of_raw_data,
147            pointer_to_raw_data: header.pointer_to_raw_data,
148            pointer_to_relocations: header.pointer_to_relocations,
149            pointer_to_line_numbers: header.pointer_to_line_numbers,
150            number_of_relocations: header.number_of_relocations,
151            number_of_line_numbers: header.number_of_line_numbers,
152            characteristics: header.characteristics,
153            data,
154        })
155    }
156
157    /// 解析导入表(通用实现)
158    fn parse_import_table(&mut self, header: &PeHeader, sections: &[PeSection]) -> Result<ImportTable, GaiaError> {
159        // 检查数据目录表是否包含导入表信息
160        if header.optional_header.data_directories.len() < 2 {
161            return Ok(ImportTable::new());
162        }
163
164        let import_dir = &header.optional_header.data_directories[1]; // 导入表是第2个数据目录
165        if import_dir.virtual_address == 0 || import_dir.size == 0 {
166            return Ok(ImportTable::new());
167        }
168
169        // 将 RVA 转换为文件偏移
170        let file_offset = self.rva_to_file_offset(import_dir.virtual_address, sections)?;
171
172        // 保存当前位置
173        let current_pos = self.get_viewer().get_position();
174
175        // 定位到导入表
176        self.get_viewer().set_position(file_offset as u64)?;
177
178        let mut import_table = ImportTable::new();
179
180        // 读取导入描述符
181        loop {
182            let import_lookup_table = self.get_viewer().read_u32()?;
183            let time_date_stamp = self.get_viewer().read_u32()?;
184            let forwarder_chain = self.get_viewer().read_u32()?;
185            let name_rva = self.get_viewer().read_u32()?;
186            let import_address_table = self.get_viewer().read_u32()?;
187
188            // 如果所有字段都为0,表示导入表结束
189            if import_lookup_table == 0
190                && time_date_stamp == 0
191                && forwarder_chain == 0
192                && name_rva == 0
193                && import_address_table == 0
194            {
195                break;
196            }
197
198            let mut dll_name = String::new();
199            let mut functions = Vec::new();
200
201            // 读取 DLL 名称
202            if name_rva != 0 {
203                let name_offset = self.rva_to_file_offset(name_rva, sections)?;
204                let saved_pos = self.get_viewer().get_position();
205                self.get_viewer().set_position(name_offset as u64)?;
206
207                let mut name_bytes = Vec::new();
208                loop {
209                    let byte = self.get_viewer().read_u8()?;
210                    if byte == 0 {
211                        break;
212                    }
213                    name_bytes.push(byte);
214                }
215                dll_name = String::from_utf8_lossy(&name_bytes).to_string();
216                self.get_viewer().set_position(saved_pos)?;
217            }
218
219            // 读取函数名称(从导入查找表)
220            if import_lookup_table != 0 {
221                let lookup_offset = self.rva_to_file_offset(import_lookup_table, sections)?;
222                let saved_pos = self.get_viewer().get_position();
223                self.get_viewer().set_position(lookup_offset as u64)?;
224
225                loop {
226                    let entry = if header.optional_header.magic == 0x20b {
227                        // PE32+
228                        self.get_viewer().read_u64()?
229                    }
230                    else {
231                        // PE32
232                        self.get_viewer().read_u32()? as u64
233                    };
234
235                    if entry == 0 {
236                        break;
237                    }
238
239                    // 检查是否是按名称导入(最高位为0)
240                    let is_ordinal = if header.optional_header.magic == 0x20b {
241                        (entry & 0x8000000000000000) != 0
242                    }
243                    else {
244                        (entry & 0x80000000) != 0
245                    };
246
247                    if !is_ordinal {
248                        let hint_name_rva =
249                            entry & if header.optional_header.magic == 0x20b { 0x7FFFFFFFFFFFFFFF } else { 0x7FFFFFFF };
250                        let hint_name_offset = self.rva_to_file_offset(hint_name_rva as u32, sections)?;
251                        let func_pos = self.get_viewer().get_position();
252                        self.get_viewer().set_position(hint_name_offset as u64)?;
253
254                        // 跳过 hint(2字节)
255                        self.get_viewer().read_u16()?;
256
257                        // 读取函数名
258                        let mut func_name_bytes = Vec::new();
259                        loop {
260                            let byte = self.get_viewer().read_u8()?;
261                            if byte == 0 {
262                                break;
263                            }
264                            func_name_bytes.push(byte);
265                        }
266                        let func_name = String::from_utf8_lossy(&func_name_bytes).to_string();
267                        functions.push(func_name);
268
269                        self.get_viewer().set_position(func_pos)?;
270                    }
271                    else {
272                        // 按序号导入
273                        let ordinal = entry & 0xFFFF;
274                        functions.push(format!("Ordinal_{}", ordinal));
275                    }
276                }
277
278                self.get_viewer().set_position(saved_pos)?;
279            }
280
281            // 添加导入条目
282            if !dll_name.is_empty() {
283                use crate::types::tables::ImportEntry;
284                let entry = ImportEntry { dll_name, functions };
285                import_table.entries.push(entry);
286            }
287        }
288
289        // 恢复位置
290        self.get_viewer().set_position(current_pos)?;
291
292        Ok(import_table)
293    }
294
295    /// 解析导出表(通用实现)
296    fn parse_export_table(&mut self, header: &PeHeader, sections: &[PeSection]) -> Result<ExportTable, GaiaError> {
297        // 检查数据目录表是否包含导出表信息
298        if header.optional_header.data_directories.is_empty() {
299            return Ok(ExportTable { name: String::new(), functions: Vec::new() });
300        }
301
302        let export_dir = &header.optional_header.data_directories[0]; // 导出表是第1个数据目录
303        if export_dir.virtual_address == 0 || export_dir.size == 0 {
304            return Ok(ExportTable { name: String::new(), functions: Vec::new() });
305        }
306
307        // 将 RVA 转换为文件偏移
308        let file_offset = self.rva_to_file_offset(export_dir.virtual_address, sections)?;
309
310        // 保存当前位置
311        let current_pos = self.get_viewer().get_position();
312
313        // 定位到导出表
314        self.get_viewer().set_position(file_offset as u64)?;
315
316        // 读取导出目录表
317        let _export_flags = self.get_viewer().read_u32()?;
318        let _time_date_stamp = self.get_viewer().read_u32()?;
319        let _major_version = self.get_viewer().read_u16()?;
320        let _minor_version = self.get_viewer().read_u16()?;
321        let name_rva = self.get_viewer().read_u32()?;
322        let _ordinal_base = self.get_viewer().read_u32()?;
323        let _number_of_functions = self.get_viewer().read_u32()?;
324        let number_of_names = self.get_viewer().read_u32()?;
325        let _address_of_functions = self.get_viewer().read_u32()?;
326        let address_of_names = self.get_viewer().read_u32()?;
327        let _address_of_name_ordinals = self.get_viewer().read_u32()?;
328
329        // 读取模块名称
330        let mut name = String::new();
331        if name_rva != 0 {
332            let name_offset = self.rva_to_file_offset(name_rva, sections)?;
333            let saved_pos = self.get_viewer().get_position();
334            self.get_viewer().set_position(name_offset as u64)?;
335
336            let mut name_bytes = Vec::new();
337            loop {
338                let byte = self.get_viewer().read_u8()?;
339                if byte == 0 {
340                    break;
341                }
342                name_bytes.push(byte);
343            }
344            name = String::from_utf8_lossy(&name_bytes).to_string();
345            self.get_viewer().set_position(saved_pos)?;
346        }
347
348        // 读取函数名称
349        let mut functions = Vec::new();
350        if address_of_names != 0 && number_of_names > 0 {
351            let names_offset = self.rva_to_file_offset(address_of_names, sections)?;
352            let saved_pos = self.get_viewer().get_position();
353            self.get_viewer().set_position(names_offset as u64)?;
354
355            for _ in 0..number_of_names {
356                let name_rva = self.get_viewer().read_u32()?;
357                if name_rva != 0 {
358                    let func_name_offset = self.rva_to_file_offset(name_rva, sections)?;
359                    let func_pos = self.get_viewer().get_position();
360                    self.get_viewer().set_position(func_name_offset as u64)?;
361
362                    let mut func_name_bytes = Vec::new();
363                    loop {
364                        let byte = self.get_viewer().read_u8()?;
365                        if byte == 0 {
366                            break;
367                        }
368                        func_name_bytes.push(byte);
369                    }
370                    let func_name = String::from_utf8_lossy(&func_name_bytes).to_string();
371                    functions.push(func_name);
372
373                    self.get_viewer().set_position(func_pos)?;
374                }
375            }
376
377            self.get_viewer().set_position(saved_pos)?;
378        }
379
380        // 恢复位置
381        self.get_viewer().set_position(current_pos)?;
382
383        Ok(ExportTable { name, functions })
384    }
385
386    /// 创建 PE 信息视图(通用实现)
387    fn create_pe_info(&mut self) -> Result<PeInfo, GaiaError> {
388        let header = self.read_header_once()?.clone();
389        let viewer = self.get_viewer();
390
391        // 根据机器类型确定架构
392        let target_arch = match header.coff_header.machine {
393            0x014c => Architecture::X86,
394            0x8664 => Architecture::X86_64,
395            0x01c0 => Architecture::ARM32,
396            0xaa64 => Architecture::ARM64,
397            unknown => {
398                tracing::warn!("未知的机器类型: {:04x}", unknown);
399                Architecture::Unknown
400            }
401        };
402
403        // 获取当前文件大小
404        let current_pos = viewer.get_position();
405        viewer.seek(std::io::SeekFrom::End(0))?;
406        let file_size = viewer.get_position();
407        viewer.set_position(current_pos)?;
408
409        Ok(PeInfo {
410            target_arch,
411            subsystem: header.optional_header.subsystem,
412            entry_point: header.optional_header.address_of_entry_point,
413            image_base: header.optional_header.image_base,
414            section_count: header.coff_header.number_of_sections,
415            file_size,
416        })
417    }
418    /// 强制读取完整的 [PeProgram],并缓存结果
419    fn read_program_once(&mut self) -> Result<&PeProgram, GaiaError>;
420
421    fn read_program_force(&mut self) -> Result<PeProgram, GaiaError> {
422        let header = self.read_header_once()?.clone();
423        let section_headers = self.read_section_headers()?;
424
425        // 读取节数据
426        let mut sections = Vec::new();
427        for section_header in section_headers {
428            let section = self.read_section_from_header(&section_header)?;
429            sections.push(section);
430        }
431
432        // 解析导入表
433        let imports = self.parse_import_table(&header, &sections)?;
434
435        // 解析导出表(EXE 文件通常没有导出表)
436        let exports = self.parse_export_table(&header, &sections)?;
437
438        let program = PeProgram { header: header, sections, imports, exports };
439        Ok(program)
440    }
441}