1use core::iter::FusedIterator;
2
3use crate::error;
4use crate::pe::{data_directories, debug, optional_header, section_table, symbol};
5use crate::strtab;
6use alloc::vec::Vec;
7use scroll::{ctx, IOread, IOwrite, Pread, Pwrite, SizeWith};
8
9#[repr(C)]
35#[derive(Debug, PartialEq, Copy, Clone, Default, Pwrite)]
36#[doc(alias("IMAGE_DOS_HEADER"))]
37pub struct DosHeader {
38 #[doc(alias("e_magic"))]
52 pub signature: u16,
53 #[doc(alias("e_cblp"))]
67 pub bytes_on_last_page: u16,
68 #[doc(alias("e_cp"))]
78 pub pages_in_file: u16,
79 #[doc(alias("e_crlc"))]
105 pub relocations: u16,
106 #[doc(alias("e_cparhdr"))]
121 pub size_of_header_in_paragraphs: u16,
122 #[doc(alias("e_minalloc"))]
137 pub minimum_extra_paragraphs_needed: u16,
138 #[doc(alias("e_maxalloc"))]
152 pub maximum_extra_paragraphs_needed: u16,
153 #[doc(alias("e_ss"))]
176 pub initial_relative_ss: u16,
177 #[doc(alias("e_sp"))]
192 pub initial_sp: u16,
193 #[doc(alias("e_csum"))]
201 pub checksum: u16,
202 #[doc(alias("e_ip"))]
212 pub initial_ip: u16,
213 #[doc(alias("e_cs"))]
223 pub initial_relative_cs: u16,
224 #[doc(alias("e_lfarlc"))]
235 pub file_address_of_relocation_table: u16,
236 #[doc(alias("e_ovno"))]
248 pub overlay_number: u16,
249 #[doc(alias("e_res"))]
257 pub reserved: [u16; 4],
258 #[doc(alias("e_oemid"))]
269 pub oem_id: u16,
270 #[doc(alias("e_oeminfo"))]
274 pub oem_info: u16,
275 #[doc(alias("e_res2"))]
283 pub reserved2: [u16; 10],
284 #[doc(alias("e_lfanew"))]
291 pub pe_pointer: u32,
292}
293
294#[doc(alias("IMAGE_DOS_SIGNATURE"))]
295pub const DOS_MAGIC: u16 = 0x5a4d;
296pub const PE_POINTER_OFFSET: u32 = 0x3c;
297pub const DOS_STUB_OFFSET: u32 = PE_POINTER_OFFSET + (core::mem::size_of::<u32>() as u32);
298
299impl DosHeader {
300 pub fn parse(bytes: &[u8]) -> error::Result<Self> {
301 let mut offset = 0;
302 let signature = bytes.gread_with(&mut offset, scroll::LE).map_err(|_| {
303 error::Error::Malformed(format!("cannot parse DOS signature (offset {:#x})", 0))
304 })?;
305 if signature != DOS_MAGIC {
306 return Err(error::Error::Malformed(format!(
307 "DOS header is malformed (signature {:#x})",
308 signature
309 )));
310 }
311
312 let bytes_on_last_page = bytes.gread_with(&mut offset, scroll::LE)?;
313 let pages_in_file = bytes.gread_with(&mut offset, scroll::LE)?;
314 let relocations = bytes.gread_with(&mut offset, scroll::LE)?;
315 let size_of_header_in_paragraphs = bytes.gread_with(&mut offset, scroll::LE)?;
316 let minimum_extra_paragraphs_needed = bytes.gread_with(&mut offset, scroll::LE)?;
317 let maximum_extra_paragraphs_needed = bytes.gread_with(&mut offset, scroll::LE)?;
318 let initial_relative_ss = bytes.gread_with(&mut offset, scroll::LE)?;
319 let initial_sp = bytes.gread_with(&mut offset, scroll::LE)?;
320 let checksum = bytes.gread_with(&mut offset, scroll::LE)?;
321 let initial_ip = bytes.gread_with(&mut offset, scroll::LE)?;
322 let initial_relative_cs = bytes.gread_with(&mut offset, scroll::LE)?;
323 let file_address_of_relocation_table = bytes.gread_with(&mut offset, scroll::LE)?;
324 let overlay_number = bytes.gread_with(&mut offset, scroll::LE)?;
325 let reserved = bytes.gread_with(&mut offset, scroll::LE)?; let oem_id = bytes.gread_with(&mut offset, scroll::LE)?;
327 let oem_info = bytes.gread_with(&mut offset, scroll::LE)?;
328 let reserved2 = bytes.gread_with(&mut offset, scroll::LE)?; debug_assert!(
331 offset == PE_POINTER_OFFSET as usize,
332 "expected offset ({:#x}) after reading DOS header to be at 0x3C",
333 offset
334 );
335
336 let pe_pointer: u32 = bytes
337 .pread_with(PE_POINTER_OFFSET as usize, scroll::LE)
338 .map_err(|_| {
339 error::Error::Malformed(format!(
340 "cannot parse PE header pointer (offset {:#x})",
341 PE_POINTER_OFFSET
342 ))
343 })?;
344
345 let pe_signature: u32 =
346 bytes
347 .pread_with(pe_pointer as usize, scroll::LE)
348 .map_err(|_| {
349 error::Error::Malformed(format!(
350 "cannot parse PE header signature (offset {:#x})",
351 pe_pointer
352 ))
353 })?;
354 if pe_signature != PE_MAGIC {
355 return Err(error::Error::Malformed(format!(
356 "PE header is malformed (signature {:#x})",
357 pe_signature
358 )));
359 }
360
361 Ok(DosHeader {
362 signature,
363 bytes_on_last_page,
364 pages_in_file,
365 relocations,
366 size_of_header_in_paragraphs,
367 minimum_extra_paragraphs_needed,
368 maximum_extra_paragraphs_needed,
369 initial_relative_ss,
370 initial_sp,
371 checksum,
372 initial_ip,
373 initial_relative_cs,
374 file_address_of_relocation_table,
375 overlay_number,
376 reserved,
377 oem_id,
378 oem_info,
379 reserved2,
380 pe_pointer,
381 })
382 }
383}
384
385#[derive(Debug, PartialEq, Copy, Clone)]
386pub struct DosStub<'a> {
395 pub data: &'a [u8],
396}
397impl<'a> Default for DosStub<'a> {
398 #[rustfmt::skip]
417 fn default() -> Self {
418 Self {
419 data: &[
420 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ],
442 }
443 }
444}
445impl<'a> ctx::TryIntoCtx<scroll::Endian> for DosStub<'a> {
446 type Error = error::Error;
447
448 fn try_into_ctx(self, bytes: &mut [u8], _: scroll::Endian) -> Result<usize, Self::Error> {
449 let offset = &mut 0;
450 bytes.gwrite_with(&*self.data, offset, ())?;
451 Ok(*offset)
452 }
453}
454
455impl<'a> DosStub<'a> {
456 pub fn parse(bytes: &'a [u8], pe_pointer: u32) -> error::Result<Self> {
461 let start_offset = DOS_STUB_OFFSET as usize;
462 let end_offset = pe_pointer as usize;
463
464 if end_offset <= start_offset {
466 return Err(error::Error::Malformed(format!(
467 "PE pointer ({:#x}) must be greater than the start offset ({:#x})",
468 pe_pointer, start_offset
469 )));
470 }
471
472 if bytes.len() < end_offset as usize {
473 return Err(error::Error::Malformed(format!(
474 "DOS stub is too short ({} bytes) to contain the PE header pointer ({:#x})",
475 bytes.len(),
476 end_offset
477 )));
478 }
479
480 let dos_stub_area = &bytes[start_offset..end_offset];
481 Ok(Self {
482 data: dos_stub_area,
483 })
484 }
485}
486
487#[repr(C)]
500#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, IOread, IOwrite, SizeWith)]
501#[doc(alias("IMAGE_FILE_HEADER"))]
502pub struct CoffHeader {
503 #[doc(alias("Machine"))]
544 pub machine: u16,
545 #[doc(alias("NumberOfSections"))]
549 pub number_of_sections: u16,
550 #[doc(alias("TimeDateStamp"))]
554 pub time_date_stamp: u32,
555 #[doc(alias("PointerToSymbolTable"))]
561 pub pointer_to_symbol_table: u32,
562 #[doc(alias("NumberOfSymbols"))]
568 pub number_of_symbol_table: u32,
569 #[doc(alias("SizeOfOptionalHeader"))]
575 pub size_of_optional_header: u16,
576 #[doc(alias("Characteristics"))]
580 pub characteristics: u16,
581}
582
583pub const SIZEOF_COFF_HEADER: usize = 20;
584pub const PE_MAGIC: u32 = 0x0000_4550;
586pub const SIZEOF_PE_MAGIC: usize = 4;
587
588#[doc(alias("IMAGE_FILE_MACHINE_UNKNOWN"))]
608pub const COFF_MACHINE_UNKNOWN: u16 = 0x0;
609
610#[doc(alias("IMAGE_FILE_MACHINE_ALPHA"))]
614pub const COFF_MACHINE_ALPHA: u16 = 0x184;
615
616#[doc(alias("IMAGE_FILE_MACHINE_ALPHA64"))]
620#[doc(alias("IMAGE_FILE_MACHINE_AXP64"))]
621pub const COFF_MACHINE_ALPHA64: u16 = 0x284;
622
623#[doc(alias("IMAGE_FILE_MACHINE_AM33"))]
627pub const COFF_MACHINE_AM33: u16 = 0x1d3;
628
629#[doc(alias("IMAGE_FILE_MACHINE_AMD64"))]
633pub const COFF_MACHINE_X86_64: u16 = 0x8664;
636
637#[doc(alias("IMAGE_FILE_MACHINE_ARM"))]
641pub const COFF_MACHINE_ARM: u16 = 0x1c0;
642
643#[doc(alias("IMAGE_FILE_MACHINE_ARM64"))]
647pub const COFF_MACHINE_ARM64: u16 = 0xaa64;
648
649#[doc(alias("IMAGE_FILE_MACHINE_ARMNT"))]
653pub const COFF_MACHINE_ARMNT: u16 = 0x1c4;
654
655#[doc(alias("IMAGE_FILE_MACHINE_EBC"))]
659pub const COFF_MACHINE_EBC: u16 = 0xebc;
660
661#[doc(alias("IMAGE_FILE_MACHINE_I386"))]
667pub const COFF_MACHINE_X86: u16 = 0x14c;
668
669#[doc(alias("IMAGE_FILE_MACHINE_IA64"))]
673pub const COFF_MACHINE_IA64: u16 = 0x200;
674
675#[doc(alias("IMAGE_FILE_MACHINE_LOONGARCH32"))]
679pub const COFF_MACHINE_LOONGARCH32: u16 = 0x6232;
680
681#[doc(alias("IMAGE_FILE_MACHINE_LOONGARCH64"))]
685pub const COFF_MACHINE_LOONGARCH64: u16 = 0x6264;
686
687#[doc(alias("IMAGE_FILE_MACHINE_M32R"))]
691pub const COFF_MACHINE_M32R: u16 = 0x9041;
692
693#[doc(alias("IMAGE_FILE_MACHINE_MIPS16"))]
697pub const COFF_MACHINE_MIPS16: u16 = 0x266;
698
699#[doc(alias("IMAGE_FILE_MACHINE_MIPSFPU"))]
703pub const COFF_MACHINE_MIPSFPU: u16 = 0x366;
704
705#[doc(alias("IMAGE_FILE_MACHINE_MIPSFPU16"))]
709pub const COFF_MACHINE_MIPSFPU16: u16 = 0x466;
710
711#[doc(alias("IMAGE_FILE_MACHINE_POWERPC"))]
715pub const COFF_MACHINE_POWERPC: u16 = 0x1f0;
716
717#[doc(alias("IMAGE_FILE_MACHINE_POWERPCFP"))]
721pub const COFF_MACHINE_POWERPCFP: u16 = 0x1f1;
722
723#[doc(alias("IMAGE_FILE_MACHINE_R4000"))]
727pub const COFF_MACHINE_R4000: u16 = 0x166;
728
729#[doc(alias("IMAGE_FILE_MACHINE_RISCV32"))]
733pub const COFF_MACHINE_RISCV32: u16 = 0x5032;
734
735#[doc(alias("IMAGE_FILE_MACHINE_RISCV64"))]
739pub const COFF_MACHINE_RISCV64: u16 = 0x5064;
740
741#[doc(alias("IMAGE_FILE_MACHINE_RISCV128"))]
745pub const COFF_MACHINE_RISCV128: u16 = 0x5128;
746
747#[doc(alias("IMAGE_FILE_MACHINE_SH3"))]
751pub const COFF_MACHINE_SH3: u16 = 0x1a2;
752
753#[doc(alias("IMAGE_FILE_MACHINE_SH3DSP"))]
757pub const COFF_MACHINE_SH3DSP: u16 = 0x1a3;
758
759#[doc(alias("IMAGE_FILE_MACHINE_SH4"))]
763pub const COFF_MACHINE_SH4: u16 = 0x1a6;
764
765#[doc(alias("IMAGE_FILE_MACHINE_SH5"))]
769pub const COFF_MACHINE_SH5: u16 = 0x1a8;
770
771#[doc(alias("IMAGE_FILE_MACHINE_THUMB"))]
775pub const COFF_MACHINE_THUMB: u16 = 0x1c2;
776
777#[doc(alias("IMAGE_FILE_MACHINE_WCEMIPSV2"))]
781pub const COFF_MACHINE_WCEMIPSV2: u16 = 0x169;
782
783impl CoffHeader {
784 pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> {
785 Ok(bytes.gread_with(offset, scroll::LE)?)
786 }
787
788 pub fn sections(
793 &self,
794 bytes: &[u8],
795 offset: &mut usize,
796 ) -> error::Result<Vec<section_table::SectionTable>> {
797 let nsections = self.number_of_sections as usize;
798
799 if nsections > bytes.len() / 40 {
801 return Err(error::Error::BufferTooShort(nsections, "sections"));
802 }
803
804 let mut sections = Vec::with_capacity(nsections);
805 let string_table_offset = self.pointer_to_symbol_table as usize
807 + symbol::SymbolTable::size(self.number_of_symbol_table as usize);
808 for i in 0..nsections {
809 let section =
810 section_table::SectionTable::parse(bytes, offset, string_table_offset as usize)?;
811 debug!("({}) {:#?}", i, section);
812 sections.push(section);
813 }
814 Ok(sections)
815 }
816
817 pub fn symbols<'a>(&self, bytes: &'a [u8]) -> error::Result<Option<symbol::SymbolTable<'a>>> {
819 let offset = self.pointer_to_symbol_table as usize;
820 let number = self.number_of_symbol_table as usize;
821 if offset == 0 {
822 Ok(None)
823 } else {
824 symbol::SymbolTable::parse(bytes, offset, number).map(Some)
825 }
826 }
827
828 pub fn strings<'a>(&self, bytes: &'a [u8]) -> error::Result<Option<strtab::Strtab<'a>>> {
830 if self.pointer_to_symbol_table == 0 {
833 return Ok(None);
834 }
835
836 let mut offset = self.pointer_to_symbol_table as usize
837 + symbol::SymbolTable::size(self.number_of_symbol_table as usize);
838
839 let length_field_size = core::mem::size_of::<u32>();
840 let length = bytes
841 .pread_with::<u32>(offset, scroll::LE)?
842 .checked_sub(length_field_size as u32)
843 .ok_or(error::Error::Malformed(format!(
844 "COFF length field size ({length_field_size:#x}) is larger than the parsed length value"
845 )))? as usize;
846
847 offset += length_field_size;
849
850 Ok(Some(strtab::Strtab::parse(bytes, offset, length, 0)?))
851 }
852}
853
854#[derive(Debug, PartialEq, Copy, Clone, Default)]
861pub struct Header<'a> {
862 pub dos_header: DosHeader,
863 pub dos_stub: DosStub<'a>,
865 pub rich_header: Option<RichHeader<'a>>,
866
867 pub signature: u32,
869 pub coff_header: CoffHeader,
870 pub optional_header: Option<optional_header::OptionalHeader>,
871}
872
873impl<'a> Header<'a> {
874 fn parse_impl(
875 bytes: &'a [u8],
876 dos_header: DosHeader,
877 dos_stub: DosStub<'a>,
878 parse_rich_header: bool,
879 ) -> error::Result<Self> {
880 let mut offset = dos_header.pe_pointer as usize;
881 let rich_header = if parse_rich_header {
882 RichHeader::parse(&bytes)?
883 } else {
884 None
885 };
886 let signature = bytes.gread_with(&mut offset, scroll::LE).map_err(|_| {
887 error::Error::Malformed(format!("cannot parse PE signature (offset {:#x})", offset))
888 })?;
889 let coff_header = CoffHeader::parse(&bytes, &mut offset)?;
890 let optional_header = if coff_header.size_of_optional_header > 0 {
891 Some(bytes.pread::<optional_header::OptionalHeader>(offset)?)
892 } else {
893 None
894 };
895
896 Ok(Header {
897 dos_header,
898 dos_stub,
899 rich_header,
900 signature,
901 coff_header,
902 optional_header,
903 })
904 }
905
906 pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
908 let dos_header = DosHeader::parse(&bytes)?;
909 let dos_stub = DosStub::parse(bytes, dos_header.pe_pointer)?;
910
911 Header::parse_impl(bytes, dos_header, dos_stub, true)
912 }
913
914 pub fn parse_without_dos(bytes: &'a [u8]) -> error::Result<Self> {
916 debug_assert!(
917 !bytes.starts_with(b"MZ"),
918 "Buf should not contain DOS header and stub"
919 );
920 let dos_header = DosHeader::default();
921 Header::parse_impl(bytes, dos_header, DosStub::default(), false)
922 }
923}
924
925impl<'a> ctx::TryIntoCtx<scroll::Endian> for Header<'a> {
926 type Error = error::Error;
927
928 fn try_into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) -> Result<usize, Self::Error> {
929 let offset = &mut 0;
930 bytes.gwrite_with(self.dos_header, offset, ctx)?;
931 bytes.gwrite_with(self.dos_stub, offset, ctx)?;
932 bytes.gwrite_with(self.signature, offset, scroll::LE)?;
933 bytes.gwrite_with(self.coff_header, offset, ctx)?;
934 if let Some(opt_header) = self.optional_header {
935 bytes.gwrite_with(opt_header, offset, ctx)?;
936 }
937 Ok(*offset)
938 }
939}
940
941pub const DANS_MARKER: u32 = 0x536E6144;
943pub const DANS_MARKER_SIZE: usize = core::mem::size_of::<u32>();
945pub const RICH_MARKER: u32 = 0x68636952;
947pub const RICH_MARKER_SIZE: usize = core::mem::size_of::<u32>();
949
950#[derive(Debug, PartialEq, Copy, Clone, Default)]
954pub struct RichHeader<'a> {
955 pub key: u32,
957 pub data: &'a [u8],
959 pub padding_size: usize,
961 pub start_offset: u32,
963 pub end_offset: u32,
965}
966
967#[repr(C)]
969#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite)]
970pub struct RichMetadata {
971 pub build: u16,
973 pub product: u16,
975 pub use_count: u32,
977}
978
979impl RichMetadata {
980 fn parse(bytes: &[u8], key: u32) -> error::Result<Self> {
982 let mut offset = 0;
983 let build_and_product = bytes.gread_with::<u32>(&mut offset, scroll::LE)? ^ key;
984 let build = (build_and_product & 0xFFFF) as u16;
985 let product = (build_and_product >> 16) as u16;
986 let use_count = bytes.gread_with::<u32>(&mut offset, scroll::LE)? ^ key;
987 Ok(Self {
988 build,
989 product,
990 use_count,
991 })
992 }
993}
994
995const RICH_METADATA_SIZE: usize = 8;
997
998#[derive(Debug)]
1000pub struct RichMetadataIterator<'a> {
1001 key: u32,
1003 data: &'a [u8],
1005}
1006
1007impl Iterator for RichMetadataIterator<'_> {
1008 type Item = error::Result<RichMetadata>;
1009
1010 fn next(&mut self) -> Option<Self::Item> {
1011 if self.data.is_empty() {
1012 return None;
1013 }
1014
1015 Some(match RichMetadata::parse(&self.data, self.key) {
1017 Ok(metadata) => {
1018 self.data = &self.data[RICH_METADATA_SIZE..];
1019 Ok(metadata)
1020 }
1021 Err(error) => {
1022 self.data = &[];
1023 Err(error.into())
1024 }
1025 })
1026 }
1027
1028 fn size_hint(&self) -> (usize, Option<usize>) {
1029 let len = self.data.len() / RICH_METADATA_SIZE;
1030 (len, Some(len))
1031 }
1032}
1033
1034impl FusedIterator for RichMetadataIterator<'_> {}
1035impl ExactSizeIterator for RichMetadataIterator<'_> {}
1036
1037impl<'a> RichHeader<'a> {
1038 pub fn parse(bytes: &'a [u8]) -> error::Result<Option<Self>> {
1051 let dos_header = DosHeader::parse(bytes)?;
1053 let dos_header_end_offset = PE_POINTER_OFFSET as usize;
1054 let pe_header_start_offset = dos_header.pe_pointer as usize;
1055
1056 if (pe_header_start_offset - dos_header_end_offset) < 8 {
1058 return Ok(None);
1059 }
1060
1061 let scan_start = dos_header_end_offset + 4;
1063 let scan_end = pe_header_start_offset;
1064 if scan_start > scan_end {
1065 return Err(error::Error::Malformed(format!(
1066 "Rich header scan start ({:#X}) is greater than scan end ({:#X})",
1067 scan_start, scan_end
1068 )));
1069 }
1070 let scan_stub = &bytes[scan_start..scan_end];
1071
1072 let (rich_end_offset, key) = match scan_stub
1074 .windows(8)
1075 .enumerate()
1076 .filter_map(
1077 |(index, window)| match window.pread_with::<u32>(0, scroll::LE) {
1078 Ok(marker) if marker == RICH_MARKER => Some(Ok(index)),
1080 Err(e) => Some(Err(error::Error::from(e))),
1082 _ => None,
1084 },
1085 )
1086 .next()
1088 {
1089 Some(Ok(rich_end_offset)) => {
1090 let rich_key =
1091 scan_stub.pread_with::<u32>(rich_end_offset + RICH_MARKER_SIZE, scroll::LE)?;
1092 (rich_end_offset, rich_key)
1093 }
1094 Some(Err(e)) => return Err(e),
1096 None => return Ok(None),
1098 };
1099
1100 if rich_end_offset >= scan_stub.len() {
1102 return Err(error::Error::Malformed(format!(
1103 "Rich end offset ({:#X}) exceeds scan stub length ({:#X})",
1104 rich_end_offset,
1105 scan_stub.len()
1106 )));
1107 }
1108 let rich_header = &scan_stub[..rich_end_offset];
1110
1111 let rich_start_offset = match scan_stub
1113 .windows(4)
1114 .enumerate()
1115 .filter_map(
1116 |(index, window)| match window.pread_with::<u32>(0, scroll::LE) {
1117 Ok(value) if (value ^ key) == DANS_MARKER => Some(Ok(index + DANS_MARKER_SIZE)),
1119 Err(e) => Some(Err(error::Error::from(e))),
1121 _ => None,
1123 },
1124 )
1125 .next()
1127 {
1128 Some(Ok(offset)) => offset,
1130 Some(Err(e)) => return Err(e),
1132 None => {
1134 return Err(error::Error::Malformed(format!(
1135 "Rich header does not contain the DanS marker"
1136 )));
1137 }
1138 };
1139
1140 if rich_start_offset >= rich_header.len() {
1142 return Err(error::Error::Malformed(format!(
1143 "Rich start offset ({:#X}) exceeds rich header length ({:#X})",
1144 rich_start_offset,
1145 rich_header.len()
1146 )));
1147 }
1148 let rich_header = &rich_header[rich_start_offset..];
1150
1151 let padding_size = rich_header
1153 .chunks(4)
1154 .map(|chunk| chunk.pread_with::<u32>(0, scroll::LE))
1155 .collect::<Result<Vec<_>, _>>()?
1156 .into_iter()
1157 .take_while(|value| value == &key)
1158 .count()
1159 * core::mem::size_of_val(&key);
1160
1161 let data = rich_header;
1163
1164 let start_offset = scan_start as u32 + rich_start_offset as u32 - DANS_MARKER_SIZE as u32;
1166 let end_offset = scan_start as u32 + rich_end_offset as u32;
1167
1168 Ok(Some(RichHeader {
1169 key,
1170 data,
1171 padding_size,
1172 start_offset,
1173 end_offset,
1174 }))
1175 }
1176
1177 pub fn metadatas(&self) -> RichMetadataIterator<'a> {
1179 RichMetadataIterator {
1180 key: self.key,
1181 data: &self.data[self.padding_size..],
1182 }
1183 }
1184}
1185
1186#[cfg(feature = "te")]
1192#[repr(C)]
1193#[derive(Debug, Default, PartialEq, Copy, Clone, Pread, Pwrite)]
1194pub struct TeHeader {
1195 pub signature: u16,
1197 pub machine: u16,
1199 pub number_of_sections: u8,
1201 pub subsystem: u8,
1203 pub stripped_size: u16,
1206 pub entry_point: u32,
1208 pub base_of_code: u32,
1210 pub image_base: u64,
1212 pub reloc_dir: data_directories::DataDirectory,
1214 pub debug_dir: data_directories::DataDirectory,
1216}
1217
1218#[cfg(feature = "te")]
1219#[doc(alias("IMAGE_TE_SIGNATURE"))]
1220pub const TE_MAGIC: u16 = 0x5a56;
1221
1222#[cfg(feature = "te")]
1223impl TeHeader {
1224 pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> {
1226 const HEADER_SIZE: usize = core::mem::size_of::<TeHeader>();
1227 let mut header: TeHeader = bytes.gread_with(offset, scroll::LE)?;
1228 let stripped_size = header.stripped_size as u32;
1229 let adj_offset = stripped_size
1230 .checked_sub(HEADER_SIZE as u32)
1231 .ok_or_else(|| {
1232 error::Error::Malformed(format!(
1233 "Stripped size ({stripped_size:#x}) is smaller than TE header size ({HEADER_SIZE:#x})",
1234 ))
1235 })?;
1236 header.fixup_header(adj_offset);
1237 Ok(header)
1238 }
1239
1240 pub fn sections(
1242 &self,
1243 bytes: &[u8],
1244 offset: &mut usize,
1245 ) -> error::Result<Vec<section_table::SectionTable>> {
1246 let adj_offset = self.stripped_size as u32 - core::mem::size_of::<TeHeader>() as u32;
1247 let nsections = self.number_of_sections as usize;
1248
1249 if nsections > bytes.len() / 40 {
1251 return Err(error::Error::BufferTooShort(nsections, "sections"));
1252 }
1253
1254 let mut sections = Vec::with_capacity(nsections);
1255 for i in 0..nsections {
1256 let mut section = section_table::SectionTable::parse(bytes, offset, 0)?;
1257 TeHeader::fixup_section(&mut section, adj_offset);
1258 debug!("({}) {:#?}", i, section);
1259 sections.push(section);
1260 }
1261 Ok(sections)
1262 }
1263
1264 fn fixup_header(&mut self, adj_offset: u32) {
1266 debug!(
1267 "Entry point fixed up from: 0x{:x} to 0x{:X}",
1268 self.entry_point,
1269 self.entry_point.wrapping_sub(adj_offset)
1270 );
1271 self.entry_point = self.entry_point.wrapping_sub(adj_offset);
1272
1273 debug!(
1274 "Base of code fixed up from: 0x{:x} to 0x{:X}",
1275 self.base_of_code,
1276 self.base_of_code.wrapping_sub(adj_offset)
1277 );
1278 self.base_of_code = self.base_of_code.wrapping_sub(adj_offset);
1279
1280 debug!(
1281 "Relocation Directory fixed up from: 0x{:x} to 0x{:X}",
1282 self.reloc_dir.virtual_address,
1283 self.reloc_dir.virtual_address.wrapping_sub(adj_offset)
1284 );
1285 self.reloc_dir.virtual_address = self.reloc_dir.virtual_address.wrapping_sub(adj_offset);
1286
1287 debug!(
1288 "Debug Directory fixed up from: 0x{:x} to 0x{:X}",
1289 self.debug_dir.virtual_address,
1290 self.debug_dir.virtual_address.wrapping_sub(adj_offset)
1291 );
1292 self.debug_dir.virtual_address = self.debug_dir.virtual_address.wrapping_sub(adj_offset);
1293 }
1294
1295 fn fixup_section(section: &mut section_table::SectionTable, adj_offset: u32) {
1297 debug!(
1298 "Section virtual address fixed up from: 0x{:X} to 0x{:X}",
1299 section.virtual_address,
1300 section.virtual_address.wrapping_sub(adj_offset)
1301 );
1302 section.virtual_address = section.virtual_address.wrapping_sub(adj_offset);
1303
1304 if section.pointer_to_linenumbers > 0 {
1305 debug!(
1306 "Section pointer to line numbers fixed up from: 0x{:X} to 0x{:X}",
1307 section.pointer_to_linenumbers,
1308 section.pointer_to_linenumbers.wrapping_sub(adj_offset)
1309 );
1310 section.pointer_to_linenumbers =
1311 section.pointer_to_linenumbers.wrapping_sub(adj_offset);
1312 }
1313
1314 if section.pointer_to_raw_data > 0 {
1315 debug!(
1316 "Section pointer to raw data fixed up from: 0x{:X} to 0x{:X}",
1317 section.pointer_to_raw_data,
1318 section.pointer_to_raw_data.wrapping_sub(adj_offset)
1319 );
1320 section.pointer_to_raw_data = section.pointer_to_raw_data.wrapping_sub(adj_offset);
1321 }
1322
1323 if section.pointer_to_relocations > 0 {
1324 debug!(
1325 "Section pointer to relocations fixed up from: 0x{:X} to 0x{:X}",
1326 section.pointer_to_relocations,
1327 section.pointer_to_relocations.wrapping_sub(adj_offset)
1328 );
1329 section.pointer_to_relocations =
1330 section.pointer_to_relocations.wrapping_sub(adj_offset);
1331 }
1332 }
1333}
1334
1335pub fn machine_to_str(machine: u16) -> &'static str {
1338 match machine {
1340 COFF_MACHINE_UNKNOWN => "UNKNOWN",
1341 COFF_MACHINE_ALPHA => "ALPHA",
1342 COFF_MACHINE_ALPHA64 => "ALPHA64",
1343 COFF_MACHINE_AM33 => "AM33",
1344 COFF_MACHINE_X86_64 => "X86_64",
1346 COFF_MACHINE_ARM => "ARM",
1347 COFF_MACHINE_ARM64 => "ARM64",
1348 COFF_MACHINE_ARMNT => "ARM_NT",
1349 COFF_MACHINE_EBC => "EBC",
1350 COFF_MACHINE_X86 => "X86",
1352 COFF_MACHINE_IA64 => "IA64",
1353 COFF_MACHINE_LOONGARCH32 => "LOONGARCH32",
1354 COFF_MACHINE_LOONGARCH64 => "LOONGARCH64",
1355 COFF_MACHINE_M32R => "M32R",
1356 COFF_MACHINE_MIPS16 => "MIPS_16",
1357 COFF_MACHINE_MIPSFPU => "MIPS_FPU",
1358 COFF_MACHINE_MIPSFPU16 => "MIPS_FPU_16",
1359 COFF_MACHINE_POWERPC => "POWERPC",
1360 COFF_MACHINE_POWERPCFP => "POWERCFP",
1361 COFF_MACHINE_R4000 => "R4000",
1362 COFF_MACHINE_RISCV32 => "RISC-V_32",
1363 COFF_MACHINE_RISCV64 => "RISC-V_64",
1364 COFF_MACHINE_RISCV128 => "RISC-V_128",
1365 COFF_MACHINE_SH3 => "SH3",
1366 COFF_MACHINE_SH3DSP => "SH3DSP",
1367 COFF_MACHINE_SH4 => "SH4",
1368 COFF_MACHINE_SH5 => "SH5",
1369 COFF_MACHINE_THUMB => "THUMB",
1370 COFF_MACHINE_WCEMIPSV2 => "WCE_MIPS_V2",
1371 _ => "COFF_UNKNOWN",
1372 }
1373}
1374
1375#[cfg(test)]
1376mod tests {
1377 use crate::{
1378 error,
1379 pe::{
1380 header::{DosStub, TeHeader},
1381 Coff,
1382 },
1383 };
1384
1385 use super::{
1386 machine_to_str, DosHeader, Header, RichHeader, RichMetadata, COFF_MACHINE_X86, DOS_MAGIC,
1387 PE_MAGIC,
1388 };
1389
1390 const CRSS_HEADER: [u8; 688] = [
1391 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
1392 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1393 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1394 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1395 0xd0, 0x00, 0x00, 0x00, 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01,
1396 0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d,
1397 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20,
1398 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
1399 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x4a, 0xc3, 0xeb, 0xee, 0x2b, 0xad,
1400 0xb8, 0xee, 0x2b, 0xad, 0xb8, 0xee, 0x2b, 0xad, 0xb8, 0xee, 0x2b, 0xac, 0xb8, 0xfe, 0x2b,
1401 0xad, 0xb8, 0x33, 0xd4, 0x66, 0xb8, 0xeb, 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x63, 0xb8, 0xea,
1402 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x7a, 0xb8, 0xed, 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x64, 0xb8,
1403 0xef, 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x61, 0xb8, 0xef, 0x2b, 0xad, 0xb8, 0x52, 0x69, 0x63,
1404 0x68, 0xee, 0x2b, 0xad, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x45,
1405 0x00, 0x00, 0x4c, 0x01, 0x05, 0x00, 0xd9, 0x8f, 0x15, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00,
1406 0x00, 0x00, 0x00, 0xe0, 0x00, 0x02, 0x01, 0x0b, 0x01, 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
1407 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00,
1408 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02,
1409 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00,
1410 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xe4, 0xab, 0x00, 0x00,
1411 0x01, 0x00, 0x40, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x10,
1412 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
1413 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
1414 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1415 0x00, 0x1a, 0x00, 0x00, 0xb8, 0x22, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x38, 0x00, 0x00,
1416 0x00, 0x10, 0x10, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1417 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1418 0x00, 0x00, 0x00, 0x68, 0x10, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1419 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1420 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1421 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x24,
1422 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1423 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
1424 0x60, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x00, 0x20,
1425 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1426 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xc0, 0x2e, 0x69, 0x64, 0x61,
1427 0x74, 0x61, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00,
1428 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1429 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x2e, 0x72, 0x73, 0x72, 0x63, 0x00, 0x00, 0x00, 0x00,
1430 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
1431 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
1432 0x42, 0x2e, 0x72, 0x65, 0x6c, 0x6f, 0x63, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x50,
1433 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1434 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00,
1435 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1436 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1437 ];
1438
1439 const NO_RICH_HEADER: [u8; 262] = [
1440 0x4D, 0x5A, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0x00,
1441 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x1A, 0x00, 0x00, 0x00,
1442 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1443 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1444 0x00, 0x01, 0x00, 0x00, 0xBA, 0x10, 0x00, 0x0E, 0x1F, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1445 0x4C, 0xCD, 0x21, 0x90, 0x90, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72,
1446 0x61, 0x6D, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1447 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x57, 0x69, 0x6E, 0x33, 0x32, 0x0D, 0x0A, 0x24, 0x37,
1448 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1449 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1451 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1452 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1455 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1456 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1457 0x00, 0x50, 0x45, 0x00, 0x00, 0x64, 0x86,
1458 ];
1459
1460 const NO_RICH_HEADER_INVALID_PE_POINTER: [u8; 304] = [
1461 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
1462 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1463 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1465 0x3C, 0xFF, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1466 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D,
1467 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1468 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
1469 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0xC7, 0xEA, 0x07, 0xC9, 0xA6, 0x84,
1470 0x54, 0xC9, 0xA6, 0x84, 0x54, 0xC9, 0xA6, 0x84, 0x54, 0x10, 0xD2, 0x81, 0x55, 0xCB, 0xA6,
1471 0x84, 0x54, 0xC0, 0xDE, 0x17, 0x54, 0xC1, 0xA6, 0x84, 0x54, 0xDD, 0xCD, 0x80, 0x55, 0xC7,
1472 0xA6, 0x84, 0x54, 0xDD, 0xCD, 0x87, 0x55, 0xC1, 0xA6, 0x84, 0x54, 0xDD, 0xCD, 0x81, 0x55,
1473 0x7E, 0xA6, 0x84, 0x54, 0xB9, 0x27, 0x85, 0x55, 0xCA, 0xA6, 0x84, 0x54, 0xC9, 0xA6, 0x85,
1474 0x54, 0x08, 0xA6, 0x84, 0x54, 0xA5, 0xD2, 0x81, 0x55, 0xE8, 0xA6, 0x84, 0x54, 0xA5, 0xD2,
1475 0x80, 0x55, 0xD9, 0xA6, 0x84, 0x54, 0xA5, 0xD2, 0x87, 0x55, 0xC0, 0xA6, 0x84, 0x54, 0x10,
1476 0xD2, 0x80, 0x55, 0x49, 0xA6, 0x84, 0x54, 0x10, 0xD2, 0x84, 0x55, 0xC8, 0xA6, 0x84, 0x54,
1477 0x10, 0xD2, 0x7B, 0x54, 0xC8, 0xA6, 0x84, 0x54, 0x10, 0xD2, 0x86, 0x55, 0xC8, 0xA6, 0x84,
1478 0x54, 0x52, 0x69, 0x63, 0x68, 0xC9, 0xA6, 0x84, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1480 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x64, 0x86, 0x07, 0x00, 0xEC, 0xA5, 0x5B, 0x66,
1481 0x00, 0x00, 0x00, 0x00,
1482 ];
1483
1484 const CORRECT_RICH_HEADER: [u8; 256] = [
1485 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
1486 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1487 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1489 0xF8, 0x00, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1490 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D,
1491 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1492 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
1493 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x4C, 0x5B, 0xB1, 0x37, 0x2D, 0x35,
1494 0xE2, 0x37, 0x2D, 0x35, 0xE2, 0x37, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x31, 0xE3, 0x3D, 0x2D,
1495 0x35, 0xE2, 0x44, 0x4F, 0x36, 0xE3, 0x32, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x30, 0xE3, 0x48,
1496 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x36, 0xE3, 0x3E, 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x30, 0xE3,
1497 0x14, 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x31, 0xE3, 0x25, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x34,
1498 0xE3, 0x3C, 0x2D, 0x35, 0xE2, 0x37, 0x2D, 0x34, 0xE2, 0xAF, 0x2D, 0x35, 0xE2, 0x37, 0x2D,
1499 0x35, 0xE2, 0x23, 0x2D, 0x35, 0xE2, 0xFC, 0x4E, 0x37, 0xE3, 0x36, 0x2D, 0x35, 0xE2, 0x52,
1500 0x69, 0x63, 0x68, 0x37, 0x2D, 0x35, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x64, 0x86, 0x05,
1502 0x00,
1503 ];
1504
1505 const CORRUPTED_RICH_HEADER: [u8; 256] = [
1506 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
1507 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1510 0xF8, 0x00, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1511 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D,
1512 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1513 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
1514 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x4C, 0x5B, 0xB1, 0x37, 0x2D, 0x35,
1515 0xE2, 0x37, 0x2D, 0x35, 0xE2, 0x37, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x31, 0xE3, 0x3D, 0x2D,
1516 0x35, 0xE2, 0x44, 0x4F, 0x36, 0xE3, 0x32, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x30, 0xE3, 0x48,
1517 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x36, 0xE3, 0x3E, 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x30, 0xE3,
1518 0x14, 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x31, 0xE3, 0x25, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x34,
1519 0xE3, 0x3C, 0x2D, 0x35, 0xE2, 0x37, 0x2D, 0x34, 0xE2, 0xAF, 0x2D, 0x35, 0xE2, 0x37, 0x2D,
1520 0x35, 0xE2, 0x23, 0x2D, 0x35, 0xE2, 0xFC, 0x4E, 0x37, 0xE3, 0x36, 0x2D, 0x35, 0xE2, 0x52,
1521 0x69, 0x63, 0x68, 0x37, 0x2D, 0x35, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1522 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x64, 0x86, 0x05,
1523 0x00,
1524 ];
1525
1526 const BORLAND_PE32_VALID_NO_RICH_HEADER: [u8; 528] = [
1527 0x4D, 0x5A, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0x00,
1528 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x1A, 0x00, 0x00, 0x00,
1529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1530 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1531 0x00, 0x02, 0x00, 0x00, 0xBA, 0x10, 0x00, 0x0E, 0x1F, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1532 0x4C, 0xCD, 0x21, 0x90, 0x90, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72,
1533 0x61, 0x6D, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1534 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x57, 0x69, 0x6E, 0x33, 0x32, 0x0D, 0x0A, 0x24, 0x37,
1535 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1536 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1537 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1538 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1539 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1541 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1542 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1543 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1550 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1561 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x08, 0x00, 0xC0, 0x9C, 0x07, 0x67, 0x00, 0x00, 0x00,
1563 0x00,
1564 ];
1565
1566 const MALFORMED_SMALL_TE: [u8; 58] = [
1570 0x56, 0x5A, 0x52, 0x5A, 0x50, 0x00, 0x17, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00,
1571 0x10, 0x86, 0x02, 0x0C, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x1B, 0x01, 0x01, 0x00, 0x00,
1572 0xFF, 0xB5, 0x00, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0xFF, 0xB5, 0x00, 0x00, 0x00, 0x04,
1573 0x34, 0x15, 0x40, 0x13, 0x41, 0x0E, 0x10, 0x15, 0x40, 0x13, 0x41, 0x0E, 0x10,
1574 ];
1575
1576 const INVALID_COFF_OBJECT: [u8; 20] = [
1580 0x4C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1581 0x00, 0x0F, 0x00, 0xFF, 0x80,
1582 ];
1583
1584 const BIN: &[u8] = include_bytes!("../../tests/bins/pe/well_formed_import.exe.bin");
1585
1586 #[test]
1587 fn crss_header() {
1588 let header = Header::parse(&&CRSS_HEADER[..]).unwrap();
1589 assert!(header.dos_header.signature == DOS_MAGIC);
1590 assert!(header.signature == PE_MAGIC);
1591 assert!(header.coff_header.machine == COFF_MACHINE_X86);
1592 assert!(machine_to_str(header.coff_header.machine) == "X86");
1593 println!("header: {:?}", &header);
1594 }
1595
1596 #[test]
1597 fn parse_without_dos() {
1598 let result = std::panic::catch_unwind(|| {
1599 let _ = Header::parse_without_dos(&BORLAND_PE32_VALID_NO_RICH_HEADER).unwrap();
1600 });
1601 assert!(result.is_err(), "Expected panic, got {result:?}");
1602 if let Err(err) = result {
1603 if let Some(s) = err.downcast_ref::<&str>() {
1604 assert_eq!(
1605 *s, "Buf should not contain DOS header and stub",
1606 "Panic message did not match"
1607 );
1608 } else {
1609 panic!("Unexpected panic type");
1610 }
1611 }
1612
1613 let dos_header = DosHeader::parse(&BIN).unwrap();
1615 let buf = &BIN[dos_header.pe_pointer as usize..];
1617 Header::parse_without_dos(buf).unwrap();
1618 }
1619
1620 #[test]
1621 fn parse_borland_weird_dos_stub() {
1622 let dos_stub = DosStub::parse(&BORLAND_PE32_VALID_NO_RICH_HEADER, 0x200).unwrap();
1623 assert_ne!(dos_stub.data, BORLAND_PE32_VALID_NO_RICH_HEADER.to_vec());
1624 }
1625
1626 #[test]
1627 fn parse_borland_no_rich_header() {
1628 let header = RichHeader::parse(&BORLAND_PE32_VALID_NO_RICH_HEADER).unwrap();
1629 assert_eq!(header, None);
1630 }
1631
1632 #[test]
1633 fn parse_no_rich_header() {
1634 let header = RichHeader::parse(&NO_RICH_HEADER).unwrap();
1635 assert_eq!(header, None);
1636 }
1637
1638 #[test]
1639 fn parse_no_rich_header_invalid_pe_pointer() {
1640 let header = RichHeader::parse(&NO_RICH_HEADER_INVALID_PE_POINTER);
1641 assert_eq!(header.is_err(), true);
1642 if let Err(error::Error::Malformed(msg)) = header {
1643 assert_eq!(msg, "cannot parse PE header signature (offset 0xff3c)");
1644 } else {
1645 panic!("Expected a Malformed error but got {:?}", header);
1646 }
1647 }
1648
1649 #[test]
1650 fn parse_correct_rich_header() {
1651 let header = RichHeader::parse(&CORRECT_RICH_HEADER).unwrap();
1652 assert_ne!(header, None);
1653 let header = header.unwrap();
1654 let expected = vec![
1655 RichMetadata {
1656 build: 25203,
1657 product: 260,
1658 use_count: 10,
1659 },
1660 RichMetadata {
1661 build: 25203,
1662 product: 259,
1663 use_count: 5,
1664 },
1665 RichMetadata {
1666 build: 25203,
1667 product: 261,
1668 use_count: 127,
1669 },
1670 RichMetadata {
1671 build: 25305,
1672 product: 259,
1673 use_count: 9,
1674 },
1675 RichMetadata {
1676 build: 25305,
1677 product: 261,
1678 use_count: 35,
1679 },
1680 RichMetadata {
1681 build: 25305,
1682 product: 260,
1683 use_count: 18,
1684 },
1685 RichMetadata {
1686 build: 25203,
1687 product: 257,
1688 use_count: 11,
1689 },
1690 RichMetadata {
1691 build: 0,
1692 product: 1,
1693 use_count: 152,
1694 },
1695 RichMetadata {
1696 build: 0,
1697 product: 0,
1698 use_count: 20,
1699 },
1700 RichMetadata {
1701 build: 25547,
1702 product: 258,
1703 use_count: 1,
1704 },
1705 ];
1706 assert_eq!(
1707 header
1708 .metadatas()
1709 .filter_map(Result::ok)
1710 .collect::<Vec<RichMetadata>>(),
1711 expected
1712 );
1713 }
1714
1715 #[test]
1716 fn parse_corrupted_rich_header() {
1717 let header_result = RichHeader::parse(&CORRUPTED_RICH_HEADER);
1718 assert_eq!(header_result.is_err(), true);
1719 }
1720
1721 #[test]
1722 fn parse_invalid_small_coff() {
1723 let header = Coff::parse(&INVALID_COFF_OBJECT);
1724 assert_eq!(header.is_err(), true);
1725 if let Err(error::Error::Malformed(msg)) = header {
1726 assert_eq!(
1727 msg,
1728 "COFF length field size (0x4) is larger than the parsed length value"
1729 );
1730 } else {
1731 panic!("Expected a Malformed error but got {:?}", header);
1732 }
1733 }
1734
1735 #[test]
1736 fn parse_malformed_small_te() {
1737 let mut offset = 0;
1738 let header = TeHeader::parse(&MALFORMED_SMALL_TE, &mut offset);
1739 assert_eq!(header.is_err(), true);
1740 if let Err(error::Error::Malformed(msg)) = header {
1741 assert_eq!(
1742 msg,
1743 "Stripped size (0x17) is smaller than TE header size (0x28)"
1744 );
1745 } else {
1746 panic!("Expected a Malformed error but got {:?}", header);
1747 }
1748 }
1749}