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#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
29pub enum SubsystemType {
30 Console,
32 Windows,
34 Native,
36 Posix,
38 WindowsCe,
40 Efi,
42 EfiBootServiceDriver,
44 EfiRuntimeDriver,
46 EfiRom,
48 Xbox,
50 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 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, }
95 }
96}
97
98impl Default for DataDirectory {
99 fn default() -> Self {
100 Self { virtual_address: 0, size: 0 }
101 }
102}
103
104#[derive(Clone, Debug, Serialize, Deserialize)]
109pub struct OptionalHeader {
110 pub magic: u16,
112 pub major_linker_version: u8,
114 pub minor_linker_version: u8,
116 pub size_of_code: u32,
118 pub size_of_initialized_data: u32,
120 pub size_of_uninitialized_data: u32,
122 pub address_of_entry_point: u32,
124 pub base_of_code: u32,
126 pub base_of_data: Option<u32>, pub image_base: u64,
130 pub section_alignment: u32,
132 pub file_alignment: u32,
134 pub major_operating_system_version: u16,
136 pub minor_operating_system_version: u16,
138 pub major_image_version: u16,
140 pub minor_image_version: u16,
142 pub major_subsystem_version: u16,
144 pub minor_subsystem_version: u16,
146 pub win32_version_value: u32,
148 pub size_of_image: u32,
150 pub size_of_headers: u32,
152 pub checksum: u32,
154 pub subsystem: SubsystemType,
156 pub dll_characteristics: u16,
158 pub size_of_stack_reserve: u64,
160 pub size_of_stack_commit: u64,
162 pub size_of_heap_reserve: u64,
164 pub size_of_heap_commit: u64,
166 pub loader_flags: u32,
168 pub number_of_rva_and_sizes: u32,
170 pub data_directories: Vec<DataDirectory>,
172}
173
174impl OptionalHeader {
175 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 for _ in 0..16 {
187 data_directories.push(DataDirectory::default());
188 }
189
190 Self {
191 magic: 0x020B, 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, 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 dll_characteristics: 0x8500, 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 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 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)), Architecture::X86_64 => (0x020B, None), _ => (0x010B, Some(0x2000)), };
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, 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#[derive(Clone, Debug, Serialize, Deserialize)]
290pub struct PeHeader {
291 pub dos_header: DosHeader,
293 pub nt_header: NtHeader,
295 pub coff_header: CoffHeader,
297 pub optional_header: OptionalHeader,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct PeSection {
307 pub name: String,
309 pub virtual_size: u32,
311 pub virtual_address: u32,
313 pub size_of_raw_data: u32,
315 pub pointer_to_raw_data: u32,
317 pub pointer_to_relocations: u32,
319 pub pointer_to_line_numbers: u32,
321 pub number_of_relocations: u16,
323 pub number_of_line_numbers: u16,
325 pub characteristics: u32,
327 #[serde(skip_serializing_if = "Vec::is_empty")]
329 pub data: Vec<u8>,
330}
331
332#[derive(Debug, Clone, Copy)]
337pub struct ReadConfig {
338 pub include_sections: bool,
340 pub validate_checksum: bool,
342 pub parse_imports: bool,
344 pub parse_exports: bool,
346}
347
348impl Default for ReadConfig {
349 fn default() -> Self {
354 Self { include_sections: true, validate_checksum: false, parse_imports: true, parse_exports: true }
355 }
356}
357
358#[derive(Debug, Clone, Serialize, Deserialize)]
363pub struct PeProgram {
364 pub header: PeHeader,
366 pub sections: Vec<PeSection>,
368 pub imports: ImportTable,
370 pub exports: ExportTable,
372}
373
374impl PeProgram {
375 pub fn create_executable(machine_code: Vec<u8>) -> Self {
377 let arch = Architecture::X86_64;
378 let machine = 0x8664; let section_count = 1;
380
381 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; let size_of_image = 0x2000; 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); 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, 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, data: machine_code,
417 };
418
419 Self { header, sections: vec![section], imports: ImportTable::default(), exports: ExportTable::default() }
420 }
421
422 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 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 let idt_size = (self.imports.entries.len() + 1) * 20;
439
440 let mut current_offset = idt_size;
441
442 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 if current_offset % 2 != 0 {
451 current_offset += 1;
452 }
453
454 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 current_offset += 2 + func.len() + 1;
462 if current_offset % 2 != 0 {
464 current_offset += 1;
465 }
466 }
467 function_name_offsets.push(entry_offsets);
468 }
469
470 current_offset = (current_offset + pointer_size - 1) & !(pointer_size - 1);
472
473 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 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 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 for (i, _entry) in self.imports.entries.iter().enumerate() {
498 cursor.write_u32::<LittleEndian>(base_rva + int_offsets[i] as u32).unwrap(); cursor.write_u32::<LittleEndian>(0).unwrap(); cursor.write_u32::<LittleEndian>(0).unwrap(); cursor.write_u32::<LittleEndian>(base_rva + dll_name_offsets[i] as u32).unwrap(); cursor.write_u32::<LittleEndian>(base_rva + iat_offsets[i] as u32).unwrap();
503 }
505 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 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(); cursor.write_all(func.as_bytes()).unwrap();
520 cursor.write_u8(0).unwrap();
521 }
522 }
523
524 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 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 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, data,
562 };
563
564 self.sections.push(idata_section);
565 self.header.coff_header.number_of_sections = self.sections.len() as u16;
566
567 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 if self.header.optional_header.data_directories.len() >= 13 {
575 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 self.header.optional_header.size_of_image = base_rva + ((idata_raw_size + 0xFFF) & !0xFFF);
585
586 self
587 }
588}
589
590#[derive(Debug, Clone, Serialize, Deserialize)]
595pub struct PeInfo {
596 pub target_arch: Architecture,
598 pub subsystem: SubsystemType,
600 pub entry_point: u32,
602 pub image_base: u64,
604 pub section_count: u16,
606 pub file_size: u64,
608}
609
610#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
615pub struct DataDirectory {
616 pub virtual_address: u32,
618 pub size: u32,
620}
621
622impl DataDirectory {
623 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 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}