diff options
Diffstat (limited to 'third_party/rust/goblin/src/pe/header.rs')
-rw-r--r-- | third_party/rust/goblin/src/pe/header.rs | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/third_party/rust/goblin/src/pe/header.rs b/third_party/rust/goblin/src/pe/header.rs new file mode 100644 index 0000000000..c1ded9dd9f --- /dev/null +++ b/third_party/rust/goblin/src/pe/header.rs @@ -0,0 +1,312 @@ +use crate::error; +use crate::pe::{optional_header, section_table, symbol}; +use crate::strtab; +use alloc::vec::Vec; +use log::debug; +use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith}; + +/// DOS header present in all PE binaries +#[repr(C)] +#[derive(Debug, PartialEq, Copy, Clone, Default)] +pub struct DosHeader { + /// Magic number: 5a4d + pub signature: u16, + /// Pointer to PE header, always at offset 0x3c + pub pe_pointer: u32, +} + +pub const DOS_MAGIC: u16 = 0x5a4d; +pub const PE_POINTER_OFFSET: u32 = 0x3c; + +impl DosHeader { + pub fn parse(bytes: &[u8]) -> error::Result<Self> { + let signature = bytes.pread_with(0, scroll::LE).map_err(|_| { + error::Error::Malformed(format!("cannot parse DOS signature (offset {:#x})", 0)) + })?; + if signature != DOS_MAGIC { + return Err(error::Error::Malformed(format!( + "DOS header is malformed (signature {:#x})", + signature + ))); + } + let pe_pointer = bytes + .pread_with(PE_POINTER_OFFSET as usize, scroll::LE) + .map_err(|_| { + error::Error::Malformed(format!( + "cannot parse PE header pointer (offset {:#x})", + PE_POINTER_OFFSET + )) + })?; + let pe_signature: u32 = + bytes + .pread_with(pe_pointer as usize, scroll::LE) + .map_err(|_| { + error::Error::Malformed(format!( + "cannot parse PE header signature (offset {:#x})", + pe_pointer + )) + })?; + if pe_signature != PE_MAGIC { + return Err(error::Error::Malformed(format!( + "PE header is malformed (signature {:#x})", + pe_signature + ))); + } + Ok(DosHeader { + signature, + pe_pointer, + }) + } +} + +/// COFF Header +#[repr(C)] +#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, IOread, IOwrite, SizeWith)] +pub struct CoffHeader { + /// The machine type + pub machine: u16, + pub number_of_sections: u16, + pub time_date_stamp: u32, + pub pointer_to_symbol_table: u32, + pub number_of_symbol_table: u32, + pub size_of_optional_header: u16, + pub characteristics: u16, +} + +pub const SIZEOF_COFF_HEADER: usize = 20; +/// PE\0\0, little endian +pub const PE_MAGIC: u32 = 0x0000_4550; +pub const SIZEOF_PE_MAGIC: usize = 4; +/// The contents of this field are assumed to be applicable to any machine type +pub const COFF_MACHINE_UNKNOWN: u16 = 0x0; +/// Matsushita AM33 +pub const COFF_MACHINE_AM33: u16 = 0x1d3; +/// x64 +pub const COFF_MACHINE_X86_64: u16 = 0x8664; +/// ARM little endian +pub const COFF_MACHINE_ARM: u16 = 0x1c0; +/// ARM64 little endian +pub const COFF_MACHINE_ARM64: u16 = 0xaa64; +/// ARM Thumb-2 little endian +pub const COFF_MACHINE_ARMNT: u16 = 0x1c4; +/// EFI byte code +pub const COFF_MACHINE_EBC: u16 = 0xebc; +/// Intel 386 or later processors and compatible processors +pub const COFF_MACHINE_X86: u16 = 0x14c; +/// Intel Itanium processor family +pub const COFF_MACHINE_IA64: u16 = 0x200; +/// Mitsubishi M32R little endian +pub const COFF_MACHINE_M32R: u16 = 0x9041; +/// MIPS16 +pub const COFF_MACHINE_MIPS16: u16 = 0x266; +/// MIPS with FPU +pub const COFF_MACHINE_MIPSFPU: u16 = 0x366; +/// MIPS16 with FPU +pub const COFF_MACHINE_MIPSFPU16: u16 = 0x466; +/// Power PC little endian +pub const COFF_MACHINE_POWERPC: u16 = 0x1f0; +/// Power PC with floating point support +pub const COFF_MACHINE_POWERPCFP: u16 = 0x1f1; +/// MIPS little endian +pub const COFF_MACHINE_R4000: u16 = 0x166; +/// RISC-V 32-bit address space +pub const COFF_MACHINE_RISCV32: u16 = 0x5032; +/// RISC-V 64-bit address space +pub const COFF_MACHINE_RISCV64: u16 = 0x5064; +/// RISC-V 128-bit address space +pub const COFF_MACHINE_RISCV128: u16 = 0x5128; +/// Hitachi SH3 +pub const COFF_MACHINE_SH3: u16 = 0x1a2; +/// Hitachi SH3 DSP +pub const COFF_MACHINE_SH3DSP: u16 = 0x1a3; +/// Hitachi SH4 +pub const COFF_MACHINE_SH4: u16 = 0x1a6; +/// Hitachi SH5 +pub const COFF_MACHINE_SH5: u16 = 0x1a8; +/// Thumb +pub const COFF_MACHINE_THUMB: u16 = 0x1c2; +/// MIPS little-endian WCE v2 +pub const COFF_MACHINE_WCEMIPSV2: u16 = 0x169; + +impl CoffHeader { + pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> { + Ok(bytes.gread_with(offset, scroll::LE)?) + } + + /// Parse the COFF section headers. + /// + /// For COFF, these immediately follow the COFF header. For PE, these immediately follow the + /// optional header. + pub fn sections( + &self, + bytes: &[u8], + offset: &mut usize, + ) -> error::Result<Vec<section_table::SectionTable>> { + let nsections = self.number_of_sections as usize; + + // a section table is at least 40 bytes + if nsections > bytes.len() / 40 { + return Err(error::Error::BufferTooShort(nsections, "sections")); + } + + let mut sections = Vec::with_capacity(nsections); + // Note that if we are handling a BigCoff, the size of the symbol will be different! + let string_table_offset = self.pointer_to_symbol_table as usize + + symbol::SymbolTable::size(self.number_of_symbol_table as usize); + for i in 0..nsections { + let section = + section_table::SectionTable::parse(bytes, offset, string_table_offset as usize)?; + debug!("({}) {:#?}", i, section); + sections.push(section); + } + Ok(sections) + } + + /// Return the COFF symbol table. + pub fn symbols<'a>(&self, bytes: &'a [u8]) -> error::Result<symbol::SymbolTable<'a>> { + let offset = self.pointer_to_symbol_table as usize; + let number = self.number_of_symbol_table as usize; + symbol::SymbolTable::parse(bytes, offset, number) + } + + /// Return the COFF string table. + pub fn strings<'a>(&self, bytes: &'a [u8]) -> error::Result<strtab::Strtab<'a>> { + let mut offset = self.pointer_to_symbol_table as usize + + symbol::SymbolTable::size(self.number_of_symbol_table as usize); + + let length_field_size = core::mem::size_of::<u32>(); + let length = bytes.pread_with::<u32>(offset, scroll::LE)? as usize - length_field_size; + + // The offset needs to be advanced in order to read the strings. + offset += length_field_size; + + Ok(strtab::Strtab::parse(bytes, offset, length, 0)?) + } +} + +#[derive(Debug, PartialEq, Copy, Clone, Default)] +pub struct Header { + pub dos_header: DosHeader, + /// PE Magic: PE\0\0, little endian + pub signature: u32, + pub coff_header: CoffHeader, + pub optional_header: Option<optional_header::OptionalHeader>, +} + +impl Header { + pub fn parse(bytes: &[u8]) -> error::Result<Self> { + let dos_header = DosHeader::parse(&bytes)?; + let mut offset = dos_header.pe_pointer as usize; + let signature = bytes.gread_with(&mut offset, scroll::LE).map_err(|_| { + error::Error::Malformed(format!("cannot parse PE signature (offset {:#x})", offset)) + })?; + let coff_header = CoffHeader::parse(&bytes, &mut offset)?; + let optional_header = if coff_header.size_of_optional_header > 0 { + Some(bytes.pread::<optional_header::OptionalHeader>(offset)?) + } else { + None + }; + Ok(Header { + dos_header, + signature, + coff_header, + optional_header, + }) + } +} + +/// Convert machine to str representation +pub fn machine_to_str(machine: u16) -> &'static str { + match machine { + COFF_MACHINE_UNKNOWN => "UNKNOWN", + COFF_MACHINE_AM33 => "AM33", + COFF_MACHINE_X86_64 => "X86_64", + COFF_MACHINE_ARM => "ARM", + COFF_MACHINE_ARM64 => "ARM64", + COFF_MACHINE_ARMNT => "ARM_NT", + COFF_MACHINE_EBC => "EBC", + COFF_MACHINE_X86 => "X86", + COFF_MACHINE_IA64 => "IA64", + COFF_MACHINE_M32R => "M32R", + COFF_MACHINE_MIPS16 => "MIPS_16", + COFF_MACHINE_MIPSFPU => "MIPS_FPU", + COFF_MACHINE_MIPSFPU16 => "MIPS_FPU_16", + COFF_MACHINE_POWERPC => "POWERPC", + COFF_MACHINE_POWERPCFP => "POWERCFP", + COFF_MACHINE_R4000 => "R4000", + COFF_MACHINE_RISCV32 => "RISC-V_32", + COFF_MACHINE_RISCV64 => "RISC-V_64", + COFF_MACHINE_RISCV128 => "RISC-V_128", + COFF_MACHINE_SH3 => "SH3", + COFF_MACHINE_SH3DSP => "SH3DSP", + COFF_MACHINE_SH4 => "SH4", + COFF_MACHINE_SH5 => "SH5", + COFF_MACHINE_THUMB => "THUMB", + COFF_MACHINE_WCEMIPSV2 => "WCE_MIPS_V2", + _ => "COFF_UNKNOWN", + } +} + +#[cfg(test)] +mod tests { + use super::{machine_to_str, Header, COFF_MACHINE_X86, DOS_MAGIC, PE_MAGIC}; + + const CRSS_HEADER: [u8; 688] = [ + 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd0, 0x00, 0x00, 0x00, 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, 0xaa, 0x4a, 0xc3, 0xeb, 0xee, 0x2b, 0xad, + 0xb8, 0xee, 0x2b, 0xad, 0xb8, 0xee, 0x2b, 0xad, 0xb8, 0xee, 0x2b, 0xac, 0xb8, 0xfe, 0x2b, + 0xad, 0xb8, 0x33, 0xd4, 0x66, 0xb8, 0xeb, 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x63, 0xb8, 0xea, + 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x7a, 0xb8, 0xed, 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x64, 0xb8, + 0xef, 0x2b, 0xad, 0xb8, 0x33, 0xd4, 0x61, 0xb8, 0xef, 0x2b, 0xad, 0xb8, 0x52, 0x69, 0x63, + 0x68, 0xee, 0x2b, 0xad, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x45, + 0x00, 0x00, 0x4c, 0x01, 0x05, 0x00, 0xd9, 0x8f, 0x15, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x00, 0x02, 0x01, 0x0b, 0x01, 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xe4, 0xab, 0x00, 0x00, + 0x01, 0x00, 0x40, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1a, 0x00, 0x00, 0xb8, 0x22, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x68, 0x10, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x24, + 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x60, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xc0, 0x2e, 0x69, 0x64, 0x61, + 0x74, 0x61, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x2e, 0x72, 0x73, 0x72, 0x63, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x42, 0x2e, 0x72, 0x65, 0x6c, 0x6f, 0x63, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + #[test] + fn crss_header() { + let header = Header::parse(&&CRSS_HEADER[..]).unwrap(); + assert!(header.dos_header.signature == DOS_MAGIC); + assert!(header.signature == PE_MAGIC); + assert!(header.coff_header.machine == COFF_MACHINE_X86); + assert!(machine_to_str(header.coff_header.machine) == "X86"); + println!("header: {:?}", &header); + } +} |