From b9713182a78f0a0ae573837cd9df3cad4afd325d Mon Sep 17 00:00:00 2001 From: kkent030315 Date: Thu, 14 Nov 2024 14:40:09 +0900 Subject: [PATCH] PE: Fix import parser for non-well-formed import table (#429) * PE: Fix import parser for non-well-formed import table * Fix doc comment --- src/pe/import.rs | 50 +++++++++++++++++-- tests/bins/pe/not_well_formed_import.exe.bin | Bin 0 -> 4096 bytes tests/bins/pe/well_formed_import.exe.bin | Bin 0 -> 3584 bytes 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 tests/bins/pe/not_well_formed_import.exe.bin create mode 100644 tests/bins/pe/well_formed_import.exe.bin diff --git a/src/pe/import.rs b/src/pe/import.rs index 0284fc327..11c3ee7c9 100644 --- a/src/pe/import.rs +++ b/src/pe/import.rs @@ -129,7 +129,7 @@ impl<'a> SyntheticImportLookupTableEntry<'a> { use self::SyntheticImportLookupTableEntry::*; if bitfield.is_ordinal() { let ordinal = bitfield.to_ordinal(); - debug!("importing by ordinal {:#x}", ordinal); + debug!("importing by ordinal {:#x} ({})", ordinal, ordinal); OrdinalNumber(ordinal) } else { let rva = bitfield.to_rva(); @@ -171,6 +171,7 @@ pub struct ImportDirectoryEntry { pub const SIZEOF_IMPORT_DIRECTORY_ENTRY: usize = 20; impl ImportDirectoryEntry { + /// Whether the entire fields are set to zero pub fn is_null(&self) -> bool { (self.import_lookup_table_rva == 0) && (self.time_date_stamp == 0) @@ -178,6 +179,13 @@ impl ImportDirectoryEntry { && (self.name_rva == 0) && (self.import_address_table_rva == 0) } + + /// Whether the entry is _possibly_ valid. + /// + /// Both [`Self::name_rva`] and [`Self::import_address_table_rva`] must be non-zero + pub fn is_possibly_valid(&self) -> bool { + self.name_rva != 0 && self.import_address_table_rva != 0 + } } #[derive(Debug)] @@ -342,8 +350,8 @@ impl<'a> ImportData<'a> { loop { let import_directory_entry: ImportDirectoryEntry = bytes.gread_with(offset, scroll::LE)?; - debug!("{:#?}", import_directory_entry); - if import_directory_entry.is_null() { + debug!("{:#?} at {:#x}", import_directory_entry, offset); + if import_directory_entry.is_null() || !import_directory_entry.is_possibly_valid() { break; } else { let entry = SyntheticImportDirectoryEntry::parse_with_opts::( @@ -353,7 +361,7 @@ impl<'a> ImportData<'a> { file_alignment, opts, )?; - debug!("entry {:#?}", entry); + debug!("entry {:#?} at {:#x}", entry, offset); import_data.push(entry); } } @@ -415,3 +423,37 @@ impl<'a> Import<'a> { Ok(imports) } } + +#[cfg(test)] +mod tests { + const NOT_WELL_FORMED_IMPORT: &[u8] = + include_bytes!("../../tests/bins/pe/not_well_formed_import.exe.bin"); + const WELL_FORMED_IMPORT: &[u8] = + include_bytes!("../../tests/bins/pe/well_formed_import.exe.bin"); + + #[test] + fn parse_non_well_formed_import_table() { + let binary = crate::pe::PE::parse(NOT_WELL_FORMED_IMPORT).expect("Unable to parse binary"); + assert_eq!(binary.import_data.is_some(), true); + assert_eq!(binary.imports.len(), 1); + assert_eq!(binary.imports[0].name, "ORDINAL 51398"); + assert_eq!(binary.imports[0].dll, "abcd.dll"); + assert_eq!(binary.imports[0].ordinal, 51398); + assert_eq!(binary.imports[0].offset, 0x7014); + assert_eq!(binary.imports[0].rva, 0); + assert_eq!(binary.imports[0].size, 8); + } + + #[test] + fn parse_well_formed_import_table() { + let binary = crate::pe::PE::parse(WELL_FORMED_IMPORT).expect("Unable to parse binary"); + assert_eq!(binary.import_data.is_some(), true); + assert_eq!(binary.imports.len(), 1); + assert_eq!(binary.imports[0].name, "GetLastError"); + assert_eq!(binary.imports[0].dll, "KERNEL32.dll"); + assert_eq!(binary.imports[0].ordinal, 647); + assert_eq!(binary.imports[0].offset, 0x2000); + assert_eq!(binary.imports[0].rva, 0x21B8); + assert_eq!(binary.imports[0].size, 8); + } +} diff --git a/tests/bins/pe/not_well_formed_import.exe.bin b/tests/bins/pe/not_well_formed_import.exe.bin new file mode 100644 index 0000000000000000000000000000000000000000..1a920d7828de2cfa6f8f9193a774c49de8fe9139 GIT binary patch literal 4096 zcmeHJL2DC16n;%bYi;5l3eBO|iL9U?OK7$9BwK4}!Kk6;AUS1|-PXuvH*B_2f`@p~ zs|SBTj{N~1f*^A`|0&tARx58`_>JMLyTIS7If_a!s$&G+8CnR!FL$%EP(m$8T%yd#IT9Cq)~W7c*}OUq^#)iCv6wJIe5^VJ1tePD+&@lUu4mom8eQZ(7pn^*Xx-LBKzZl zc*iu~?&1($M8;~ZRwJyB*fQ#1-F3p=j$<2yogjwWmT|WTqgq`Fu}#9D7_8ao@->Mp ziTj8L)hA`XCR6~3=K}0ES0TjLAx(0M`GJv@l=wZp&g@!#+35Nu&vQM1`=$MdrSitQ zX4-ag_H+bm#@|1zm3Rk>fgYQJhfHNQE1*oe@7X+Rda4N(&;`%IU}2yP@&n>3{`YDy nAvT3(t^&)Q@JL%|)A;i#$NHfsX&H^C`KND9GE0j5>k9k=g6Wcq literal 0 HcmV?d00001 diff --git a/tests/bins/pe/well_formed_import.exe.bin b/tests/bins/pe/well_formed_import.exe.bin new file mode 100644 index 0000000000000000000000000000000000000000..1336060fa999803dc80186180d300f8a98454e9c GIT binary patch literal 3584 zcmeHJziU%b6h29%wAI86f&oQuDpg zC+e|>IdUF9ed2Wd;_EoQnmgQ%d6Opx)w;_Cm2$C=`G}kI%5z=Pm*33}VZ`UN8pP)VyoJ(5nka*eWn$ zErhJv<(51XVhQbo4qEp!@=RiVgU)GeK&x<$u@6`a6Ak*|_w*#XUJWv(R*?36&nLQ- z&fQ68mX~a|ULUL+A92s*?;rO{{SGc_pVeNL^ChP?nH@-k-}7W%aeAvU9dMM+QFpGJ U=q9_+D*5-SJEmrunwSp!27y+kSO5S3 literal 0 HcmV?d00001