1use alloc::vec::Vec;
2use core::iter::FusedIterator;
3
4use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith, ctx};
5
6use crate::error;
7use crate::options::Permissive;
8use crate::pe::{data_directories, debug, optional_header, section_table, symbol};
9use crate::strtab;
10
11#[repr(C)]
37#[derive(Debug, PartialEq, Copy, Clone, Default, Pwrite)]
38#[doc(alias("IMAGE_DOS_HEADER"))]
39pub struct DosHeader {
40 #[doc(alias("e_magic"))]
54 pub signature: u16,
55 #[doc(alias("e_cblp"))]
69 pub bytes_on_last_page: u16,
70 #[doc(alias("e_cp"))]
80 pub pages_in_file: u16,
81 #[doc(alias("e_crlc"))]
107 pub relocations: u16,
108 #[doc(alias("e_cparhdr"))]
123 pub size_of_header_in_paragraphs: u16,
124 #[doc(alias("e_minalloc"))]
139 pub minimum_extra_paragraphs_needed: u16,
140 #[doc(alias("e_maxalloc"))]
154 pub maximum_extra_paragraphs_needed: u16,
155 #[doc(alias("e_ss"))]
178 pub initial_relative_ss: u16,
179 #[doc(alias("e_sp"))]
194 pub initial_sp: u16,
195 #[doc(alias("e_csum"))]
203 pub checksum: u16,
204 #[doc(alias("e_ip"))]
214 pub initial_ip: u16,
215 #[doc(alias("e_cs"))]
225 pub initial_relative_cs: u16,
226 #[doc(alias("e_lfarlc"))]
237 pub file_address_of_relocation_table: u16,
238 #[doc(alias("e_ovno"))]
250 pub overlay_number: u16,
251 #[doc(alias("e_res"))]
259 pub reserved: [u16; 4],
260 #[doc(alias("e_oemid"))]
271 pub oem_id: u16,
272 #[doc(alias("e_oeminfo"))]
276 pub oem_info: u16,
277 #[doc(alias("e_res2"))]
285 pub reserved2: [u16; 10],
286 #[doc(alias("e_lfanew"))]
293 pub pe_pointer: u32,
294}
295
296#[doc(alias("IMAGE_DOS_SIGNATURE"))]
297pub const DOS_MAGIC: u16 = 0x5a4d;
298pub const PE_POINTER_OFFSET: u32 = 0x3c;
299pub const DOS_STUB_OFFSET: u32 = PE_POINTER_OFFSET + (core::mem::size_of::<u32>() as u32);
300
301impl DosHeader {
302 pub fn parse(bytes: &[u8]) -> error::Result<Self> {
303 let mut offset = 0;
304 let signature = bytes.gread_with(&mut offset, scroll::LE).map_err(|_| {
305 error::Error::Malformed(format!("cannot parse DOS signature (offset {:#x})", 0))
306 })?;
307 if signature != DOS_MAGIC {
308 return Err(error::Error::Malformed(format!(
309 "DOS header is malformed (signature {:#x})",
310 signature
311 )));
312 }
313
314 let bytes_on_last_page = bytes.gread_with(&mut offset, scroll::LE)?;
315 let pages_in_file = bytes.gread_with(&mut offset, scroll::LE)?;
316 let relocations = bytes.gread_with(&mut offset, scroll::LE)?;
317 let size_of_header_in_paragraphs = bytes.gread_with(&mut offset, scroll::LE)?;
318 let minimum_extra_paragraphs_needed = bytes.gread_with(&mut offset, scroll::LE)?;
319 let maximum_extra_paragraphs_needed = bytes.gread_with(&mut offset, scroll::LE)?;
320 let initial_relative_ss = bytes.gread_with(&mut offset, scroll::LE)?;
321 let initial_sp = bytes.gread_with(&mut offset, scroll::LE)?;
322 let checksum = bytes.gread_with(&mut offset, scroll::LE)?;
323 let initial_ip = bytes.gread_with(&mut offset, scroll::LE)?;
324 let initial_relative_cs = bytes.gread_with(&mut offset, scroll::LE)?;
325 let file_address_of_relocation_table = bytes.gread_with(&mut offset, scroll::LE)?;
326 let overlay_number = bytes.gread_with(&mut offset, scroll::LE)?;
327 let reserved = bytes.gread_with(&mut offset, scroll::LE)?; let oem_id = bytes.gread_with(&mut offset, scroll::LE)?;
329 let oem_info = bytes.gread_with(&mut offset, scroll::LE)?;
330 let reserved2 = bytes.gread_with(&mut offset, scroll::LE)?; debug_assert!(
333 offset == PE_POINTER_OFFSET as usize,
334 "expected offset ({:#x}) after reading DOS header to be at 0x3C",
335 offset
336 );
337
338 let pe_pointer: u32 = bytes
339 .pread_with(PE_POINTER_OFFSET as usize, scroll::LE)
340 .map_err(|_| {
341 error::Error::Malformed(format!(
342 "cannot parse PE header pointer (offset {:#x})",
343 PE_POINTER_OFFSET
344 ))
345 })?;
346
347 let pe_signature: u32 =
348 bytes
349 .pread_with(pe_pointer as usize, scroll::LE)
350 .map_err(|_| {
351 error::Error::Malformed(format!(
352 "cannot parse PE header signature (offset {:#x})",
353 pe_pointer
354 ))
355 })?;
356 if pe_signature != PE_MAGIC {
357 return Err(error::Error::Malformed(format!(
358 "PE header is malformed (signature {:#x})",
359 pe_signature
360 )));
361 }
362
363 Ok(DosHeader {
364 signature,
365 bytes_on_last_page,
366 pages_in_file,
367 relocations,
368 size_of_header_in_paragraphs,
369 minimum_extra_paragraphs_needed,
370 maximum_extra_paragraphs_needed,
371 initial_relative_ss,
372 initial_sp,
373 checksum,
374 initial_ip,
375 initial_relative_cs,
376 file_address_of_relocation_table,
377 overlay_number,
378 reserved,
379 oem_id,
380 oem_info,
381 reserved2,
382 pe_pointer,
383 })
384 }
385}
386
387#[derive(Debug, PartialEq, Copy, Clone)]
388pub struct DosStub<'a> {
397 pub data: &'a [u8],
398}
399
400impl<'a> Default for DosStub<'a> {
401 #[rustfmt::skip]
420 fn default() -> Self {
421 Self {
422 data: &[
423 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, ],
445 }
446 }
447}
448
449impl<'a> ctx::TryIntoCtx<scroll::Endian> for DosStub<'a> {
450 type Error = error::Error;
451
452 fn try_into_ctx(self, bytes: &mut [u8], _: scroll::Endian) -> Result<usize, Self::Error> {
453 let offset = &mut 0;
454 bytes.gwrite_with(&*self.data, offset, ())?;
455 Ok(*offset)
456 }
457}
458
459impl<'a> DosStub<'a> {
460 pub fn parse(bytes: &'a [u8], pe_pointer: u32) -> error::Result<Self> {
465 let start_offset = DOS_STUB_OFFSET as usize;
466 let end_offset = pe_pointer as usize;
467
468 if end_offset < start_offset {
471 return Err(error::Error::Malformed(format!(
472 "PE pointer ({:#x}) cannot be before the DOS stub start ({:#x})",
473 pe_pointer, start_offset
474 )));
475 }
476
477 if bytes.len() < end_offset {
478 return Err(error::Error::Malformed(format!(
479 "File is too short ({} bytes) to contain the PE header at {:#x}",
480 bytes.len(),
481 end_offset
482 )));
483 }
484
485 let dos_stub_area = &bytes[start_offset..end_offset];
486 Ok(Self {
487 data: dos_stub_area,
488 })
489 }
490}
491
492#[repr(C)]
505#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, IOread, IOwrite, SizeWith)]
506#[doc(alias("IMAGE_FILE_HEADER"))]
507pub struct CoffHeader {
508 #[doc(alias("Machine"))]
549 pub machine: u16,
550 #[doc(alias("NumberOfSections"))]
554 pub number_of_sections: u16,
555 #[doc(alias("TimeDateStamp"))]
559 pub time_date_stamp: u32,
560 #[doc(alias("PointerToSymbolTable"))]
566 pub pointer_to_symbol_table: u32,
567 #[doc(alias("NumberOfSymbols"))]
573 pub number_of_symbol_table: u32,
574 #[doc(alias("SizeOfOptionalHeader"))]
580 pub size_of_optional_header: u16,
581 #[doc(alias("Characteristics"))]
585 pub characteristics: u16,
586}
587
588pub const SIZEOF_COFF_HEADER: usize = 20;
589pub const PE_MAGIC: u32 = 0x0000_4550;
591pub const SIZEOF_PE_MAGIC: usize = 4;
592
593#[doc(alias("IMAGE_FILE_MACHINE_UNKNOWN"))]
613pub const COFF_MACHINE_UNKNOWN: u16 = 0x0;
614
615#[doc(alias("IMAGE_FILE_MACHINE_ALPHA"))]
619pub const COFF_MACHINE_ALPHA: u16 = 0x184;
620
621#[doc(alias("IMAGE_FILE_MACHINE_ALPHA64"))]
625#[doc(alias("IMAGE_FILE_MACHINE_AXP64"))]
626pub const COFF_MACHINE_ALPHA64: u16 = 0x284;
627
628#[doc(alias("IMAGE_FILE_MACHINE_AM33"))]
632pub const COFF_MACHINE_AM33: u16 = 0x1d3;
633
634#[doc(alias("IMAGE_FILE_MACHINE_AMD64"))]
638pub const COFF_MACHINE_X86_64: u16 = 0x8664;
641
642#[doc(alias("IMAGE_FILE_MACHINE_ARM"))]
646pub const COFF_MACHINE_ARM: u16 = 0x1c0;
647
648#[doc(alias("IMAGE_FILE_MACHINE_ARM64"))]
652pub const COFF_MACHINE_ARM64: u16 = 0xaa64;
653
654#[doc(alias("IMAGE_FILE_MACHINE_ARMNT"))]
658pub const COFF_MACHINE_ARMNT: u16 = 0x1c4;
659
660#[doc(alias("IMAGE_FILE_MACHINE_EBC"))]
664pub const COFF_MACHINE_EBC: u16 = 0xebc;
665
666#[doc(alias("IMAGE_FILE_MACHINE_I386"))]
672pub const COFF_MACHINE_X86: u16 = 0x14c;
673
674#[doc(alias("IMAGE_FILE_MACHINE_IA64"))]
678pub const COFF_MACHINE_IA64: u16 = 0x200;
679
680#[doc(alias("IMAGE_FILE_MACHINE_LOONGARCH32"))]
684pub const COFF_MACHINE_LOONGARCH32: u16 = 0x6232;
685
686#[doc(alias("IMAGE_FILE_MACHINE_LOONGARCH64"))]
690pub const COFF_MACHINE_LOONGARCH64: u16 = 0x6264;
691
692#[doc(alias("IMAGE_FILE_MACHINE_M32R"))]
696pub const COFF_MACHINE_M32R: u16 = 0x9041;
697
698#[doc(alias("IMAGE_FILE_MACHINE_MIPS16"))]
702pub const COFF_MACHINE_MIPS16: u16 = 0x266;
703
704#[doc(alias("IMAGE_FILE_MACHINE_MIPSFPU"))]
708pub const COFF_MACHINE_MIPSFPU: u16 = 0x366;
709
710#[doc(alias("IMAGE_FILE_MACHINE_MIPSFPU16"))]
714pub const COFF_MACHINE_MIPSFPU16: u16 = 0x466;
715
716#[doc(alias("IMAGE_FILE_MACHINE_POWERPC"))]
720pub const COFF_MACHINE_POWERPC: u16 = 0x1f0;
721
722#[doc(alias("IMAGE_FILE_MACHINE_POWERPCFP"))]
726pub const COFF_MACHINE_POWERPCFP: u16 = 0x1f1;
727
728#[doc(alias("IMAGE_FILE_MACHINE_R4000"))]
732pub const COFF_MACHINE_R4000: u16 = 0x166;
733
734#[doc(alias("IMAGE_FILE_MACHINE_RISCV32"))]
738pub const COFF_MACHINE_RISCV32: u16 = 0x5032;
739
740#[doc(alias("IMAGE_FILE_MACHINE_RISCV64"))]
744pub const COFF_MACHINE_RISCV64: u16 = 0x5064;
745
746#[doc(alias("IMAGE_FILE_MACHINE_RISCV128"))]
750pub const COFF_MACHINE_RISCV128: u16 = 0x5128;
751
752#[doc(alias("IMAGE_FILE_MACHINE_SH3"))]
756pub const COFF_MACHINE_SH3: u16 = 0x1a2;
757
758#[doc(alias("IMAGE_FILE_MACHINE_SH3DSP"))]
762pub const COFF_MACHINE_SH3DSP: u16 = 0x1a3;
763
764#[doc(alias("IMAGE_FILE_MACHINE_SH4"))]
768pub const COFF_MACHINE_SH4: u16 = 0x1a6;
769
770#[doc(alias("IMAGE_FILE_MACHINE_SH5"))]
774pub const COFF_MACHINE_SH5: u16 = 0x1a8;
775
776#[doc(alias("IMAGE_FILE_MACHINE_THUMB"))]
780pub const COFF_MACHINE_THUMB: u16 = 0x1c2;
781
782#[doc(alias("IMAGE_FILE_MACHINE_WCEMIPSV2"))]
786pub const COFF_MACHINE_WCEMIPSV2: u16 = 0x169;
787
788impl CoffHeader {
789 pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> {
790 Ok(bytes.gread_with(offset, scroll::LE)?)
791 }
792
793 pub fn sections(
798 &self,
799 bytes: &[u8],
800 offset: &mut usize,
801 ) -> error::Result<Vec<section_table::SectionTable>> {
802 self.sections_with_opts(bytes, offset, &crate::pe::options::ParseOptions::default())
803 }
804
805 pub(crate) fn sections_with_opts(
810 &self,
811 bytes: &[u8],
812 offset: &mut usize,
813 opts: &crate::pe::options::ParseOptions,
814 ) -> error::Result<Vec<section_table::SectionTable>> {
815 let nsections = self.number_of_sections as usize;
816
817 if nsections > bytes.len() / 40 {
819 return Err(error::Error::BufferTooShort(nsections, "sections"));
820 }
821
822 let mut sections = Vec::with_capacity(nsections);
823 let string_table_offset = self.pointer_to_symbol_table as usize
825 + symbol::SymbolTable::size(self.number_of_symbol_table as usize);
826 for i in 0..nsections {
827 let section = section_table::SectionTable::parse_with_opts(
828 bytes,
829 offset,
830 string_table_offset as usize,
831 opts,
832 )?;
833 debug!("({}) {:#?}", i, section);
834 sections.push(section);
835 }
836 Ok(sections)
837 }
838
839 pub fn symbols<'a>(&self, bytes: &'a [u8]) -> error::Result<Option<symbol::SymbolTable<'a>>> {
841 let offset = self.pointer_to_symbol_table as usize;
842 let number = self.number_of_symbol_table as usize;
843 if offset == 0 {
844 Ok(None)
845 } else {
846 symbol::SymbolTable::parse(bytes, offset, number).map(Some)
847 }
848 }
849
850 pub fn strings<'a>(&self, bytes: &'a [u8]) -> error::Result<Option<strtab::Strtab<'a>>> {
852 if self.pointer_to_symbol_table == 0 {
855 return Ok(None);
856 }
857
858 let mut offset = self.pointer_to_symbol_table as usize
859 + symbol::SymbolTable::size(self.number_of_symbol_table as usize);
860
861 let length_field_size = core::mem::size_of::<u32>();
862 let length = bytes
863 .pread_with::<u32>(offset, scroll::LE)?
864 .checked_sub(length_field_size as u32)
865 .ok_or(error::Error::Malformed(format!(
866 "COFF length field size ({length_field_size:#x}) is larger than the parsed length value"
867 )))? as usize;
868
869 offset += length_field_size;
871
872 Ok(Some(strtab::Strtab::parse(bytes, offset, length, 0)?))
873 }
874}
875
876#[derive(Debug, PartialEq, Copy, Clone, Default)]
883pub struct Header<'a> {
884 pub dos_header: DosHeader,
885 pub dos_stub: DosStub<'a>,
887 pub rich_header: Option<RichHeader<'a>>,
888
889 pub signature: u32,
891 pub coff_header: CoffHeader,
892 pub optional_header: Option<optional_header::OptionalHeader>,
893}
894
895impl<'a> Header<'a> {
896 fn parse_impl(
897 bytes: &'a [u8],
898 dos_header: DosHeader,
899 dos_stub: DosStub<'a>,
900 parse_rich_header: bool,
901 opts: &crate::pe::options::ParseOptions,
902 ) -> error::Result<Self> {
903 let rich_header = if parse_rich_header {
904 RichHeader::parse_with_opts(&bytes, opts)?
905 } else {
906 None
907 };
908 let mut offset = dos_header.pe_pointer as usize;
909 let signature = bytes
910 .gread_with::<u32>(&mut offset, scroll::LE)
911 .map_err(|_| {
912 error::Error::Malformed(format!("cannot parse PE signature (offset {:#x})", offset))
913 })?;
914 let coff_header = CoffHeader::parse(&bytes, &mut offset)?;
915 let optional_header = if coff_header.size_of_optional_header > 0 {
916 Some(bytes.pread::<optional_header::OptionalHeader>(offset)?)
917 } else {
918 None
919 };
920
921 Ok(Header {
922 dos_header,
923 dos_stub,
924 rich_header,
925 signature,
926 coff_header,
927 optional_header,
928 })
929 }
930
931 pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
933 Self::parse_with_opts(bytes, &crate::pe::options::ParseOptions::default())
934 }
935
936 pub(crate) fn parse_with_opts(
938 bytes: &'a [u8],
939 opts: &crate::pe::options::ParseOptions,
940 ) -> error::Result<Self> {
941 let dos_header = DosHeader::parse(&bytes)?;
942 let dos_stub = DosStub::parse(bytes, dos_header.pe_pointer)
943 .or_permissive_and_default(opts.parse_mode.is_permissive(), "DOS stub parse failed")?;
944
945 Header::parse_impl(bytes, dos_header, dos_stub, true, opts)
946 }
947
948 pub fn parse_without_dos(bytes: &'a [u8]) -> error::Result<Self> {
950 let dos_header = DosHeader::default();
951 Header::parse_impl(
952 bytes,
953 dos_header,
954 DosStub::default(),
955 false,
956 &crate::pe::options::ParseOptions::default(),
957 )
958 }
959}
960
961impl<'a> ctx::TryIntoCtx<scroll::Endian> for Header<'a> {
962 type Error = error::Error;
963
964 fn try_into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) -> Result<usize, Self::Error> {
965 let offset = &mut 0;
966 bytes.gwrite_with(self.dos_header, offset, ctx)?;
967 bytes.gwrite_with(self.dos_stub, offset, ctx)?;
968 bytes.gwrite_with(self.signature, offset, scroll::LE)?;
969 bytes.gwrite_with(self.coff_header, offset, ctx)?;
970 if let Some(opt_header) = self.optional_header {
971 bytes.gwrite_with(opt_header, offset, ctx)?;
972 }
973 Ok(*offset)
974 }
975}
976
977pub const DANS_MARKER: u32 = 0x536E6144;
979pub const DANS_MARKER_SIZE: usize = core::mem::size_of::<u32>();
981pub const RICH_MARKER: u32 = 0x68636952;
983pub const RICH_MARKER_SIZE: usize = core::mem::size_of::<u32>();
985
986#[derive(Debug, PartialEq, Copy, Clone, Default)]
990pub struct RichHeader<'a> {
991 pub key: u32,
993 pub data: &'a [u8],
995 pub padding_size: usize,
997 pub start_offset: u32,
999 pub end_offset: u32,
1001}
1002
1003#[repr(C)]
1005#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite)]
1006pub struct RichMetadata {
1007 pub build: u16,
1009 pub product: u16,
1011 pub use_count: u32,
1013}
1014
1015impl RichMetadata {
1016 fn parse(bytes: &[u8], key: u32) -> error::Result<Self> {
1018 let mut offset = 0;
1019 let build_and_product = bytes.gread_with::<u32>(&mut offset, scroll::LE)? ^ key;
1020 let build = (build_and_product & 0xFFFF) as u16;
1021 let product = (build_and_product >> 16) as u16;
1022 let use_count = bytes.gread_with::<u32>(&mut offset, scroll::LE)? ^ key;
1023 Ok(Self {
1024 build,
1025 product,
1026 use_count,
1027 })
1028 }
1029}
1030
1031const RICH_METADATA_SIZE: usize = 8;
1033
1034#[derive(Debug)]
1036pub struct RichMetadataIterator<'a> {
1037 key: u32,
1039 data: &'a [u8],
1041}
1042
1043impl Iterator for RichMetadataIterator<'_> {
1044 type Item = error::Result<RichMetadata>;
1045
1046 fn next(&mut self) -> Option<Self::Item> {
1047 if self.data.is_empty() {
1048 return None;
1049 }
1050
1051 Some(match RichMetadata::parse(&self.data, self.key) {
1053 Ok(metadata) => {
1054 self.data = &self.data[RICH_METADATA_SIZE..];
1055 Ok(metadata)
1056 }
1057 Err(error) => {
1058 self.data = &[];
1059 Err(error.into())
1060 }
1061 })
1062 }
1063
1064 fn size_hint(&self) -> (usize, Option<usize>) {
1065 let len = self.data.len() / RICH_METADATA_SIZE;
1066 (len, Some(len))
1067 }
1068}
1069
1070impl FusedIterator for RichMetadataIterator<'_> {}
1071
1072impl ExactSizeIterator for RichMetadataIterator<'_> {}
1073
1074impl<'a> RichHeader<'a> {
1075 pub fn parse(bytes: &'a [u8]) -> error::Result<Option<Self>> {
1088 Self::parse_with_opts(bytes, &crate::pe::options::ParseOptions::default())
1089 }
1090
1091 pub(crate) fn parse_with_opts(
1092 bytes: &'a [u8],
1093 opts: &crate::pe::options::ParseOptions,
1094 ) -> error::Result<Option<Self>> {
1095 let dos_header = DosHeader::parse(bytes)?;
1097 let dos_header_end_offset = PE_POINTER_OFFSET as usize;
1098 let pe_header_start_offset = dos_header.pe_pointer as usize;
1099
1100 if pe_header_start_offset <= dos_header_end_offset
1102 || (pe_header_start_offset - dos_header_end_offset) < 8
1103 {
1104 return Ok(None);
1105 }
1106
1107 let scan_start = dos_header_end_offset + 4;
1109 let scan_end = pe_header_start_offset;
1110 if scan_start > scan_end {
1111 return Err(error::Error::Malformed(format!(
1112 "Rich header scan start ({:#X}) is greater than scan end ({:#X})",
1113 scan_start, scan_end
1114 )))
1115 .or_permissive_and_value(
1116 opts.parse_mode.is_permissive(),
1117 "Packed binaries may have PE pointer before DOS header end",
1118 None,
1119 );
1120 }
1121 let scan_stub = &bytes[scan_start..scan_end];
1122
1123 let (rich_end_offset, key) = match scan_stub
1125 .windows(8)
1126 .enumerate()
1127 .filter_map(
1128 |(index, window)| match window.pread_with::<u32>(0, scroll::LE) {
1129 Ok(marker) if marker == RICH_MARKER => Some(Ok(index)),
1131 Err(e) => Some(Err(error::Error::from(e))),
1133 _ => None,
1135 },
1136 )
1137 .next()
1139 {
1140 Some(Ok(rich_end_offset)) => {
1141 let rich_key =
1142 scan_stub.pread_with::<u32>(rich_end_offset + RICH_MARKER_SIZE, scroll::LE)?;
1143 (rich_end_offset, rich_key)
1144 }
1145 Some(Err(e)) => return Err(e),
1147 None => return Ok(None),
1149 };
1150
1151 if rich_end_offset >= scan_stub.len() {
1153 return Err(error::Error::Malformed(format!(
1154 "Rich end offset ({:#X}) exceeds scan stub length ({:#X})",
1155 rich_end_offset,
1156 scan_stub.len()
1157 )));
1158 }
1159 let rich_header = &scan_stub[..rich_end_offset];
1161
1162 let rich_start_offset = match scan_stub
1164 .windows(4)
1165 .enumerate()
1166 .filter_map(
1167 |(index, window)| match window.pread_with::<u32>(0, scroll::LE) {
1168 Ok(value) if (value ^ key) == DANS_MARKER => Some(Ok(index + DANS_MARKER_SIZE)),
1170 Err(e) => Some(Err(error::Error::from(e))),
1172 _ => None,
1174 },
1175 )
1176 .next()
1178 {
1179 Some(Ok(offset)) => offset,
1181 Some(Err(e)) => return Err(e),
1183 None => {
1185 return Err(error::Error::Malformed(format!(
1186 "Rich header does not contain the DanS marker"
1187 )));
1188 }
1189 };
1190
1191 if rich_start_offset >= rich_header.len() {
1193 return Err(error::Error::Malformed(format!(
1194 "Rich start offset ({:#X}) exceeds rich header length ({:#X})",
1195 rich_start_offset,
1196 rich_header.len()
1197 )));
1198 }
1199 let rich_header = &rich_header[rich_start_offset..];
1201
1202 let padding_size = rich_header
1204 .chunks(4)
1205 .map(|chunk| chunk.pread_with::<u32>(0, scroll::LE))
1206 .collect::<Result<Vec<_>, _>>()?
1207 .into_iter()
1208 .take_while(|value| value == &key)
1209 .count()
1210 * core::mem::size_of_val(&key);
1211
1212 let data = rich_header;
1214
1215 let start_offset = scan_start as u32 + rich_start_offset as u32 - DANS_MARKER_SIZE as u32;
1217 let end_offset = scan_start as u32 + rich_end_offset as u32;
1218
1219 Ok(Some(RichHeader {
1220 key,
1221 data,
1222 padding_size,
1223 start_offset,
1224 end_offset,
1225 }))
1226 }
1227
1228 pub fn metadatas(&self) -> RichMetadataIterator<'a> {
1230 RichMetadataIterator {
1231 key: self.key,
1232 data: &self.data[self.padding_size..],
1233 }
1234 }
1235}
1236
1237#[cfg(feature = "te")]
1243#[repr(C)]
1244#[derive(Debug, Default, PartialEq, Copy, Clone, Pread, Pwrite)]
1245pub struct TeHeader {
1246 pub signature: u16,
1248 pub machine: u16,
1250 pub number_of_sections: u8,
1252 pub subsystem: u8,
1254 pub stripped_size: u16,
1257 pub entry_point: u32,
1259 pub base_of_code: u32,
1261 pub image_base: u64,
1263 pub reloc_dir: data_directories::DataDirectory,
1265 pub debug_dir: data_directories::DataDirectory,
1267}
1268
1269#[cfg(feature = "te")]
1270#[doc(alias("IMAGE_TE_SIGNATURE"))]
1271pub const TE_MAGIC: u16 = 0x5a56;
1272
1273#[cfg(feature = "te")]
1274impl TeHeader {
1275 pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> {
1277 const HEADER_SIZE: usize = core::mem::size_of::<TeHeader>();
1278 let mut header: TeHeader = bytes.gread_with(offset, scroll::LE)?;
1279 let stripped_size = header.stripped_size as u32;
1280 let adj_offset = stripped_size
1281 .checked_sub(HEADER_SIZE as u32)
1282 .ok_or_else(|| {
1283 error::Error::Malformed(format!(
1284 "Stripped size ({stripped_size:#x}) is smaller than TE header size ({HEADER_SIZE:#x})",
1285 ))
1286 })?;
1287 header.fixup_header(adj_offset);
1288 Ok(header)
1289 }
1290
1291 pub fn sections(
1293 &self,
1294 bytes: &[u8],
1295 offset: &mut usize,
1296 ) -> error::Result<Vec<section_table::SectionTable>> {
1297 let adj_offset = self.stripped_size as u32 - core::mem::size_of::<TeHeader>() as u32;
1298 let nsections = self.number_of_sections as usize;
1299
1300 if nsections > bytes.len() / 40 {
1302 return Err(error::Error::BufferTooShort(nsections, "sections"));
1303 }
1304
1305 let mut sections = Vec::with_capacity(nsections);
1306 for i in 0..nsections {
1307 let mut section = section_table::SectionTable::parse(bytes, offset, 0)?;
1308 TeHeader::fixup_section(&mut section, adj_offset);
1309 debug!("({}) {:#?}", i, section);
1310 sections.push(section);
1311 }
1312 Ok(sections)
1313 }
1314
1315 fn fixup_header(&mut self, adj_offset: u32) {
1317 debug!(
1318 "Entry point fixed up from: 0x{:x} to 0x{:X}",
1319 self.entry_point,
1320 self.entry_point.wrapping_sub(adj_offset)
1321 );
1322 self.entry_point = self.entry_point.wrapping_sub(adj_offset);
1323
1324 debug!(
1325 "Base of code fixed up from: 0x{:x} to 0x{:X}",
1326 self.base_of_code,
1327 self.base_of_code.wrapping_sub(adj_offset)
1328 );
1329 self.base_of_code = self.base_of_code.wrapping_sub(adj_offset);
1330
1331 debug!(
1332 "Relocation Directory fixed up from: 0x{:x} to 0x{:X}",
1333 self.reloc_dir.virtual_address,
1334 self.reloc_dir.virtual_address.wrapping_sub(adj_offset)
1335 );
1336 self.reloc_dir.virtual_address = self.reloc_dir.virtual_address.wrapping_sub(adj_offset);
1337
1338 debug!(
1339 "Debug Directory fixed up from: 0x{:x} to 0x{:X}",
1340 self.debug_dir.virtual_address,
1341 self.debug_dir.virtual_address.wrapping_sub(adj_offset)
1342 );
1343 self.debug_dir.virtual_address = self.debug_dir.virtual_address.wrapping_sub(adj_offset);
1344 }
1345
1346 fn fixup_section(section: &mut section_table::SectionTable, adj_offset: u32) {
1348 debug!(
1349 "Section virtual address fixed up from: 0x{:X} to 0x{:X}",
1350 section.virtual_address,
1351 section.virtual_address.wrapping_sub(adj_offset)
1352 );
1353 section.virtual_address = section.virtual_address.wrapping_sub(adj_offset);
1354
1355 if section.pointer_to_linenumbers > 0 {
1356 debug!(
1357 "Section pointer to line numbers fixed up from: 0x{:X} to 0x{:X}",
1358 section.pointer_to_linenumbers,
1359 section.pointer_to_linenumbers.wrapping_sub(adj_offset)
1360 );
1361 section.pointer_to_linenumbers =
1362 section.pointer_to_linenumbers.wrapping_sub(adj_offset);
1363 }
1364
1365 if section.pointer_to_raw_data > 0 {
1366 debug!(
1367 "Section pointer to raw data fixed up from: 0x{:X} to 0x{:X}",
1368 section.pointer_to_raw_data,
1369 section.pointer_to_raw_data.wrapping_sub(adj_offset)
1370 );
1371 section.pointer_to_raw_data = section.pointer_to_raw_data.wrapping_sub(adj_offset);
1372 }
1373
1374 if section.pointer_to_relocations > 0 {
1375 debug!(
1376 "Section pointer to relocations fixed up from: 0x{:X} to 0x{:X}",
1377 section.pointer_to_relocations,
1378 section.pointer_to_relocations.wrapping_sub(adj_offset)
1379 );
1380 section.pointer_to_relocations =
1381 section.pointer_to_relocations.wrapping_sub(adj_offset);
1382 }
1383 }
1384}
1385
1386pub fn machine_to_str(machine: u16) -> &'static str {
1389 match machine {
1391 COFF_MACHINE_UNKNOWN => "UNKNOWN",
1392 COFF_MACHINE_ALPHA => "ALPHA",
1393 COFF_MACHINE_ALPHA64 => "ALPHA64",
1394 COFF_MACHINE_AM33 => "AM33",
1395 COFF_MACHINE_X86_64 => "X86_64",
1397 COFF_MACHINE_ARM => "ARM",
1398 COFF_MACHINE_ARM64 => "ARM64",
1399 COFF_MACHINE_ARMNT => "ARM_NT",
1400 COFF_MACHINE_EBC => "EBC",
1401 COFF_MACHINE_X86 => "X86",
1403 COFF_MACHINE_IA64 => "IA64",
1404 COFF_MACHINE_LOONGARCH32 => "LOONGARCH32",
1405 COFF_MACHINE_LOONGARCH64 => "LOONGARCH64",
1406 COFF_MACHINE_M32R => "M32R",
1407 COFF_MACHINE_MIPS16 => "MIPS_16",
1408 COFF_MACHINE_MIPSFPU => "MIPS_FPU",
1409 COFF_MACHINE_MIPSFPU16 => "MIPS_FPU_16",
1410 COFF_MACHINE_POWERPC => "POWERPC",
1411 COFF_MACHINE_POWERPCFP => "POWERCFP",
1412 COFF_MACHINE_R4000 => "R4000",
1413 COFF_MACHINE_RISCV32 => "RISC-V_32",
1414 COFF_MACHINE_RISCV64 => "RISC-V_64",
1415 COFF_MACHINE_RISCV128 => "RISC-V_128",
1416 COFF_MACHINE_SH3 => "SH3",
1417 COFF_MACHINE_SH3DSP => "SH3DSP",
1418 COFF_MACHINE_SH4 => "SH4",
1419 COFF_MACHINE_SH5 => "SH5",
1420 COFF_MACHINE_THUMB => "THUMB",
1421 COFF_MACHINE_WCEMIPSV2 => "WCE_MIPS_V2",
1422 _ => "COFF_UNKNOWN",
1423 }
1424}
1425
1426#[cfg(test)]
1427mod tests {
1428 use super::*;
1429 use crate::{error, pe::Coff};
1430
1431 const CRSS_HEADER: [u8; 688] = [
1432 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
1433 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1434 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1435 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1436 0xd0, 0x00, 0x00, 0x00, 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01,
1437 0x4c, 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d,
1438 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20,
1439 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
1440 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x4a, 0xc3, 0xeb, 0xee, 0x2b, 0xad,
1441 0xb8, 0xee, 0x2b, 0xad, 0xb8, 0xee, 0x2b, 0xad, 0xb8, 0xee, 0x2b, 0xac, 0xb8, 0xfe, 0x2b,
1442 0xad, 0xb8, 0x33, 0xd4, 0x66, 0xb8, 0xeb, 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x63, 0xb8, 0xea,
1443 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x7a, 0xb8, 0xed, 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x64, 0xb8,
1444 0xef, 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x61, 0xb8, 0xef, 0x2b, 0xad, 0xb8, 0x52, 0x69, 0x63,
1445 0x68, 0xee, 0x2b, 0xad, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x45,
1446 0x00, 0x00, 0x4c, 0x01, 0x05, 0x00, 0xd9, 0x8f, 0x15, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00,
1447 0x00, 0x00, 0x00, 0xe0, 0x00, 0x02, 0x01, 0x0b, 0x01, 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
1448 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00,
1449 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02,
1450 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00,
1451 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xe4, 0xab, 0x00, 0x00,
1452 0x01, 0x00, 0x40, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x10,
1453 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
1454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
1455 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1456 0x00, 0x1a, 0x00, 0x00, 0xb8, 0x22, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x38, 0x00, 0x00,
1457 0x00, 0x10, 0x10, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1459 0x00, 0x00, 0x00, 0x68, 0x10, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1460 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1462 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x24,
1463 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
1464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
1465 0x60, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x00, 0x20,
1466 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xc0, 0x2e, 0x69, 0x64, 0x61,
1468 0x74, 0x61, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00,
1469 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1470 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x2e, 0x72, 0x73, 0x72, 0x63, 0x00, 0x00, 0x00, 0x00,
1471 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
1472 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
1473 0x42, 0x2e, 0x72, 0x65, 0x6c, 0x6f, 0x63, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x50,
1474 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1475 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00,
1476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1477 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1478 ];
1479
1480 const NO_RICH_HEADER: [u8; 262] = [
1481 0x4D, 0x5A, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0x00,
1482 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x1A, 0x00, 0x00, 0x00,
1483 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1484 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1485 0x00, 0x01, 0x00, 0x00, 0xBA, 0x10, 0x00, 0x0E, 0x1F, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1486 0x4C, 0xCD, 0x21, 0x90, 0x90, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72,
1487 0x61, 0x6D, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1488 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x57, 0x69, 0x6E, 0x33, 0x32, 0x0D, 0x0A, 0x24, 0x37,
1489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1492 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1493 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1494 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1495 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1496 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1497 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1498 0x00, 0x50, 0x45, 0x00, 0x00, 0x64, 0x86,
1499 ];
1500
1501 const NO_RICH_HEADER_INVALID_PE_POINTER: [u8; 304] = [
1502 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
1503 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1505 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1506 0x3C, 0xFF, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1507 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D,
1508 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1509 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
1510 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0xC7, 0xEA, 0x07, 0xC9, 0xA6, 0x84,
1511 0x54, 0xC9, 0xA6, 0x84, 0x54, 0xC9, 0xA6, 0x84, 0x54, 0x10, 0xD2, 0x81, 0x55, 0xCB, 0xA6,
1512 0x84, 0x54, 0xC0, 0xDE, 0x17, 0x54, 0xC1, 0xA6, 0x84, 0x54, 0xDD, 0xCD, 0x80, 0x55, 0xC7,
1513 0xA6, 0x84, 0x54, 0xDD, 0xCD, 0x87, 0x55, 0xC1, 0xA6, 0x84, 0x54, 0xDD, 0xCD, 0x81, 0x55,
1514 0x7E, 0xA6, 0x84, 0x54, 0xB9, 0x27, 0x85, 0x55, 0xCA, 0xA6, 0x84, 0x54, 0xC9, 0xA6, 0x85,
1515 0x54, 0x08, 0xA6, 0x84, 0x54, 0xA5, 0xD2, 0x81, 0x55, 0xE8, 0xA6, 0x84, 0x54, 0xA5, 0xD2,
1516 0x80, 0x55, 0xD9, 0xA6, 0x84, 0x54, 0xA5, 0xD2, 0x87, 0x55, 0xC0, 0xA6, 0x84, 0x54, 0x10,
1517 0xD2, 0x80, 0x55, 0x49, 0xA6, 0x84, 0x54, 0x10, 0xD2, 0x84, 0x55, 0xC8, 0xA6, 0x84, 0x54,
1518 0x10, 0xD2, 0x7B, 0x54, 0xC8, 0xA6, 0x84, 0x54, 0x10, 0xD2, 0x86, 0x55, 0xC8, 0xA6, 0x84,
1519 0x54, 0x52, 0x69, 0x63, 0x68, 0xC9, 0xA6, 0x84, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1520 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1521 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x64, 0x86, 0x07, 0x00, 0xEC, 0xA5, 0x5B, 0x66,
1522 0x00, 0x00, 0x00, 0x00,
1523 ];
1524
1525 const CORRECT_RICH_HEADER: [u8; 256] = [
1526 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
1527 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1528 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1530 0xF8, 0x00, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1531 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D,
1532 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1533 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
1534 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x4C, 0x5B, 0xB1, 0x37, 0x2D, 0x35,
1535 0xE2, 0x37, 0x2D, 0x35, 0xE2, 0x37, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x31, 0xE3, 0x3D, 0x2D,
1536 0x35, 0xE2, 0x44, 0x4F, 0x36, 0xE3, 0x32, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x30, 0xE3, 0x48,
1537 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x36, 0xE3, 0x3E, 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x30, 0xE3,
1538 0x14, 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x31, 0xE3, 0x25, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x34,
1539 0xE3, 0x3C, 0x2D, 0x35, 0xE2, 0x37, 0x2D, 0x34, 0xE2, 0xAF, 0x2D, 0x35, 0xE2, 0x37, 0x2D,
1540 0x35, 0xE2, 0x23, 0x2D, 0x35, 0xE2, 0xFC, 0x4E, 0x37, 0xE3, 0x36, 0x2D, 0x35, 0xE2, 0x52,
1541 0x69, 0x63, 0x68, 0x37, 0x2D, 0x35, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1542 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x64, 0x86, 0x05,
1543 0x00,
1544 ];
1545
1546 const CORRUPTED_RICH_HEADER: [u8; 256] = [
1547 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
1548 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 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 0xF8, 0x00, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1552 0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D,
1553 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1554 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
1555 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x4C, 0x5B, 0xB1, 0x37, 0x2D, 0x35,
1556 0xE2, 0x37, 0x2D, 0x35, 0xE2, 0x37, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x31, 0xE3, 0x3D, 0x2D,
1557 0x35, 0xE2, 0x44, 0x4F, 0x36, 0xE3, 0x32, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x30, 0xE3, 0x48,
1558 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x36, 0xE3, 0x3E, 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x30, 0xE3,
1559 0x14, 0x2D, 0x35, 0xE2, 0xEE, 0x4F, 0x31, 0xE3, 0x25, 0x2D, 0x35, 0xE2, 0x44, 0x4F, 0x34,
1560 0xE3, 0x3C, 0x2D, 0x35, 0xE2, 0x37, 0x2D, 0x34, 0xE2, 0xAF, 0x2D, 0x35, 0xE2, 0x37, 0x2D,
1561 0x35, 0xE2, 0x23, 0x2D, 0x35, 0xE2, 0xFC, 0x4E, 0x37, 0xE3, 0x36, 0x2D, 0x35, 0xE2, 0x52,
1562 0x69, 0x63, 0x68, 0x37, 0x2D, 0x35, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x64, 0x86, 0x05,
1564 0x00,
1565 ];
1566
1567 const HEADER_WITH_OMITTED_DOS_STUB: [u8; 512] = [
1568 0x4d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
1570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1572 0x40, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x4c, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1574 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x02, 0x01, 0x0b, 0x01, 0x0e, 0x00, 0x00, 0xe0,
1575 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x00, 0x90, 0xab, 0x04, 0x00, 0x00,
1576 0xd0, 0x02, 0x00, 0x00, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00,
1577 0x00, 0x02, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01,
1578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
1579 0x00, 0x00, 0x02, 0x00, 0x40, 0x89, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1580 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1581 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xcb, 0x04, 0x00, 0x94, 0x01, 0x00,
1582 0x00, 0x00, 0xb0, 0x04, 0x00, 0x64, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc, 0x04, 0x00, 0x10,
1584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1586 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xad, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00,
1587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x50, 0x58, 0x30, 0x00, 0x00, 0x00,
1590 0x00, 0x00, 0xc0, 0x02, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
1591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1592 0x00, 0x00, 0xe0, 0x55, 0x50, 0x58, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00,
1593 0x00, 0xd0, 0x02, 0x00, 0x00, 0xde, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
1594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xe0, 0x2e, 0x72,
1595 0x73, 0x72, 0x63, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xb0, 0x04, 0x00, 0x00,
1596 0x1e, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1597 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x2e, 0x39, 0x35, 0x00, 0x55, 0x50, 0x58, 0x21,
1601 0x0d, 0x09, 0x08, 0x08, 0x25, 0x1d, 0xab, 0x52, 0xef, 0x64, 0xdc, 0xe5, 0x52, 0x8d, 0x04,
1602 0x00, 0x90, 0xdb, 0x01, 0x00, 0x38, 0x42, 0x04, 0x00, 0x26, 0x19, 0x00, 0xa8,
1603 ];
1604
1605 const BORLAND_PE32_VALID_NO_RICH_HEADER: [u8; 528] = [
1606 0x4D, 0x5A, 0x50, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0x00,
1607 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x1A, 0x00, 0x00, 0x00,
1608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1610 0x00, 0x02, 0x00, 0x00, 0xBA, 0x10, 0x00, 0x0E, 0x1F, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
1611 0x4C, 0xCD, 0x21, 0x90, 0x90, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72,
1612 0x61, 0x6D, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
1613 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x57, 0x69, 0x6E, 0x33, 0x32, 0x0D, 0x0A, 0x24, 0x37,
1614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1620 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1624 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1627 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1629 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1632 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1633 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1635 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1636 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1638 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1640 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x08, 0x00, 0xC0, 0x9C, 0x07, 0x67, 0x00, 0x00, 0x00,
1642 0x00,
1643 ];
1644
1645 const INVALID_COFF_OBJECT: [u8; 20] = [
1649 0x4C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1650 0x00, 0x0F, 0x00, 0xFF, 0x80,
1651 ];
1652
1653 const MALFORMED_SMALL_TE: [u8; 58] = [
1657 0x56, 0x5A, 0x52, 0x5A, 0x50, 0x00, 0x17, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00,
1658 0x10, 0x86, 0x02, 0x0C, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x1B, 0x01, 0x01, 0x00, 0x00,
1659 0xFF, 0xB5, 0x00, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0xFF, 0xB5, 0x00, 0x00, 0x00, 0x04,
1660 0x34, 0x15, 0x40, 0x13, 0x41, 0x0E, 0x10, 0x15, 0x40, 0x13, 0x41, 0x0E, 0x10,
1661 ];
1662
1663 const WELL_FORMED_WITH_RICH_HEADER: &[u8] =
1664 include_bytes!("../../tests/bins/pe/well_formed_import.exe.bin");
1665
1666 #[test]
1667 fn crss_header() {
1668 let header = Header::parse(&&CRSS_HEADER[..]).unwrap();
1669 assert!(header.dos_header.signature == DOS_MAGIC);
1670 assert!(header.signature == PE_MAGIC);
1671 assert!(header.coff_header.machine == COFF_MACHINE_X86);
1672 assert!(machine_to_str(header.coff_header.machine) == "X86");
1673 println!("header: {:?}", &header);
1674 }
1675
1676 #[test]
1677 fn parse_without_dos_rich() {
1678 let dos_header = DosHeader::parse(&WELL_FORMED_WITH_RICH_HEADER).unwrap();
1680 let buf = &WELL_FORMED_WITH_RICH_HEADER[dos_header.pe_pointer as usize..];
1682 let header = Header::parse_without_dos(buf).unwrap();
1683
1684 assert_eq!(header.coff_header.number_of_sections, 6);
1685 assert_eq!(header.rich_header, None);
1686 assert_eq!(header.dos_header, DosHeader::default());
1687 }
1688
1689 #[test]
1690 fn parse_borland_weird_dos_stub() {
1691 let dos_stub = DosStub::parse(&BORLAND_PE32_VALID_NO_RICH_HEADER, 0x200).unwrap();
1692 assert_ne!(dos_stub.data, BORLAND_PE32_VALID_NO_RICH_HEADER.to_vec());
1693 }
1694
1695 #[test]
1696 fn parse_borland_no_rich_header() {
1697 let header = RichHeader::parse(&BORLAND_PE32_VALID_NO_RICH_HEADER).unwrap();
1698 assert_eq!(header, None);
1699 }
1700
1701 #[test]
1702 fn parse_no_rich_header() {
1703 let header = RichHeader::parse(&NO_RICH_HEADER).unwrap();
1704 assert_eq!(header, None);
1705 }
1706
1707 #[test]
1708 fn parse_no_rich_header_invalid_pe_pointer() {
1709 let header = RichHeader::parse(&NO_RICH_HEADER_INVALID_PE_POINTER);
1710 assert_eq!(header.is_err(), true);
1711 if let Err(error::Error::Malformed(msg)) = header {
1712 assert_eq!(msg, "cannot parse PE header signature (offset 0xff3c)");
1713 } else {
1714 panic!("Expected a Malformed error but got {:?}", header);
1715 }
1716 }
1717
1718 #[test]
1719 fn parse_correct_rich_header() {
1720 let header = RichHeader::parse(&CORRECT_RICH_HEADER).unwrap();
1721 assert_ne!(header, None);
1722 let header = header.unwrap();
1723 let expected = vec![
1724 RichMetadata {
1725 build: 25203,
1726 product: 260,
1727 use_count: 10,
1728 },
1729 RichMetadata {
1730 build: 25203,
1731 product: 259,
1732 use_count: 5,
1733 },
1734 RichMetadata {
1735 build: 25203,
1736 product: 261,
1737 use_count: 127,
1738 },
1739 RichMetadata {
1740 build: 25305,
1741 product: 259,
1742 use_count: 9,
1743 },
1744 RichMetadata {
1745 build: 25305,
1746 product: 261,
1747 use_count: 35,
1748 },
1749 RichMetadata {
1750 build: 25305,
1751 product: 260,
1752 use_count: 18,
1753 },
1754 RichMetadata {
1755 build: 25203,
1756 product: 257,
1757 use_count: 11,
1758 },
1759 RichMetadata {
1760 build: 0,
1761 product: 1,
1762 use_count: 152,
1763 },
1764 RichMetadata {
1765 build: 0,
1766 product: 0,
1767 use_count: 20,
1768 },
1769 RichMetadata {
1770 build: 25547,
1771 product: 258,
1772 use_count: 1,
1773 },
1774 ];
1775 assert_eq!(
1776 header
1777 .metadatas()
1778 .filter_map(Result::ok)
1779 .collect::<Vec<RichMetadata>>(),
1780 expected
1781 );
1782 }
1783
1784 #[test]
1785 fn parse_corrupted_rich_header() {
1786 let header_result = RichHeader::parse(&CORRUPTED_RICH_HEADER);
1787 assert_eq!(header_result.is_err(), true);
1788 }
1789
1790 #[test]
1791 fn parse_malformed_small_te() {
1792 let mut offset = 0;
1793 let header = TeHeader::parse(&MALFORMED_SMALL_TE, &mut offset);
1794 assert_eq!(header.is_err(), true);
1795 if let Err(error::Error::Malformed(msg)) = header {
1796 assert_eq!(
1797 msg,
1798 "Stripped size (0x17) is smaller than TE header size (0x28)"
1799 );
1800 } else {
1801 panic!("Expected a Malformed error but got {:?}", header);
1802 }
1803 }
1804
1805 #[test]
1806 fn parse_invalid_small_coff() {
1807 let header = Coff::parse(&INVALID_COFF_OBJECT);
1808 assert_eq!(header.is_err(), true);
1809 if let Err(error::Error::Malformed(msg)) = header {
1810 assert_eq!(
1811 msg,
1812 "COFF length field size (0x4) is larger than the parsed length value"
1813 );
1814 } else {
1815 panic!("Expected a Malformed error but got {:?}", header);
1816 }
1817 }
1818
1819 #[test]
1820 fn parse_with_omitted_dos_stub() {
1821 let header = Header::parse(&HEADER_WITH_OMITTED_DOS_STUB).unwrap();
1822
1823 assert_eq!(header.dos_header.pe_pointer, 0x40);
1824 assert_eq!(header.coff_header.number_of_sections, 3);
1825 }
1826
1827 static EMPTY_STRING_TABLE_OBJ: [u8; 424] = [
1829 0x64, 0x86, 0x03, 0x00, 0xf3, 0xcb, 0x20, 0x69, 0x02, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00,
1830 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x24, 0x6d, 0x6e, 0x00, 0x00,
1831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00,
1832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x60,
1833 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1835 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50, 0xc0, 0x2e, 0x64, 0x65, 0x62, 0x75,
1836 0x67, 0x24, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
1837 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1838 0x00, 0x40, 0x00, 0x10, 0x42, 0xc3, 0x04, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x68,
1839 0x00, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x11, 0x00, 0x00, 0x00, 0x00, 0x43, 0x3a, 0x5c, 0x55,
1840 0x73, 0x65, 0x72, 0x73, 0x5c, 0x43, 0x6f, 0x6e, 0x74, 0x6f, 0x73, 0x6f, 0x5c, 0x77, 0x69,
1841 0x6e, 0x2d, 0x6b, 0x65, 0x78, 0x70, 0x5c, 0x61, 0x63, 0x6c, 0x5f, 0x65, 0x64, 0x69, 0x74,
1842 0x2e, 0x6f, 0x62, 0x6a, 0x00, 0x37, 0x00, 0x3c, 0x11, 0x03, 0x02, 0x00, 0x00, 0xd0, 0x00,
1843 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x2a, 0x00, 0x84, 0x86, 0x00,
1844 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x28, 0x52, 0x29, 0x20,
1845 0x4d, 0x61, 0x63, 0x72, 0x6f, 0x20, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72,
1846 0x00, 0x00, 0x00, 0x40, 0x63, 0x6f, 0x6d, 0x70, 0x2e, 0x69, 0x64, 0x84, 0x86, 0x03, 0x01,
1847 0xff, 0xff, 0x00, 0x00, 0x03, 0x00, 0x40, 0x66, 0x65, 0x61, 0x74, 0x2e, 0x30, 0x30, 0x10,
1848 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x03, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x24,
1849 0x6d, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00,
1850 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1851 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
1852 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x24, 0x53, 0x00,
1854 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x01, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00,
1855 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x6d, 0x70,
1856 0x74, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00,
1857 0x04, 0x00, 0x00, 0x00,
1858 ];
1859
1860 #[test]
1861 fn parse_coff_with_empty_string_table() {
1862 let coff = Coff::parse(&EMPTY_STRING_TABLE_OBJ).unwrap();
1865
1866 assert_eq!(coff.header.number_of_sections, 3);
1868 assert_eq!(coff.header.number_of_symbol_table, 9);
1869 assert!(coff.strings.is_some());
1870
1871 let strings = coff.strings.unwrap();
1873 assert_eq!(strings.len(), 0); }
1875}