/// A PE32 (32-bit) image file. /// /// This is a file that starts with [`pe::ImageNtHeaders32`], and corresponds /// to [`crate::FileKind::Pe32`]. pubtype PeFile32<'data, R = &'data [u8]> = PeFile<'data, pe::ImageNtHeaders32, R>; /// A PE32+ (64-bit) image file. /// /// This is a file that starts with [`pe::ImageNtHeaders64`], and corresponds /// to [`crate::FileKind::Pe64`]. pubtype PeFile64<'data, R = &'data [u8]> = PeFile<'data, pe::ImageNtHeaders64, R>;
/// A PE image file. /// /// Most functionality is provided by the [`Object`] trait implementation. #[derive(Debug)] pubstruct PeFile<'data, Pe, R = &'data [u8]> where
Pe: ImageNtHeaders,
R: ReadRef<'data>,
{ pub(super) dos_header: &'data pe::ImageDosHeader, pub(super) nt_headers: &'data Pe, pub(super) data_directories: DataDirectories<'data>, pub(super) common: CoffCommon<'data, R>, pub(super) data: R,
}
impl<'data, Pe, R> PeFile<'data, Pe, R> where
Pe: ImageNtHeaders,
R: ReadRef<'data>,
{ /// Parse the raw PE file data. pubfn parse(data: R) -> Result<Self> { let dos_header = pe::ImageDosHeader::parse(data)?; letmut offset = dos_header.nt_headers_offset().into(); let (nt_headers, data_directories) = Pe::parse(data, &mut offset)?; let sections = nt_headers.sections(data, offset)?; let coff_symbols = nt_headers.symbols(data); let image_base = nt_headers.optional_header().image_base();
Ok(PeFile {
dos_header,
nt_headers,
data_directories,
common: CoffCommon {
sections, // The PE file format deprecates the COFF symbol table (https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#coff-file-header-object-and-image) // We do not want to prevent parsing the rest of the PE file for a corrupt COFF header, but rather return an empty symbol table
symbols: coff_symbols.unwrap_or_default(),
image_base,
},
data,
})
}
/// Returns this binary data. pubfn data(&self) -> R { self.data
}
/// Return the DOS header of this file. pubfn dos_header(&self) -> &'data pe::ImageDosHeader { self.dos_header
}
/// Return the NT Headers of this file. pubfn nt_headers(&self) -> &'data Pe { self.nt_headers
}
/// Returns information about the rich header of this file (if any). pubfn rich_header_info(&self) -> Option<RichHeaderInfo<'_>> {
RichHeaderInfo::parse(self.data, self.dos_header.nt_headers_offset().into())
}
/// Returns the section table of this binary. pubfn section_table(&self) -> SectionTable<'data> { self.common.sections
}
/// Returns the data directories of this file. pubfn data_directories(&self) -> DataDirectories<'data> { self.data_directories
}
/// Returns the data directory at the given index. pubfn data_directory(&self, id: usize) -> Option<&'data pe::ImageDataDirectory> { self.data_directories.get(id)
}
/// Returns the export table of this file. /// /// The export table is located using the data directory. pubfn export_table(&self) -> Result<Option<ExportTable<'data>>> { self.data_directories
.export_table(self.data, &self.common.sections)
}
/// Returns the import table of this file. /// /// The import table is located using the data directory. pubfn import_table(&self) -> Result<Option<ImportTable<'data>>> { self.data_directories
.import_table(self.data, &self.common.sections)
}
fn exports(&self) -> Result<Vec<Export<'data>>> { letmut exports = Vec::new(); iflet Some(export_table) = self.export_table()? { for (name_pointer, address_index) in export_table.name_iter() { let name = export_table.name_from_pointer(name_pointer)?; let address = export_table.address_by_index(address_index.into())?; if !export_table.is_forward(address) {
exports.push(Export {
name: ByteString(name),
address: self.common.image_base.wrapping_add(address.into()),
})
}
}
}
Ok(exports)
}
fn pdb_info(&self) -> Result<Option<CodeView<'_>>> { let data_dir = matchself.data_directory(pe::IMAGE_DIRECTORY_ENTRY_DEBUG) {
Some(data_dir) => data_dir,
None => return Ok(None),
}; let debug_data = data_dir.data(self.data, &self.common.sections)?; let debug_dirs = pod::slice_from_all_bytes::<pe::ImageDebugDirectory>(debug_data)
.read_error("Invalid PE debug dir size")?;
for debug_dir in debug_dirs { if debug_dir.typ.get(LE) != pe::IMAGE_DEBUG_TYPE_CODEVIEW { continue;
}
let info = self
.data
.read_slice_at::<u8>(
debug_dir.pointer_to_raw_data.get(LE) as u64,
debug_dir.size_of_data.get(LE) as usize,
)
.read_error("Invalid CodeView Info address")?;
letmut info = Bytes(info);
let sig = info
.read_bytes(4)
.read_error("Invalid CodeView signature")?; if sig.0 != b"RSDS" { continue;
}
let guid: [u8; 16] = info
.read_bytes(16)
.read_error("Invalid CodeView GUID")?
.0
.try_into()
.unwrap();
let age = info.read::<U32<LE>>().read_error("Invalid CodeView Age")?;
let path = info
.read_string()
.read_error("Invalid CodeView file path")?;
/// An iterator for the COMDAT section groups in a [`PeFile32`]. pubtype PeComdatIterator32<'data, 'file, R = &'data [u8]> =
PeComdatIterator<'data, 'file, pe::ImageNtHeaders32, R>; /// An iterator for the COMDAT section groups in a [`PeFile64`]. pubtype PeComdatIterator64<'data, 'file, R = &'data [u8]> =
PeComdatIterator<'data, 'file, pe::ImageNtHeaders64, R>;
/// An iterator for the COMDAT section groups in a [`PeFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct PeComdatIterator<'data, 'file, Pe, R = &'data [u8]> where
Pe: ImageNtHeaders,
R: ReadRef<'data>,
{ #[allow(unused)]
file: &'file PeFile<'data, Pe, R>,
}
impl<'data, 'file, Pe, R> Iterator for PeComdatIterator<'data, 'file, Pe, R> where
Pe: ImageNtHeaders,
R: ReadRef<'data>,
{ type Item = PeComdat<'data, 'file, Pe, R>;
/// A COMDAT section group in a [`PeFile32`]. pubtype PeComdat32<'data, 'file, R = &'data [u8]> =
PeComdat<'data, 'file, pe::ImageNtHeaders32, R>; /// A COMDAT section group in a [`PeFile64`]. pubtype PeComdat64<'data, 'file, R = &'data [u8]> =
PeComdat<'data, 'file, pe::ImageNtHeaders64, R>;
/// A COMDAT section group in a [`PeFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct PeComdat<'data, 'file, Pe, R = &'data [u8]> where
Pe: ImageNtHeaders,
R: ReadRef<'data>,
{ #[allow(unused)]
file: &'file PeFile<'data, Pe, R>,
}
impl<'data, 'file, Pe, R> read::private::Sealed for PeComdat<'data, 'file, Pe, R> where
Pe: ImageNtHeaders,
R: ReadRef<'data>,
{
}
impl<'data, 'file, Pe, R> ObjectComdat<'data> for PeComdat<'data, 'file, Pe, R> where
Pe: ImageNtHeaders,
R: ReadRef<'data>,
{ type SectionIterator = PeComdatSectionIterator<'data, 'file, Pe, R>;
/// An iterator for the sections in a COMDAT section group in a [`PeFile32`]. pubtype PeComdatSectionIterator32<'data, 'file, R = &'data [u8]> =
PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>; /// An iterator for the sections in a COMDAT section group in a [`PeFile64`]. pubtype PeComdatSectionIterator64<'data, 'file, R = &'data [u8]> =
PeComdatSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>;
/// An iterator for the sections in a COMDAT section group in a [`PeFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct PeComdatSectionIterator<'data, 'file, Pe, R = &'data [u8]> where
Pe: ImageNtHeaders,
R: ReadRef<'data>,
{ #[allow(unused)]
file: &'file PeFile<'data, Pe, R>,
}
impl<'data, 'file, Pe, R> Iterator for PeComdatSectionIterator<'data, 'file, Pe, R> where
Pe: ImageNtHeaders,
R: ReadRef<'data>,
{ type Item = SectionIndex;
impl pe::ImageDosHeader { /// Read the DOS header. /// /// Also checks that the `e_magic` field in the header is valid. pubfn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> { // DOS header comes first. let dos_header = data
.read_at::<pe::ImageDosHeader>(0)
.read_error("Invalid DOS header size or alignment")?; if dos_header.e_magic.get(LE) != pe::IMAGE_DOS_SIGNATURE { return Err(Error("Invalid DOS magic"));
}
Ok(dos_header)
}
/// Return the file offset of the nt_headers. #[inline] pubfn nt_headers_offset(&self) -> u32 { self.e_lfanew.get(LE)
}
}
/// Find the optional header and read its `magic` field. /// /// It can be useful to know this magic value before trying to /// fully parse the NT headers. pubfn optional_header_magic<'data, R: ReadRef<'data>>(data: R) -> Result<u16> { let dos_header = pe::ImageDosHeader::parse(data)?; // NT headers are at an offset specified in the DOS header. let offset = dos_header.nt_headers_offset().into(); // It doesn't matter which NT header type is used for the purpose // of reading the optional header magic. let nt_headers = data
.read_at::<pe::ImageNtHeaders32>(offset)
.read_error("Invalid NT headers offset, size, or alignment")?; if nt_headers.signature() != pe::IMAGE_NT_SIGNATURE { return Err(Error("Invalid PE magic"));
}
Ok(nt_headers.optional_header().magic())
}
/// A trait for generic access to [`pe::ImageNtHeaders32`] and [`pe::ImageNtHeaders64`]. #[allow(missing_docs)] pubtrait ImageNtHeaders: Debug + Pod { type ImageOptionalHeader: ImageOptionalHeader; type ImageThunkData: ImageThunkData;
/// Return true if this type is a 64-bit header. /// /// This is a property of the type, not a value in the header data. fn is_type_64(&self) -> bool;
/// Return true if the magic field in the optional header is valid. fn is_valid_optional_magic(&self) -> bool;
/// Return the signature fn signature(&self) -> u32;
/// Return the file header. fn file_header(&self) -> &pe::ImageFileHeader;
/// Return the optional header. fn optional_header(&self) -> &Self::ImageOptionalHeader;
// Provided methods.
/// Read the NT headers, including the data directories. /// /// `data` must be for the entire file. /// /// `offset` must be headers offset, which can be obtained from [`pe::ImageDosHeader::nt_headers_offset`]. /// It is updated to point after the optional header, which is where the section headers are located. /// /// Also checks that the `signature` and `magic` fields in the headers are valid. fn parse<'data, R: ReadRef<'data>>(
data: R,
offset: &mut u64,
) -> read::Result<(&'data Self, DataDirectories<'data>)> { // Note that this does not include the data directories in the optional header. let nt_headers = data
.read::<Self>(offset)
.read_error("Invalid PE headers offset or size")?; if nt_headers.signature() != pe::IMAGE_NT_SIGNATURE { return Err(Error("Invalid PE magic"));
} if !nt_headers.is_valid_optional_magic() { return Err(Error("Invalid PE optional header magic"));
}
// Read the rest of the optional header, and then read the data directories from that. let optional_data_size =
u64::from(nt_headers.file_header().size_of_optional_header.get(LE))
.checked_sub(mem::size_of::<Self::ImageOptionalHeader>() as u64)
.read_error("PE optional header size is too small")?; let optional_data = data
.read_bytes(offset, optional_data_size)
.read_error("Invalid PE optional header size")?; let data_directories = DataDirectories::parse(
optional_data,
nt_headers.optional_header().number_of_rva_and_sizes(),
)?;
Ok((nt_headers, data_directories))
}
/// Read the section table. /// /// `data` must be for the entire file. /// `offset` must be after the optional file header. #[inline] fn sections<'data, R: ReadRef<'data>>(
&self,
data: R,
offset: u64,
) -> read::Result<SectionTable<'data>> {
SectionTable::parse(self.file_header(), data, offset)
}
/// Read the COFF symbol table and string table. /// /// `data` must be the entire file data. #[inline] fn symbols<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<SymbolTable<'data, R>> {
SymbolTable::parse(self.file_header(), data)
}
}
/// A trait for generic access to [`pe::ImageOptionalHeader32`] and [`pe::ImageOptionalHeader64`]. #[allow(missing_docs)] pubtrait ImageOptionalHeader: Debug + Pod { // Standard fields. fn magic(&self) -> u16; fn major_linker_version(&self) -> u8; fn minor_linker_version(&self) -> u8; fn size_of_code(&self) -> u32; fn size_of_initialized_data(&self) -> u32; fn size_of_uninitialized_data(&self) -> u32; fn address_of_entry_point(&self) -> u32; fn base_of_code(&self) -> u32; fn base_of_data(&self) -> Option<u32>;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.