Skip to content

Commit 3af3130

Browse files
authored
pe.header: fix parse without rich header (#451)
fix parse without rich header
1 parent a503e77 commit 3af3130

File tree

1 file changed

+30
-17
lines changed

1 file changed

+30
-17
lines changed

src/pe/header.rs

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
use alloc::vec::Vec;
12
use core::iter::FusedIterator;
23

4+
use scroll::{ctx, IOread, IOwrite, Pread, Pwrite, SizeWith};
5+
36
use crate::error;
47
use crate::pe::{data_directories, debug, optional_header, section_table, symbol};
58
use crate::strtab;
6-
use alloc::vec::Vec;
7-
use scroll::{ctx, IOread, IOwrite, Pread, Pwrite, SizeWith};
89

910
/// In `winnt.h` and `pe.h`, it's `IMAGE_DOS_HEADER`. It's a DOS header present in all PE binaries.
1011
///
@@ -394,6 +395,7 @@ impl DosHeader {
394395
pub struct DosStub<'a> {
395396
pub data: &'a [u8],
396397
}
398+
397399
impl<'a> Default for DosStub<'a> {
398400
/// This is the very basic DOS program bytecode representation embedded in MSVC linker.
399401
///
@@ -442,6 +444,7 @@ impl<'a> Default for DosStub<'a> {
442444
}
443445
}
444446
}
447+
445448
impl<'a> ctx::TryIntoCtx<scroll::Endian> for DosStub<'a> {
446449
type Error = error::Error;
447450

@@ -870,9 +873,16 @@ impl<'a> Header<'a> {
870873
bytes: &'a [u8],
871874
dos_header: DosHeader,
872875
dos_stub: DosStub<'a>,
876+
parse_rich_header: bool,
873877
) -> error::Result<Self> {
874878
let mut offset = dos_header.pe_pointer as usize;
875-
let rich_header = RichHeader::parse(&bytes)?;
879+
880+
let rich_header = if parse_rich_header {
881+
RichHeader::parse(&bytes)?
882+
} else {
883+
None
884+
};
885+
876886
let signature = bytes.gread_with(&mut offset, scroll::LE).map_err(|_| {
877887
error::Error::Malformed(format!("cannot parse PE signature (offset {:#x})", offset))
878888
})?;
@@ -898,13 +908,13 @@ impl<'a> Header<'a> {
898908
let dos_header = DosHeader::parse(&bytes)?;
899909
let dos_stub = DosStub::parse(bytes, dos_header.pe_pointer)?;
900910

901-
Header::parse_impl(bytes, dos_header, dos_stub)
911+
Header::parse_impl(bytes, dos_header, dos_stub, true)
902912
}
903913

904914
/// Parses PE header from the given bytes, a default DosHeader and DosStub are generated, and any malformed header or stub is ignored
905915
pub fn parse_without_dos(bytes: &'a [u8]) -> error::Result<Self> {
906916
let dos_header = DosHeader::default();
907-
Header::parse_impl(bytes, dos_header, DosStub::default())
917+
Header::parse_impl(bytes, dos_header, DosStub::default(), false)
908918
}
909919
}
910920

@@ -1018,6 +1028,7 @@ impl Iterator for RichMetadataIterator<'_> {
10181028
}
10191029

10201030
impl FusedIterator for RichMetadataIterator<'_> {}
1031+
10211032
impl ExactSizeIterator for RichMetadataIterator<'_> {}
10221033

10231034
impl<'a> RichHeader<'a> {
@@ -1354,9 +1365,7 @@ pub fn machine_to_str(machine: u16) -> &'static str {
13541365
mod tests {
13551366
use crate::{error, pe::header::DosStub};
13561367

1357-
use super::{
1358-
machine_to_str, Header, RichHeader, RichMetadata, COFF_MACHINE_X86, DOS_MAGIC, PE_MAGIC,
1359-
};
1368+
use super::{COFF_MACHINE_X86, DOS_MAGIC, DosHeader, Header, machine_to_str, PE_MAGIC, RichHeader, RichMetadata};
13601369

13611370
const CRSS_HEADER: [u8; 688] = [
13621371
0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
@@ -1534,6 +1543,9 @@ mod tests {
15341543
0x00,
15351544
];
15361545

1546+
const WELL_FORMED_WITH_RICH_HEADER: &[u8] =
1547+
include_bytes!("../../tests/bins/pe/well_formed_import.exe.bin");
1548+
15371549
#[test]
15381550
fn crss_header() {
15391551
let header = Header::parse(&&CRSS_HEADER[..]).unwrap();
@@ -1545,15 +1557,16 @@ mod tests {
15451557
}
15461558

15471559
#[test]
1548-
fn parse_without_dos() {
1549-
let header = Header::parse_without_dos(&BORLAND_PE32_VALID_NO_RICH_HEADER).unwrap();
1550-
assert_eq!(header.dos_stub, DosStub::default());
1551-
assert_eq!(header.rich_header.is_none(), true);
1552-
1553-
// DOS stub is default but rich parser still works
1554-
let header = Header::parse_without_dos(&CORRECT_RICH_HEADER).unwrap();
1555-
assert_eq!(header.dos_stub, DosStub::default());
1556-
assert_eq!(header.rich_header.is_some(), true);
1560+
fn parse_without_dos_rich() {
1561+
// Get a PE pointer (e_lfanew)
1562+
let dos_header = DosHeader::parse(&WELL_FORMED_WITH_RICH_HEADER).unwrap();
1563+
// Skip DOS header and DOS stub
1564+
let buf = &WELL_FORMED_WITH_RICH_HEADER[dos_header.pe_pointer as usize..];
1565+
let header = Header::parse_without_dos(buf).unwrap();
1566+
1567+
assert_eq!(header.coff_header.number_of_sections, 6);
1568+
assert_eq!(header.rich_header, None);
1569+
assert_eq!(header.dos_header, DosHeader::default());
15571570
}
15581571

15591572
#[test]

0 commit comments

Comments
 (0)