diff options
Diffstat (limited to 'vendor/object/src/read/pe')
-rw-r--r-- | vendor/object/src/read/pe/data_directory.rs | 213 | ||||
-rw-r--r-- | vendor/object/src/read/pe/export.rs | 333 | ||||
-rw-r--r-- | vendor/object/src/read/pe/file.rs | 1050 | ||||
-rw-r--r-- | vendor/object/src/read/pe/import.rs | 337 | ||||
-rw-r--r-- | vendor/object/src/read/pe/mod.rs | 68 | ||||
-rw-r--r-- | vendor/object/src/read/pe/relocation.rs | 92 | ||||
-rw-r--r-- | vendor/object/src/read/pe/resource.rs | 209 | ||||
-rw-r--r-- | vendor/object/src/read/pe/rich.rs | 91 | ||||
-rw-r--r-- | vendor/object/src/read/pe/section.rs | 440 |
9 files changed, 0 insertions, 2833 deletions
diff --git a/vendor/object/src/read/pe/data_directory.rs b/vendor/object/src/read/pe/data_directory.rs deleted file mode 100644 index a17179f..0000000 --- a/vendor/object/src/read/pe/data_directory.rs +++ /dev/null @@ -1,213 +0,0 @@ -use core::slice; - -use crate::read::{Error, ReadError, ReadRef, Result}; -use crate::{pe, LittleEndian as LE}; - -use super::{ - DelayLoadImportTable, ExportTable, ImportTable, RelocationBlockIterator, ResourceDirectory, - SectionTable, -}; - -/// The table of data directories in a PE file. -/// -/// Returned by [`ImageNtHeaders::parse`](super::ImageNtHeaders::parse). -#[derive(Debug, Clone, Copy)] -pub struct DataDirectories<'data> { - entries: &'data [pe::ImageDataDirectory], -} - -impl<'data> DataDirectories<'data> { - /// Parse the data directory table. - /// - /// `data` must be the remaining optional data following the - /// [optional header](pe::ImageOptionalHeader64). `number` must be from the - /// [`number_of_rva_and_sizes`](pe::ImageOptionalHeader64::number_of_rva_and_sizes) - /// field of the optional header. - pub fn parse(data: &'data [u8], number: u32) -> Result<Self> { - let entries = data - .read_slice_at(0, number as usize) - .read_error("Invalid PE number of RVA and sizes")?; - Ok(DataDirectories { entries }) - } - - /// The number of data directories. - #[allow(clippy::len_without_is_empty)] - pub fn len(&self) -> usize { - self.entries.len() - } - - /// Iterator over the data directories. - pub fn iter(&self) -> slice::Iter<'data, pe::ImageDataDirectory> { - self.entries.iter() - } - - /// Iterator which gives the directories as well as their index (one of the IMAGE_DIRECTORY_ENTRY_* constants). - pub fn enumerate(&self) -> core::iter::Enumerate<slice::Iter<'data, pe::ImageDataDirectory>> { - self.entries.iter().enumerate() - } - - /// Returns the data directory at the given index. - /// - /// Index should be one of the `IMAGE_DIRECTORY_ENTRY_*` constants. - /// - /// Returns `None` if the index is larger than the table size, - /// or if the entry at the index has a zero virtual address. - pub fn get(&self, index: usize) -> Option<&'data pe::ImageDataDirectory> { - self.entries - .get(index) - .filter(|d| d.virtual_address.get(LE) != 0) - } - - /// Returns the unparsed export directory. - /// - /// `data` must be the entire file data. - pub fn export_directory<R: ReadRef<'data>>( - &self, - data: R, - sections: &SectionTable<'data>, - ) -> Result<Option<&'data pe::ImageExportDirectory>> { - let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_EXPORT) { - Some(data_dir) => data_dir, - None => return Ok(None), - }; - let export_data = data_dir.data(data, sections)?; - ExportTable::parse_directory(export_data).map(Some) - } - - /// Returns the partially parsed export directory. - /// - /// `data` must be the entire file data. - pub fn export_table<R: ReadRef<'data>>( - &self, - data: R, - sections: &SectionTable<'data>, - ) -> Result<Option<ExportTable<'data>>> { - let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_EXPORT) { - Some(data_dir) => data_dir, - None => return Ok(None), - }; - let export_va = data_dir.virtual_address.get(LE); - let export_data = data_dir.data(data, sections)?; - ExportTable::parse(export_data, export_va).map(Some) - } - - /// Returns the partially parsed import directory. - /// - /// `data` must be the entire file data. - pub fn import_table<R: ReadRef<'data>>( - &self, - data: R, - sections: &SectionTable<'data>, - ) -> Result<Option<ImportTable<'data>>> { - let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_IMPORT) { - Some(data_dir) => data_dir, - None => return Ok(None), - }; - let import_va = data_dir.virtual_address.get(LE); - let (section_data, section_va) = sections - .pe_data_containing(data, import_va) - .read_error("Invalid import data dir virtual address")?; - Ok(Some(ImportTable::new(section_data, section_va, import_va))) - } - - /// Returns the partially parsed delay-load import directory. - /// - /// `data` must be the entire file data. - pub fn delay_load_import_table<R: ReadRef<'data>>( - &self, - data: R, - sections: &SectionTable<'data>, - ) -> Result<Option<DelayLoadImportTable<'data>>> { - let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT) { - Some(data_dir) => data_dir, - None => return Ok(None), - }; - let import_va = data_dir.virtual_address.get(LE); - let (section_data, section_va) = sections - .pe_data_containing(data, import_va) - .read_error("Invalid import data dir virtual address")?; - Ok(Some(DelayLoadImportTable::new( - section_data, - section_va, - import_va, - ))) - } - - /// Returns the blocks in the base relocation directory. - /// - /// `data` must be the entire file data. - pub fn relocation_blocks<R: ReadRef<'data>>( - &self, - data: R, - sections: &SectionTable<'data>, - ) -> Result<Option<RelocationBlockIterator<'data>>> { - let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_BASERELOC) { - Some(data_dir) => data_dir, - None => return Ok(None), - }; - let reloc_data = data_dir.data(data, sections)?; - Ok(Some(RelocationBlockIterator::new(reloc_data))) - } - - /// Returns the resource directory. - /// - /// `data` must be the entire file data. - pub fn resource_directory<R: ReadRef<'data>>( - &self, - data: R, - sections: &SectionTable<'data>, - ) -> Result<Option<ResourceDirectory<'data>>> { - let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_RESOURCE) { - Some(data_dir) => data_dir, - None => return Ok(None), - }; - let rsrc_data = data_dir.data(data, sections)?; - Ok(Some(ResourceDirectory::new(rsrc_data))) - } -} - -impl pe::ImageDataDirectory { - /// Return the virtual address range of this directory entry. - pub fn address_range(&self) -> (u32, u32) { - (self.virtual_address.get(LE), self.size.get(LE)) - } - - /// Return the file offset and size of this directory entry. - /// - /// This function has some limitations: - /// - It requires that the data is contained in a single section. - /// - It uses the size field of the directory entry, which is - /// not desirable for all data directories. - /// - It uses the `virtual_address` of the directory entry as an address, - /// which is not valid for `IMAGE_DIRECTORY_ENTRY_SECURITY`. - pub fn file_range(&self, sections: &SectionTable<'_>) -> Result<(u32, u32)> { - let (offset, section_size) = sections - .pe_file_range_at(self.virtual_address.get(LE)) - .read_error("Invalid data dir virtual address")?; - let size = self.size.get(LE); - if size > section_size { - return Err(Error("Invalid data dir size")); - } - Ok((offset, size)) - } - - /// Get the data referenced by this directory entry. - /// - /// This function has some limitations: - /// - It requires that the data is contained in a single section. - /// - It uses the size field of the directory entry, which is - /// not desirable for all data directories. - /// - It uses the `virtual_address` of the directory entry as an address, - /// which is not valid for `IMAGE_DIRECTORY_ENTRY_SECURITY`. - pub fn data<'data, R: ReadRef<'data>>( - &self, - data: R, - sections: &SectionTable<'data>, - ) -> Result<&'data [u8]> { - sections - .pe_data_at(data, self.virtual_address.get(LE)) - .read_error("Invalid data dir virtual address")? - .get(..self.size.get(LE) as usize) - .read_error("Invalid data dir size") - } -} diff --git a/vendor/object/src/read/pe/export.rs b/vendor/object/src/read/pe/export.rs deleted file mode 100644 index 1aba844..0000000 --- a/vendor/object/src/read/pe/export.rs +++ /dev/null @@ -1,333 +0,0 @@ -use alloc::vec::Vec; -use core::fmt::Debug; - -use crate::read::{ByteString, Bytes, Error, ReadError, ReadRef, Result}; -use crate::{pe, LittleEndian as LE, U16Bytes, U32Bytes}; - -/// Where an export is pointing to. -#[derive(Clone, Copy)] -pub enum ExportTarget<'data> { - /// The address of the export, relative to the image base. - Address(u32), - /// Forwarded to an export ordinal in another DLL. - /// - /// This gives the name of the DLL, and the ordinal. - ForwardByOrdinal(&'data [u8], u32), - /// Forwarded to an export name in another DLL. - /// - /// This gives the name of the DLL, and the export name. - ForwardByName(&'data [u8], &'data [u8]), -} - -impl<'data> ExportTarget<'data> { - /// Returns true if the target is an address. - pub fn is_address(&self) -> bool { - match self { - ExportTarget::Address(_) => true, - _ => false, - } - } - - /// Returns true if the export is forwarded to another DLL. - pub fn is_forward(&self) -> bool { - !self.is_address() - } -} - -/// An export from a PE file. -/// -/// There are multiple kinds of PE exports (with or without a name, and local or forwarded). -#[derive(Clone, Copy)] -pub struct Export<'data> { - /// The ordinal of the export. - /// - /// These are sequential, starting at a base specified in the DLL. - pub ordinal: u32, - /// The name of the export, if known. - pub name: Option<&'data [u8]>, - /// The target of this export. - pub target: ExportTarget<'data>, -} - -impl<'a> Debug for Export<'a> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::result::Result<(), core::fmt::Error> { - f.debug_struct("Export") - .field("ordinal", &self.ordinal) - .field("name", &self.name.map(ByteString)) - .field("target", &self.target) - .finish() - } -} - -impl<'a> Debug for ExportTarget<'a> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::result::Result<(), core::fmt::Error> { - match self { - ExportTarget::Address(address) => write!(f, "Address({:#x})", address), - ExportTarget::ForwardByOrdinal(library, ordinal) => write!( - f, - "ForwardByOrdinal({:?}.#{})", - ByteString(library), - ordinal - ), - ExportTarget::ForwardByName(library, name) => write!( - f, - "ForwardByName({:?}.{:?})", - ByteString(library), - ByteString(name) - ), - } - } -} - -/// A partially parsed PE export table. -/// -/// Returned by [`DataDirectories::export_table`](super::DataDirectories::export_table). -#[derive(Debug, Clone)] -pub struct ExportTable<'data> { - data: Bytes<'data>, - virtual_address: u32, - directory: &'data pe::ImageExportDirectory, - addresses: &'data [U32Bytes<LE>], - names: &'data [U32Bytes<LE>], - name_ordinals: &'data [U16Bytes<LE>], -} - -impl<'data> ExportTable<'data> { - /// Parse the export table given its section data and address. - pub fn parse(data: &'data [u8], virtual_address: u32) -> Result<Self> { - let directory = Self::parse_directory(data)?; - let data = Bytes(data); - - let mut addresses = &[][..]; - let address_of_functions = directory.address_of_functions.get(LE); - if address_of_functions != 0 { - addresses = data - .read_slice_at::<U32Bytes<_>>( - address_of_functions.wrapping_sub(virtual_address) as usize, - directory.number_of_functions.get(LE) as usize, - ) - .read_error("Invalid PE export address table")?; - } - - let mut names = &[][..]; - let mut name_ordinals = &[][..]; - let address_of_names = directory.address_of_names.get(LE); - let address_of_name_ordinals = directory.address_of_name_ordinals.get(LE); - if address_of_names != 0 { - if address_of_name_ordinals == 0 { - return Err(Error("Missing PE export ordinal table")); - } - - let number = directory.number_of_names.get(LE) as usize; - names = data - .read_slice_at::<U32Bytes<_>>( - address_of_names.wrapping_sub(virtual_address) as usize, - number, - ) - .read_error("Invalid PE export name pointer table")?; - name_ordinals = data - .read_slice_at::<U16Bytes<_>>( - address_of_name_ordinals.wrapping_sub(virtual_address) as usize, - number, - ) - .read_error("Invalid PE export ordinal table")?; - } - - Ok(ExportTable { - data, - virtual_address, - directory, - addresses, - names, - name_ordinals, - }) - } - - /// Parse the export directory given its section data. - pub fn parse_directory(data: &'data [u8]) -> Result<&'data pe::ImageExportDirectory> { - data.read_at::<pe::ImageExportDirectory>(0) - .read_error("Invalid PE export dir size") - } - - /// Returns the header of the export table. - pub fn directory(&self) -> &'data pe::ImageExportDirectory { - self.directory - } - - /// Returns the base value of ordinals. - /// - /// Adding this to an address index will give an ordinal. - pub fn ordinal_base(&self) -> u32 { - self.directory.base.get(LE) - } - - /// Returns the unparsed address table. - /// - /// An address table entry may be a local address, or the address of a forwarded export entry. - /// See [`Self::is_forward`] and [`Self::target_from_address`]. - pub fn addresses(&self) -> &'data [U32Bytes<LE>] { - self.addresses - } - - /// Returns the unparsed name pointer table. - /// - /// A name pointer table entry can be used with [`Self::name_from_pointer`]. - pub fn name_pointers(&self) -> &'data [U32Bytes<LE>] { - self.names - } - - /// Returns the unparsed ordinal table. - /// - /// An ordinal table entry is a 0-based index into the address table. - /// See [`Self::address_by_index`] and [`Self::target_by_index`]. - pub fn name_ordinals(&self) -> &'data [U16Bytes<LE>] { - self.name_ordinals - } - - /// Returns an iterator for the entries in the name pointer table and ordinal table. - /// - /// A name pointer table entry can be used with [`Self::name_from_pointer`]. - /// - /// An ordinal table entry is a 0-based index into the address table. - /// See [`Self::address_by_index`] and [`Self::target_by_index`]. - pub fn name_iter(&self) -> impl Iterator<Item = (u32, u16)> + 'data { - self.names - .iter() - .map(|x| x.get(LE)) - .zip(self.name_ordinals.iter().map(|x| x.get(LE))) - } - - /// Returns the export address table entry at the given address index. - /// - /// This may be a local address, or the address of a forwarded export entry. - /// See [`Self::is_forward`] and [`Self::target_from_address`]. - /// - /// `index` is a 0-based index into the export address table. - pub fn address_by_index(&self, index: u32) -> Result<u32> { - Ok(self - .addresses - .get(index as usize) - .read_error("Invalid PE export address index")? - .get(LE)) - } - - /// Returns the export address table entry at the given ordinal. - /// - /// This may be a local address, or the address of a forwarded export entry. - /// See [`Self::is_forward`] and [`Self::target_from_address`]. - pub fn address_by_ordinal(&self, ordinal: u32) -> Result<u32> { - self.address_by_index(ordinal.wrapping_sub(self.ordinal_base())) - } - - /// Returns the target of the export at the given address index. - /// - /// `index` is a 0-based index into the export address table. - pub fn target_by_index(&self, index: u32) -> Result<ExportTarget<'data>> { - self.target_from_address(self.address_by_index(index)?) - } - - /// Returns the target of the export at the given ordinal. - pub fn target_by_ordinal(&self, ordinal: u32) -> Result<ExportTarget<'data>> { - self.target_from_address(self.address_by_ordinal(ordinal)?) - } - - /// Convert an export address table entry into a target. - pub fn target_from_address(&self, address: u32) -> Result<ExportTarget<'data>> { - Ok(if let Some(forward) = self.forward_string(address)? { - let i = forward - .iter() - .position(|x| *x == b'.') - .read_error("Missing PE forwarded export separator")?; - let library = &forward[..i]; - match &forward[i + 1..] { - [b'#', digits @ ..] => { - let ordinal = - parse_ordinal(digits).read_error("Invalid PE forwarded export ordinal")?; - ExportTarget::ForwardByOrdinal(library, ordinal) - } - [] => { - return Err(Error("Missing PE forwarded export name")); - } - name => ExportTarget::ForwardByName(library, name), - } - } else { - ExportTarget::Address(address) - }) - } - - fn forward_offset(&self, address: u32) -> Option<usize> { - let offset = address.wrapping_sub(self.virtual_address) as usize; - if offset < self.data.len() { - Some(offset) - } else { - None - } - } - - /// Return true if the export address table entry is a forward. - pub fn is_forward(&self, address: u32) -> bool { - self.forward_offset(address).is_some() - } - - /// Return the forward string if the export address table entry is a forward. - pub fn forward_string(&self, address: u32) -> Result<Option<&'data [u8]>> { - if let Some(offset) = self.forward_offset(address) { - self.data - .read_string_at(offset) - .read_error("Invalid PE forwarded export address") - .map(Some) - } else { - Ok(None) - } - } - - /// Convert an export name pointer table entry into a name. - pub fn name_from_pointer(&self, name_pointer: u32) -> Result<&'data [u8]> { - let offset = name_pointer.wrapping_sub(self.virtual_address); - self.data - .read_string_at(offset as usize) - .read_error("Invalid PE export name pointer") - } - - /// Returns the parsed exports in this table. - pub fn exports(&self) -> Result<Vec<Export<'data>>> { - // First, let's list all exports. - let mut exports = Vec::new(); - let ordinal_base = self.ordinal_base(); - for (i, address) in self.addresses.iter().enumerate() { - // Convert from an array index to an ordinal. - let ordinal = ordinal_base.wrapping_add(i as u32); - let target = self.target_from_address(address.get(LE))?; - exports.push(Export { - ordinal, - target, - // Might be populated later. - name: None, - }); - } - - // Now, check whether some (or all) of them have an associated name. - // `ordinal_index` is a 0-based index into `addresses`. - for (name_pointer, ordinal_index) in self.name_iter() { - let name = self.name_from_pointer(name_pointer)?; - exports - .get_mut(ordinal_index as usize) - .read_error("Invalid PE export ordinal")? - .name = Some(name); - } - - Ok(exports) - } -} - -fn parse_ordinal(digits: &[u8]) -> Option<u32> { - if digits.is_empty() { - return None; - } - let mut result: u32 = 0; - for &c in digits { - let x = (c as char).to_digit(10)?; - result = result.checked_mul(10)?.checked_add(x)?; - } - Some(result) -} diff --git a/vendor/object/src/read/pe/file.rs b/vendor/object/src/read/pe/file.rs deleted file mode 100644 index 5372bdd..0000000 --- a/vendor/object/src/read/pe/file.rs +++ /dev/null @@ -1,1050 +0,0 @@ -use alloc::vec::Vec; -use core::fmt::Debug; -use core::{mem, str}; - -use core::convert::TryInto; - -use crate::read::coff::{CoffCommon, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SymbolTable}; -use crate::read::{ - self, Architecture, ComdatKind, Error, Export, FileFlags, Import, NoDynamicRelocationIterator, - Object, ObjectComdat, ObjectKind, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, -}; -use crate::{pe, ByteString, Bytes, CodeView, LittleEndian as LE, Pod, SubArchitecture, U32}; - -use super::{ - DataDirectories, ExportTable, ImageThunkData, ImportTable, PeSection, PeSectionIterator, - PeSegment, PeSegmentIterator, RichHeaderInfo, SectionTable, -}; - -/// A PE32 (32-bit) image file. -/// -/// This is a file that starts with [`pe::ImageNtHeaders32`], and corresponds -/// to [`crate::FileKind::Pe32`]. -pub type 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`]. -pub type 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)] -pub struct 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. - pub fn parse(data: R) -> Result<Self> { - let dos_header = pe::ImageDosHeader::parse(data)?; - let mut 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. - pub fn data(&self) -> R { - self.data - } - - /// Return the DOS header of this file. - pub fn dos_header(&self) -> &'data pe::ImageDosHeader { - self.dos_header - } - - /// Return the NT Headers of this file. - pub fn nt_headers(&self) -> &'data Pe { - self.nt_headers - } - - /// Returns information about the rich header of this file (if any). - pub fn rich_header_info(&self) -> Option<RichHeaderInfo<'_>> { - RichHeaderInfo::parse(self.data, self.dos_header.nt_headers_offset().into()) - } - - /// Returns the section table of this binary. - pub fn section_table(&self) -> SectionTable<'data> { - self.common.sections - } - - /// Returns the data directories of this file. - pub fn data_directories(&self) -> DataDirectories<'data> { - self.data_directories - } - - /// Returns the data directory at the given index. - pub fn 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. - pub fn 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. - pub fn import_table(&self) -> Result<Option<ImportTable<'data>>> { - self.data_directories - .import_table(self.data, &self.common.sections) - } - - pub(super) fn section_alignment(&self) -> u64 { - u64::from(self.nt_headers.optional_header().section_alignment()) - } -} - -impl<'data, Pe, R> read::private::Sealed for PeFile<'data, Pe, R> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Pe, R> Object<'data, 'file> for PeFile<'data, Pe, R> -where - 'data: 'file, - Pe: ImageNtHeaders, - R: 'file + ReadRef<'data>, -{ - type Segment = PeSegment<'data, 'file, Pe, R>; - type SegmentIterator = PeSegmentIterator<'data, 'file, Pe, R>; - type Section = PeSection<'data, 'file, Pe, R>; - type SectionIterator = PeSectionIterator<'data, 'file, Pe, R>; - type Comdat = PeComdat<'data, 'file, Pe, R>; - type ComdatIterator = PeComdatIterator<'data, 'file, Pe, R>; - type Symbol = CoffSymbol<'data, 'file, R>; - type SymbolIterator = CoffSymbolIterator<'data, 'file, R>; - type SymbolTable = CoffSymbolTable<'data, 'file, R>; - type DynamicRelocationIterator = NoDynamicRelocationIterator; - - fn architecture(&self) -> Architecture { - match self.nt_headers.file_header().machine.get(LE) { - pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm, - pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64, - pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386, - pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64, - _ => Architecture::Unknown, - } - } - - fn sub_architecture(&self) -> Option<SubArchitecture> { - match self.nt_headers.file_header().machine.get(LE) { - pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC), - _ => None, - } - } - - #[inline] - fn is_little_endian(&self) -> bool { - // Only little endian is supported. - true - } - - #[inline] - fn is_64(&self) -> bool { - self.nt_headers.is_type_64() - } - - fn kind(&self) -> ObjectKind { - let characteristics = self.nt_headers.file_header().characteristics.get(LE); - if characteristics & pe::IMAGE_FILE_DLL != 0 { - ObjectKind::Dynamic - } else if characteristics & pe::IMAGE_FILE_SYSTEM != 0 { - ObjectKind::Unknown - } else { - ObjectKind::Executable - } - } - - fn segments(&'file self) -> PeSegmentIterator<'data, 'file, Pe, R> { - PeSegmentIterator { - file: self, - iter: self.common.sections.iter(), - } - } - - fn section_by_name_bytes( - &'file self, - section_name: &[u8], - ) -> Option<PeSection<'data, 'file, Pe, R>> { - self.common - .sections - .section_by_name(self.common.symbols.strings(), section_name) - .map(|(index, section)| PeSection { - file: self, - index: SectionIndex(index), - section, - }) - } - - fn section_by_index( - &'file self, - index: SectionIndex, - ) -> Result<PeSection<'data, 'file, Pe, R>> { - let section = self.common.sections.section(index.0)?; - Ok(PeSection { - file: self, - index, - section, - }) - } - - fn sections(&'file self) -> PeSectionIterator<'data, 'file, Pe, R> { - PeSectionIterator { - file: self, - iter: self.common.sections.iter().enumerate(), - } - } - - fn comdats(&'file self) -> PeComdatIterator<'data, 'file, Pe, R> { - PeComdatIterator { file: self } - } - - fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<CoffSymbol<'data, 'file, R>> { - let symbol = self.common.symbols.symbol(index.0)?; - Ok(CoffSymbol { - file: &self.common, - index, - symbol, - }) - } - - fn symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R> { - CoffSymbolIterator { - file: &self.common, - index: 0, - } - } - - fn symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R>> { - Some(CoffSymbolTable { file: &self.common }) - } - - fn dynamic_symbols(&'file self) -> CoffSymbolIterator<'data, 'file, R> { - CoffSymbolIterator { - file: &self.common, - // Hack: don't return any. - index: self.common.symbols.len(), - } - } - - fn dynamic_symbol_table(&'file self) -> Option<CoffSymbolTable<'data, 'file, R>> { - None - } - - fn dynamic_relocations(&'file self) -> Option<NoDynamicRelocationIterator> { - None - } - - fn imports(&self) -> Result<Vec<Import<'data>>> { - let mut imports = Vec::new(); - if let Some(import_table) = self.import_table()? { - let mut import_descs = import_table.descriptors()?; - while let Some(import_desc) = import_descs.next()? { - let library = import_table.name(import_desc.name.get(LE))?; - let mut first_thunk = import_desc.original_first_thunk.get(LE); - if first_thunk == 0 { - first_thunk = import_desc.first_thunk.get(LE); - } - let mut thunks = import_table.thunks(first_thunk)?; - while let Some(thunk) = thunks.next::<Pe>()? { - if !thunk.is_ordinal() { - let (_hint, name) = import_table.hint_name(thunk.address())?; - imports.push(Import { - library: ByteString(library), - name: ByteString(name), - }); - } - } - } - } - Ok(imports) - } - - fn exports(&self) -> Result<Vec<Export<'data>>> { - let mut exports = Vec::new(); - if let 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 = match self.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).map(Bytes)?; - let debug_data_size = data_dir.size.get(LE) as usize; - - let count = debug_data_size / mem::size_of::<pe::ImageDebugDirectory>(); - let rem = debug_data_size % mem::size_of::<pe::ImageDebugDirectory>(); - if rem != 0 || count < 1 { - return Err(Error("Invalid PE debug dir size")); - } - - let debug_dirs = debug_data - .read_slice_at::<pe::ImageDebugDirectory>(0, count) - .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")?; - - let mut 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")?; - - return Ok(Some(CodeView { - path: ByteString(path), - guid, - age: age.get(LE), - })); - } - Ok(None) - } - - fn has_debug_symbols(&self) -> bool { - self.section_by_name(".debug_info").is_some() - } - - fn relative_address_base(&self) -> u64 { - self.common.image_base - } - - fn entry(&self) -> u64 { - u64::from(self.nt_headers.optional_header().address_of_entry_point()) - .wrapping_add(self.common.image_base) - } - - fn flags(&self) -> FileFlags { - FileFlags::Coff { - characteristics: self.nt_headers.file_header().characteristics.get(LE), - } - } -} - -/// An iterator for the COMDAT section groups in a [`PeFile32`]. -pub type PeComdatIterator32<'data, 'file, R = &'data [u8]> = - PeComdatIterator<'data, 'file, pe::ImageNtHeaders32, R>; -/// An iterator for the COMDAT section groups in a [`PeFile64`]. -pub type 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)] -pub struct 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>; - - #[inline] - fn next(&mut self) -> Option<Self::Item> { - None - } -} - -/// A COMDAT section group in a [`PeFile32`]. -pub type PeComdat32<'data, 'file, R = &'data [u8]> = - PeComdat<'data, 'file, pe::ImageNtHeaders32, R>; -/// A COMDAT section group in a [`PeFile64`]. -pub type 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)] -pub struct 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>; - - #[inline] - fn kind(&self) -> ComdatKind { - unreachable!(); - } - - #[inline] - fn symbol(&self) -> SymbolIndex { - unreachable!(); - } - - #[inline] - fn name_bytes(&self) -> Result<&[u8]> { - unreachable!(); - } - - #[inline] - fn name(&self) -> Result<&str> { - unreachable!(); - } - - #[inline] - fn sections(&self) -> Self::SectionIterator { - unreachable!(); - } -} - -/// An iterator for the sections in a COMDAT section group in a [`PeFile32`]. -pub type 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`]. -pub type 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)] -pub struct 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; - - fn next(&mut self) -> Option<Self::Item> { - None - } -} - -impl pe::ImageDosHeader { - /// Read the DOS header. - /// - /// Also checks that the `e_magic` field in the header is valid. - pub fn 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] - pub fn 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. -pub fn 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)] -pub trait 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)] -pub trait 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>; - - // NT additional fields. - fn image_base(&self) -> u64; - fn section_alignment(&self) -> u32; - fn file_alignment(&self) -> u32; - fn major_operating_system_version(&self) -> u16; - fn minor_operating_system_version(&self) -> u16; - fn major_image_version(&self) -> u16; - fn minor_image_version(&self) -> u16; - fn major_subsystem_version(&self) -> u16; - fn minor_subsystem_version(&self) -> u16; - fn win32_version_value(&self) -> u32; - fn size_of_image(&self) -> u32; - fn size_of_headers(&self) -> u32; - fn check_sum(&self) -> u32; - fn subsystem(&self) -> u16; - fn dll_characteristics(&self) -> u16; - fn size_of_stack_reserve(&self) -> u64; - fn size_of_stack_commit(&self) -> u64; - fn size_of_heap_reserve(&self) -> u64; - fn size_of_heap_commit(&self) -> u64; - fn loader_flags(&self) -> u32; - fn number_of_rva_and_sizes(&self) -> u32; -} - -impl ImageNtHeaders for pe::ImageNtHeaders32 { - type ImageOptionalHeader = pe::ImageOptionalHeader32; - type ImageThunkData = pe::ImageThunkData32; - - #[inline] - fn is_type_64(&self) -> bool { - false - } - - #[inline] - fn is_valid_optional_magic(&self) -> bool { - self.optional_header.magic.get(LE) == pe::IMAGE_NT_OPTIONAL_HDR32_MAGIC - } - - #[inline] - fn signature(&self) -> u32 { - self.signature.get(LE) - } - - #[inline] - fn file_header(&self) -> &pe::ImageFileHeader { - &self.file_header - } - - #[inline] - fn optional_header(&self) -> &Self::ImageOptionalHeader { - &self.optional_header - } -} - -impl ImageOptionalHeader for pe::ImageOptionalHeader32 { - #[inline] - fn magic(&self) -> u16 { - self.magic.get(LE) - } - - #[inline] - fn major_linker_version(&self) -> u8 { - self.major_linker_version - } - - #[inline] - fn minor_linker_version(&self) -> u8 { - self.minor_linker_version - } - - #[inline] - fn size_of_code(&self) -> u32 { - self.size_of_code.get(LE) - } - - #[inline] - fn size_of_initialized_data(&self) -> u32 { - self.size_of_initialized_data.get(LE) - } - - #[inline] - fn size_of_uninitialized_data(&self) -> u32 { - self.size_of_uninitialized_data.get(LE) - } - - #[inline] - fn address_of_entry_point(&self) -> u32 { - self.address_of_entry_point.get(LE) - } - - #[inline] - fn base_of_code(&self) -> u32 { - self.base_of_code.get(LE) - } - - #[inline] - fn base_of_data(&self) -> Option<u32> { - Some(self.base_of_data.get(LE)) - } - - #[inline] - fn image_base(&self) -> u64 { - self.image_base.get(LE).into() - } - - #[inline] - fn section_alignment(&self) -> u32 { - self.section_alignment.get(LE) - } - - #[inline] - fn file_alignment(&self) -> u32 { - self.file_alignment.get(LE) - } - - #[inline] - fn major_operating_system_version(&self) -> u16 { - self.major_operating_system_version.get(LE) - } - - #[inline] - fn minor_operating_system_version(&self) -> u16 { - self.minor_operating_system_version.get(LE) - } - - #[inline] - fn major_image_version(&self) -> u16 { - self.major_image_version.get(LE) - } - - #[inline] - fn minor_image_version(&self) -> u16 { - self.minor_image_version.get(LE) - } - - #[inline] - fn major_subsystem_version(&self) -> u16 { - self.major_subsystem_version.get(LE) - } - - #[inline] - fn minor_subsystem_version(&self) -> u16 { - self.minor_subsystem_version.get(LE) - } - - #[inline] - fn win32_version_value(&self) -> u32 { - self.win32_version_value.get(LE) - } - - #[inline] - fn size_of_image(&self) -> u32 { - self.size_of_image.get(LE) - } - - #[inline] - fn size_of_headers(&self) -> u32 { - self.size_of_headers.get(LE) - } - - #[inline] - fn check_sum(&self) -> u32 { - self.check_sum.get(LE) - } - - #[inline] - fn subsystem(&self) -> u16 { - self.subsystem.get(LE) - } - - #[inline] - fn dll_characteristics(&self) -> u16 { - self.dll_characteristics.get(LE) - } - - #[inline] - fn size_of_stack_reserve(&self) -> u64 { - self.size_of_stack_reserve.get(LE).into() - } - - #[inline] - fn size_of_stack_commit(&self) -> u64 { - self.size_of_stack_commit.get(LE).into() - } - - #[inline] - fn size_of_heap_reserve(&self) -> u64 { - self.size_of_heap_reserve.get(LE).into() - } - - #[inline] - fn size_of_heap_commit(&self) -> u64 { - self.size_of_heap_commit.get(LE).into() - } - - #[inline] - fn loader_flags(&self) -> u32 { - self.loader_flags.get(LE) - } - - #[inline] - fn number_of_rva_and_sizes(&self) -> u32 { - self.number_of_rva_and_sizes.get(LE) - } -} - -impl ImageNtHeaders for pe::ImageNtHeaders64 { - type ImageOptionalHeader = pe::ImageOptionalHeader64; - type ImageThunkData = pe::ImageThunkData64; - - #[inline] - fn is_type_64(&self) -> bool { - true - } - - #[inline] - fn is_valid_optional_magic(&self) -> bool { - self.optional_header.magic.get(LE) == pe::IMAGE_NT_OPTIONAL_HDR64_MAGIC - } - - #[inline] - fn signature(&self) -> u32 { - self.signature.get(LE) - } - - #[inline] - fn file_header(&self) -> &pe::ImageFileHeader { - &self.file_header - } - - #[inline] - fn optional_header(&self) -> &Self::ImageOptionalHeader { - &self.optional_header - } -} - -impl ImageOptionalHeader for pe::ImageOptionalHeader64 { - #[inline] - fn magic(&self) -> u16 { - self.magic.get(LE) - } - - #[inline] - fn major_linker_version(&self) -> u8 { - self.major_linker_version - } - - #[inline] - fn minor_linker_version(&self) -> u8 { - self.minor_linker_version - } - - #[inline] - fn size_of_code(&self) -> u32 { - self.size_of_code.get(LE) - } - - #[inline] - fn size_of_initialized_data(&self) -> u32 { - self.size_of_initialized_data.get(LE) - } - - #[inline] - fn size_of_uninitialized_data(&self) -> u32 { - self.size_of_uninitialized_data.get(LE) - } - - #[inline] - fn address_of_entry_point(&self) -> u32 { - self.address_of_entry_point.get(LE) - } - - #[inline] - fn base_of_code(&self) -> u32 { - self.base_of_code.get(LE) - } - - #[inline] - fn base_of_data(&self) -> Option<u32> { - None - } - - #[inline] - fn image_base(&self) -> u64 { - self.image_base.get(LE) - } - - #[inline] - fn section_alignment(&self) -> u32 { - self.section_alignment.get(LE) - } - - #[inline] - fn file_alignment(&self) -> u32 { - self.file_alignment.get(LE) - } - - #[inline] - fn major_operating_system_version(&self) -> u16 { - self.major_operating_system_version.get(LE) - } - - #[inline] - fn minor_operating_system_version(&self) -> u16 { - self.minor_operating_system_version.get(LE) - } - - #[inline] - fn major_image_version(&self) -> u16 { - self.major_image_version.get(LE) - } - - #[inline] - fn minor_image_version(&self) -> u16 { - self.minor_image_version.get(LE) - } - - #[inline] - fn major_subsystem_version(&self) -> u16 { - self.major_subsystem_version.get(LE) - } - - #[inline] - fn minor_subsystem_version(&self) -> u16 { - self.minor_subsystem_version.get(LE) - } - - #[inline] - fn win32_version_value(&self) -> u32 { - self.win32_version_value.get(LE) - } - - #[inline] - fn size_of_image(&self) -> u32 { - self.size_of_image.get(LE) - } - - #[inline] - fn size_of_headers(&self) -> u32 { - self.size_of_headers.get(LE) - } - - #[inline] - fn check_sum(&self) -> u32 { - self.check_sum.get(LE) - } - - #[inline] - fn subsystem(&self) -> u16 { - self.subsystem.get(LE) - } - - #[inline] - fn dll_characteristics(&self) -> u16 { - self.dll_characteristics.get(LE) - } - - #[inline] - fn size_of_stack_reserve(&self) -> u64 { - self.size_of_stack_reserve.get(LE) - } - - #[inline] - fn size_of_stack_commit(&self) -> u64 { - self.size_of_stack_commit.get(LE) - } - - #[inline] - fn size_of_heap_reserve(&self) -> u64 { - self.size_of_heap_reserve.get(LE) - } - - #[inline] - fn size_of_heap_commit(&self) -> u64 { - self.size_of_heap_commit.get(LE) - } - - #[inline] - fn loader_flags(&self) -> u32 { - self.loader_flags.get(LE) - } - - #[inline] - fn number_of_rva_and_sizes(&self) -> u32 { - self.number_of_rva_and_sizes.get(LE) - } -} diff --git a/vendor/object/src/read/pe/import.rs b/vendor/object/src/read/pe/import.rs deleted file mode 100644 index 8e9a9a9..0000000 --- a/vendor/object/src/read/pe/import.rs +++ /dev/null @@ -1,337 +0,0 @@ -use core::fmt::Debug; -use core::mem; - -use crate::read::{Bytes, ReadError, Result}; -use crate::{pe, LittleEndian as LE, Pod, U16Bytes}; - -use super::ImageNtHeaders; - -/// Information for parsing a PE import table. -/// -/// Returned by [`DataDirectories::import_table`](super::DataDirectories::import_table). -#[derive(Debug, Clone)] -pub struct ImportTable<'data> { - section_data: Bytes<'data>, - section_address: u32, - import_address: u32, -} - -impl<'data> ImportTable<'data> { - /// Create a new import table parser. - /// - /// The import descriptors start at `import_address`. - /// The size declared in the `IMAGE_DIRECTORY_ENTRY_IMPORT` data directory is - /// ignored by the Windows loader, and so descriptors will be parsed until a null entry. - /// - /// `section_data` should be from the section containing `import_address`, and - /// `section_address` should be the address of that section. Pointers within the - /// descriptors and thunks may point to anywhere within the section data. - pub fn new(section_data: &'data [u8], section_address: u32, import_address: u32) -> Self { - ImportTable { - section_data: Bytes(section_data), - section_address, - import_address, - } - } - - /// Return an iterator for the import descriptors. - pub fn descriptors(&self) -> Result<ImportDescriptorIterator<'data>> { - let offset = self.import_address.wrapping_sub(self.section_address); - let mut data = self.section_data; - data.skip(offset as usize) - .read_error("Invalid PE import descriptor address")?; - Ok(ImportDescriptorIterator { data }) - } - - /// Return a library name given its address. - /// - /// This address may be from [`pe::ImageImportDescriptor::name`]. - pub fn name(&self, address: u32) -> Result<&'data [u8]> { - self.section_data - .read_string_at(address.wrapping_sub(self.section_address) as usize) - .read_error("Invalid PE import descriptor name") - } - - /// Return a list of thunks given its address. - /// - /// This address may be from [`pe::ImageImportDescriptor::original_first_thunk`] - /// or [`pe::ImageImportDescriptor::first_thunk`]. - pub fn thunks(&self, address: u32) -> Result<ImportThunkList<'data>> { - let offset = address.wrapping_sub(self.section_address); - let mut data = self.section_data; - data.skip(offset as usize) - .read_error("Invalid PE import thunk table address")?; - Ok(ImportThunkList { data }) - } - - /// Parse a thunk. - pub fn import<Pe: ImageNtHeaders>(&self, thunk: Pe::ImageThunkData) -> Result<Import<'data>> { - if thunk.is_ordinal() { - Ok(Import::Ordinal(thunk.ordinal())) - } else { - let (hint, name) = self.hint_name(thunk.address())?; - Ok(Import::Name(hint, name)) - } - } - - /// Return the hint and name at the given address. - /// - /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`]. - /// - /// The hint is an index into the export name pointer table in the target library. - pub fn hint_name(&self, address: u32) -> Result<(u16, &'data [u8])> { - let offset = address.wrapping_sub(self.section_address); - let mut data = self.section_data; - data.skip(offset as usize) - .read_error("Invalid PE import thunk address")?; - let hint = data - .read::<U16Bytes<LE>>() - .read_error("Missing PE import thunk hint")? - .get(LE); - let name = data - .read_string() - .read_error("Missing PE import thunk name")?; - Ok((hint, name)) - } -} - -/// A fallible iterator for the descriptors in the import data directory. -#[derive(Debug, Clone)] -pub struct ImportDescriptorIterator<'data> { - data: Bytes<'data>, -} - -impl<'data> ImportDescriptorIterator<'data> { - /// Return the next descriptor. - /// - /// Returns `Ok(None)` when a null descriptor is found. - pub fn next(&mut self) -> Result<Option<&'data pe::ImageImportDescriptor>> { - let import_desc = self - .data - .read::<pe::ImageImportDescriptor>() - .read_error("Missing PE null import descriptor")?; - if import_desc.is_null() { - Ok(None) - } else { - Ok(Some(import_desc)) - } - } -} - -/// A list of import thunks. -/// -/// These may be in the import lookup table, or the import address table. -#[derive(Debug, Clone)] -pub struct ImportThunkList<'data> { - data: Bytes<'data>, -} - -impl<'data> ImportThunkList<'data> { - /// Get the thunk at the given index. - pub fn get<Pe: ImageNtHeaders>(&self, index: usize) -> Result<Pe::ImageThunkData> { - let thunk = self - .data - .read_at(index * mem::size_of::<Pe::ImageThunkData>()) - .read_error("Invalid PE import thunk index")?; - Ok(*thunk) - } - - /// Return the first thunk in the list, and update `self` to point after it. - /// - /// Returns `Ok(None)` when a null thunk is found. - pub fn next<Pe: ImageNtHeaders>(&mut self) -> Result<Option<Pe::ImageThunkData>> { - let thunk = self - .data - .read::<Pe::ImageThunkData>() - .read_error("Missing PE null import thunk")?; - if thunk.address() == 0 { - Ok(None) - } else { - Ok(Some(*thunk)) - } - } -} - -/// A parsed import thunk. -#[derive(Debug, Clone, Copy)] -pub enum Import<'data> { - /// Import by ordinal. - Ordinal(u16), - /// Import by name. - /// - /// Includes a hint for the index into the export name pointer table in the target library. - Name(u16, &'data [u8]), -} - -/// A trait for generic access to [`pe::ImageThunkData32`] and [`pe::ImageThunkData64`]. -#[allow(missing_docs)] -pub trait ImageThunkData: Debug + Pod { - /// Return the raw thunk value. - fn raw(self) -> u64; - - /// Returns true if the ordinal flag is set. - fn is_ordinal(self) -> bool; - - /// Return the ordinal portion of the thunk. - /// - /// Does not check the ordinal flag. - fn ordinal(self) -> u16; - - /// Return the RVA portion of the thunk. - /// - /// Does not check the ordinal flag. - fn address(self) -> u32; -} - -impl ImageThunkData for pe::ImageThunkData64 { - fn raw(self) -> u64 { - self.0.get(LE) - } - - fn is_ordinal(self) -> bool { - self.0.get(LE) & pe::IMAGE_ORDINAL_FLAG64 != 0 - } - - fn ordinal(self) -> u16 { - self.0.get(LE) as u16 - } - - fn address(self) -> u32 { - self.0.get(LE) as u32 & 0x7fff_ffff - } -} - -impl ImageThunkData for pe::ImageThunkData32 { - fn raw(self) -> u64 { - self.0.get(LE).into() - } - - fn is_ordinal(self) -> bool { - self.0.get(LE) & pe::IMAGE_ORDINAL_FLAG32 != 0 - } - - fn ordinal(self) -> u16 { - self.0.get(LE) as u16 - } - - fn address(self) -> u32 { - self.0.get(LE) & 0x7fff_ffff - } -} - -/// Information for parsing a PE delay-load import table. -/// -/// Returned by -/// [`DataDirectories::delay_load_import_table`](super::DataDirectories::delay_load_import_table). -#[derive(Debug, Clone)] -pub struct DelayLoadImportTable<'data> { - section_data: Bytes<'data>, - section_address: u32, - import_address: u32, -} - -impl<'data> DelayLoadImportTable<'data> { - /// Create a new delay load import table parser. - /// - /// The import descriptors start at `import_address`. - /// This table works in the same way the import table does: descriptors will be - /// parsed until a null entry. - /// - /// `section_data` should be from the section containing `import_address`, and - /// `section_address` should be the address of that section. Pointers within the - /// descriptors and thunks may point to anywhere within the section data. - pub fn new(section_data: &'data [u8], section_address: u32, import_address: u32) -> Self { - DelayLoadImportTable { - section_data: Bytes(section_data), - section_address, - import_address, - } - } - - /// Return an iterator for the import descriptors. - pub fn descriptors(&self) -> Result<DelayLoadDescriptorIterator<'data>> { - let offset = self.import_address.wrapping_sub(self.section_address); - let mut data = self.section_data; - data.skip(offset as usize) - .read_error("Invalid PE delay-load import descriptor address")?; - Ok(DelayLoadDescriptorIterator { data }) - } - - /// Return a library name given its address. - /// - /// This address may be from [`pe::ImageDelayloadDescriptor::dll_name_rva`]. - pub fn name(&self, address: u32) -> Result<&'data [u8]> { - self.section_data - .read_string_at(address.wrapping_sub(self.section_address) as usize) - .read_error("Invalid PE import descriptor name") - } - - /// Return a list of thunks given its address. - /// - /// This address may be from the INT, i.e. from - /// [`pe::ImageDelayloadDescriptor::import_name_table_rva`]. - /// - /// Please note that others RVA values from [`pe::ImageDelayloadDescriptor`] are used - /// by the delay loader at runtime to store values, and thus do not point inside the same - /// section as the INT. Calling this function on those addresses will fail. - pub fn thunks(&self, address: u32) -> Result<ImportThunkList<'data>> { - let offset = address.wrapping_sub(self.section_address); - let mut data = self.section_data; - data.skip(offset as usize) - .read_error("Invalid PE delay load import thunk table address")?; - Ok(ImportThunkList { data }) - } - - /// Parse a thunk. - pub fn import<Pe: ImageNtHeaders>(&self, thunk: Pe::ImageThunkData) -> Result<Import<'data>> { - if thunk.is_ordinal() { - Ok(Import::Ordinal(thunk.ordinal())) - } else { - let (hint, name) = self.hint_name(thunk.address())?; - Ok(Import::Name(hint, name)) - } - } - - /// Return the hint and name at the given address. - /// - /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`]. - /// - /// The hint is an index into the export name pointer table in the target library. - pub fn hint_name(&self, address: u32) -> Result<(u16, &'data [u8])> { - let offset = address.wrapping_sub(self.section_address); - let mut data = self.section_data; - data.skip(offset as usize) - .read_error("Invalid PE delay load import thunk address")?; - let hint = data - .read::<U16Bytes<LE>>() - .read_error("Missing PE delay load import thunk hint")? - .get(LE); - let name = data - .read_string() - .read_error("Missing PE delay load import thunk name")?; - Ok((hint, name)) - } -} - -/// A fallible iterator for the descriptors in the delay-load data directory. -#[derive(Debug, Clone)] -pub struct DelayLoadDescriptorIterator<'data> { - data: Bytes<'data>, -} - -impl<'data> DelayLoadDescriptorIterator<'data> { - /// Return the next descriptor. - /// - /// Returns `Ok(None)` when a null descriptor is found. - pub fn next(&mut self) -> Result<Option<&'data pe::ImageDelayloadDescriptor>> { - let import_desc = self - .data - .read::<pe::ImageDelayloadDescriptor>() - .read_error("Missing PE null delay-load import descriptor")?; - if import_desc.is_null() { - Ok(None) - } else { - Ok(Some(import_desc)) - } - } -} diff --git a/vendor/object/src/read/pe/mod.rs b/vendor/object/src/read/pe/mod.rs deleted file mode 100644 index ab6011c..0000000 --- a/vendor/object/src/read/pe/mod.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Support for reading PE files. -//! -//! Traits are used to abstract over the difference between PE32 and PE32+. -//! The primary trait for this is [`ImageNtHeaders`]. -//! -//! ## High level API -//! -//! [`PeFile`] implements the [`Object`](crate::read::Object) trait for -//! PE files. [`PeFile`] is parameterised by [`ImageNtHeaders`] to allow -//! reading both PE32 and PE32+. There are type aliases for these parameters -//! ([`PeFile32`] and [`PeFile64`]). -//! -//! ## Low level API -//! -//! The [`ImageNtHeaders`] trait can be directly used to parse both -//! [`pe::ImageNtHeaders32`] and [`pe::ImageNtHeaders64`]. -//! -//! ### Example for low level API -//! ```no_run -//! use object::pe; -//! use object::read::pe::ImageNtHeaders; -//! use std::error::Error; -//! use std::fs; -//! -//! /// Reads a file and displays the name of each section. -//! fn main() -> Result<(), Box<dyn Error>> { -//! # #[cfg(feature = "std")] { -//! let data = fs::read("path/to/binary")?; -//! let dos_header = pe::ImageDosHeader::parse(&*data)?; -//! let mut offset = dos_header.nt_headers_offset().into(); -//! let (nt_headers, data_directories) = pe::ImageNtHeaders64::parse(&*data, &mut offset)?; -//! let sections = nt_headers.sections(&*data, offset)?; -//! let symbols = nt_headers.symbols(&*data)?; -//! for section in sections.iter() { -//! println!("{}", String::from_utf8_lossy(section.name(symbols.strings())?)); -//! } -//! # } -//! Ok(()) -//! } -//! ``` -#[cfg(doc)] -use crate::pe; - -mod file; -pub use file::*; - -mod section; -pub use section::*; - -mod data_directory; -pub use data_directory::*; - -mod export; -pub use export::*; - -mod import; -pub use import::*; - -mod relocation; -pub use relocation::*; - -mod resource; -pub use resource::*; - -mod rich; -pub use rich::*; - -pub use super::coff::{SectionTable, SymbolTable}; diff --git a/vendor/object/src/read/pe/relocation.rs b/vendor/object/src/read/pe/relocation.rs deleted file mode 100644 index 77421b7..0000000 --- a/vendor/object/src/read/pe/relocation.rs +++ /dev/null @@ -1,92 +0,0 @@ -use core::slice; - -use crate::endian::{LittleEndian as LE, U16}; -use crate::pe; -use crate::read::{Bytes, Error, ReadError, Result}; - -/// An iterator over the relocation blocks in the `.reloc` section of a PE file. -/// -/// Returned by [`DataDirectories::relocation_blocks`](super::DataDirectories::relocation_blocks). -#[derive(Debug, Default, Clone, Copy)] -pub struct RelocationBlockIterator<'data> { - data: Bytes<'data>, -} - -impl<'data> RelocationBlockIterator<'data> { - /// Construct a new iterator from the data of the `.reloc` section. - pub fn new(data: &'data [u8]) -> Self { - RelocationBlockIterator { data: Bytes(data) } - } - - /// Read the next relocation page. - pub fn next(&mut self) -> Result<Option<RelocationIterator<'data>>> { - if self.data.is_empty() { - return Ok(None); - } - let header = self - .data - .read::<pe::ImageBaseRelocation>() - .read_error("Invalid PE reloc section size")?; - let virtual_address = header.virtual_address.get(LE); - let size = header.size_of_block.get(LE); - if size <= 8 || size & 3 != 0 { - return Err(Error("Invalid PE reloc block size")); - } - let count = (size - 8) / 2; - let relocs = self - .data - .read_slice::<U16<LE>>(count as usize) - .read_error("Invalid PE reloc block size")? - .iter(); - Ok(Some(RelocationIterator { - virtual_address, - size, - relocs, - })) - } -} - -/// An iterator of the relocations in a block in the `.reloc` section of a PE file. -#[derive(Debug, Clone)] -pub struct RelocationIterator<'data> { - virtual_address: u32, - size: u32, - relocs: slice::Iter<'data, U16<LE>>, -} - -impl<'data> RelocationIterator<'data> { - /// Return the virtual address of the page that this block of relocations applies to. - pub fn virtual_address(&self) -> u32 { - self.virtual_address - } - - /// Return the size in bytes of this block of relocations. - pub fn size(&self) -> u32 { - self.size - } -} - -impl<'data> Iterator for RelocationIterator<'data> { - type Item = Relocation; - - fn next(&mut self) -> Option<Relocation> { - loop { - let reloc = self.relocs.next()?.get(LE); - if reloc != 0 { - return Some(Relocation { - virtual_address: self.virtual_address.wrapping_add((reloc & 0xfff) as u32), - typ: reloc >> 12, - }); - } - } - } -} - -/// A relocation in the `.reloc` section of a PE file. -#[derive(Debug, Default, Clone, Copy)] -pub struct Relocation { - /// The virtual address of the relocation. - pub virtual_address: u32, - /// One of the `pe::IMAGE_REL_BASED_*` constants. - pub typ: u16, -} diff --git a/vendor/object/src/read/pe/resource.rs b/vendor/object/src/read/pe/resource.rs deleted file mode 100644 index 331da3f..0000000 --- a/vendor/object/src/read/pe/resource.rs +++ /dev/null @@ -1,209 +0,0 @@ -use alloc::string::String; -use core::char; - -use crate::read::{ReadError, ReadRef, Result}; -use crate::{pe, LittleEndian as LE, U16Bytes}; - -/// The `.rsrc` section of a PE file. -/// -/// Returned by [`DataDirectories::resource_directory`](super::DataDirectories::resource_directory). -#[derive(Debug, Clone, Copy)] -pub struct ResourceDirectory<'data> { - data: &'data [u8], -} - -impl<'data> ResourceDirectory<'data> { - /// Construct from the data of the `.rsrc` section. - pub fn new(data: &'data [u8]) -> Self { - ResourceDirectory { data } - } - - /// Parses the root resource directory. - pub fn root(&self) -> Result<ResourceDirectoryTable<'data>> { - ResourceDirectoryTable::parse(self.data, 0) - } -} - -/// A table of resource entries. -#[derive(Debug, Clone)] -pub struct ResourceDirectoryTable<'data> { - /// The table header. - pub header: &'data pe::ImageResourceDirectory, - /// The table entries. - pub entries: &'data [pe::ImageResourceDirectoryEntry], -} - -impl<'data> ResourceDirectoryTable<'data> { - fn parse(data: &'data [u8], offset: u32) -> Result<Self> { - let mut offset = u64::from(offset); - let header = data - .read::<pe::ImageResourceDirectory>(&mut offset) - .read_error("Invalid resource table header")?; - let entries_count = header.number_of_id_entries.get(LE) as usize - + header.number_of_named_entries.get(LE) as usize; - let entries = data - .read_slice::<pe::ImageResourceDirectoryEntry>(&mut offset, entries_count) - .read_error("Invalid resource table entries")?; - Ok(Self { header, entries }) - } -} - -impl pe::ImageResourceDirectoryEntry { - /// Returns true if the entry has a name, rather than an ID. - pub fn has_name(&self) -> bool { - self.name_or_id.get(LE) & pe::IMAGE_RESOURCE_NAME_IS_STRING != 0 - } - - /// Returns the section offset of the name. - /// - /// Valid if `has_name()` returns true. - fn name(&self) -> ResourceName { - let offset = self.name_or_id.get(LE) & !pe::IMAGE_RESOURCE_NAME_IS_STRING; - ResourceName { offset } - } - - /// Returns the ID. - /// - /// Valid if `has_string_name()` returns false. - fn id(&self) -> u16 { - (self.name_or_id.get(LE) & 0x0000_FFFF) as u16 - } - - /// Returns the entry name - pub fn name_or_id(&self) -> ResourceNameOrId { - if self.has_name() { - ResourceNameOrId::Name(self.name()) - } else { - ResourceNameOrId::Id(self.id()) - } - } - - /// Returns true if the entry is a subtable. - pub fn is_table(&self) -> bool { - self.offset_to_data_or_directory.get(LE) & pe::IMAGE_RESOURCE_DATA_IS_DIRECTORY != 0 - } - - /// Returns the section offset of the associated table or data. - pub fn data_offset(&self) -> u32 { - self.offset_to_data_or_directory.get(LE) & !pe::IMAGE_RESOURCE_DATA_IS_DIRECTORY - } - - /// Returns the data associated to this directory entry. - pub fn data<'data>( - &self, - section: ResourceDirectory<'data>, - ) -> Result<ResourceDirectoryEntryData<'data>> { - if self.is_table() { - ResourceDirectoryTable::parse(section.data, self.data_offset()) - .map(ResourceDirectoryEntryData::Table) - } else { - section - .data - .read_at::<pe::ImageResourceDataEntry>(self.data_offset().into()) - .read_error("Invalid resource entry") - .map(ResourceDirectoryEntryData::Data) - } - } -} - -/// Data associated with a resource directory entry. -#[derive(Debug, Clone)] -pub enum ResourceDirectoryEntryData<'data> { - /// A subtable entry. - Table(ResourceDirectoryTable<'data>), - /// A resource data entry. - Data(&'data pe::ImageResourceDataEntry), -} - -impl<'data> ResourceDirectoryEntryData<'data> { - /// Converts to an option of table. - /// - /// Helper for iterator filtering. - pub fn table(self) -> Option<ResourceDirectoryTable<'data>> { - match self { - Self::Table(dir) => Some(dir), - _ => None, - } - } - - /// Converts to an option of data entry. - /// - /// Helper for iterator filtering. - pub fn data(self) -> Option<&'data pe::ImageResourceDataEntry> { - match self { - Self::Data(rsc) => Some(rsc), - _ => None, - } - } -} - -/// A resource name. -#[derive(Debug, Clone, Copy)] -pub struct ResourceName { - offset: u32, -} - -impl ResourceName { - /// Converts to a `String`. - pub fn to_string_lossy(&self, directory: ResourceDirectory<'_>) -> Result<String> { - let d = self.data(directory)?.iter().map(|c| c.get(LE)); - - Ok(char::decode_utf16(d) - .map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER)) - .collect::<String>()) - } - - /// Returns the string unicode buffer. - pub fn data<'data>( - &self, - directory: ResourceDirectory<'data>, - ) -> Result<&'data [U16Bytes<LE>]> { - let mut offset = u64::from(self.offset); - let len = directory - .data - .read::<U16Bytes<LE>>(&mut offset) - .read_error("Invalid resource name offset")?; - directory - .data - .read_slice::<U16Bytes<LE>>(&mut offset, len.get(LE).into()) - .read_error("Invalid resource name length") - } - - /// Returns the string buffer as raw bytes. - pub fn raw_data<'data>(&self, directory: ResourceDirectory<'data>) -> Result<&'data [u8]> { - self.data(directory).map(crate::pod::bytes_of_slice) - } -} - -/// A resource name or ID. -/// -/// Can be either a string or a numeric ID. -#[derive(Debug)] -pub enum ResourceNameOrId { - /// A resource name. - Name(ResourceName), - /// A resource ID. - Id(u16), -} - -impl ResourceNameOrId { - /// Converts to an option of name. - /// - /// Helper for iterator filtering. - pub fn name(self) -> Option<ResourceName> { - match self { - Self::Name(name) => Some(name), - _ => None, - } - } - - /// Converts to an option of ID. - /// - /// Helper for iterator filtering. - pub fn id(self) -> Option<u16> { - match self { - Self::Id(id) => Some(id), - _ => None, - } - } -} diff --git a/vendor/object/src/read/pe/rich.rs b/vendor/object/src/read/pe/rich.rs deleted file mode 100644 index 33dd039..0000000 --- a/vendor/object/src/read/pe/rich.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! PE rich header handling - -use core::mem; - -use crate::pod::bytes_of_slice; -use crate::read::Bytes; -use crate::{pe, LittleEndian as LE, ReadRef, U32}; - -/// Parsed information about a Rich Header. -#[derive(Debug, Clone, Copy)] -pub struct RichHeaderInfo<'data> { - /// The offset at which the rich header starts. - pub offset: usize, - /// The length (in bytes) of the rich header. - /// - /// This includes the payload, but also the 16-byte start sequence and the - /// 8-byte final "Rich" and XOR key. - pub length: usize, - /// The XOR key used to mask the rich header. - /// - /// Unless the file has been tampered with, it should be equal to a checksum - /// of the file header. - pub xor_key: u32, - masked_entries: &'data [pe::MaskedRichHeaderEntry], -} - -/// A PE rich header entry after it has been unmasked. -/// -/// See [`pe::MaskedRichHeaderEntry`]. -#[derive(Debug, Clone, Copy)] -#[repr(C)] -pub struct RichHeaderEntry { - /// ID of the component. - pub comp_id: u32, - /// Number of times this component has been used when building this PE. - pub count: u32, -} - -impl<'data> RichHeaderInfo<'data> { - /// Try to locate a rich header and its entries in the current PE file. - pub fn parse<R: ReadRef<'data>>(data: R, nt_header_offset: u64) -> Option<Self> { - // Locate the rich header, if any. - // It ends with the "Rich" string and an XOR key, before the NT header. - let data = data.read_bytes_at(0, nt_header_offset).map(Bytes).ok()?; - let end_marker_offset = memmem(data.0, b"Rich", 4)?; - let xor_key = *data.read_at::<U32<LE>>(end_marker_offset + 4).ok()?; - - // It starts at the masked "DanS" string and 3 masked zeroes. - let masked_start_marker = U32::new(LE, 0x536e_6144 ^ xor_key.get(LE)); - let start_header = [masked_start_marker, xor_key, xor_key, xor_key]; - let start_sequence = bytes_of_slice(&start_header); - let start_marker_offset = memmem(&data.0[..end_marker_offset], start_sequence, 4)?; - - // Extract the items between the markers. - let items_offset = start_marker_offset + start_sequence.len(); - let items_len = end_marker_offset - items_offset; - let item_count = items_len / mem::size_of::<pe::MaskedRichHeaderEntry>(); - let items = data.read_slice_at(items_offset, item_count).ok()?; - Some(RichHeaderInfo { - offset: start_marker_offset, - // Includes "Rich" marker and the XOR key. - length: end_marker_offset - start_marker_offset + 8, - xor_key: xor_key.get(LE), - masked_entries: items, - }) - } - - /// Returns an iterator over the unmasked entries. - pub fn unmasked_entries(&self) -> impl Iterator<Item = RichHeaderEntry> + 'data { - let xor_key = self.xor_key; - self.masked_entries - .iter() - .map(move |entry| RichHeaderEntry { - comp_id: entry.masked_comp_id.get(LE) ^ xor_key, - count: entry.masked_count.get(LE) ^ xor_key, - }) - } -} - -/// Find the offset of the first occurrence of needle in the data. -/// -/// The offset must have the given alignment. -fn memmem(data: &[u8], needle: &[u8], align: usize) -> Option<usize> { - let mut offset = 0; - loop { - if data.get(offset..)?.get(..needle.len())? == needle { - return Some(offset); - } - offset += align; - } -} diff --git a/vendor/object/src/read/pe/section.rs b/vendor/object/src/read/pe/section.rs deleted file mode 100644 index 74c9d7f..0000000 --- a/vendor/object/src/read/pe/section.rs +++ /dev/null @@ -1,440 +0,0 @@ -use core::marker::PhantomData; -use core::{cmp, iter, slice, str}; - -use crate::endian::LittleEndian as LE; -use crate::pe; -use crate::pe::ImageSectionHeader; -use crate::read::{ - self, CompressedData, CompressedFileRange, ObjectSection, ObjectSegment, ReadError, ReadRef, - Relocation, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags, -}; - -use super::{ImageNtHeaders, PeFile, SectionTable}; - -/// An iterator for the loadable sections in a [`PeFile32`](super::PeFile32). -pub type PeSegmentIterator32<'data, 'file, R = &'data [u8]> = - PeSegmentIterator<'data, 'file, pe::ImageNtHeaders32, R>; -/// An iterator for the loadable sections in a [`PeFile64`](super::PeFile64). -pub type PeSegmentIterator64<'data, 'file, R = &'data [u8]> = - PeSegmentIterator<'data, 'file, pe::ImageNtHeaders64, R>; - -/// An iterator for the loadable sections in a [`PeFile`]. -#[derive(Debug)] -pub struct PeSegmentIterator<'data, 'file, Pe, R = &'data [u8]> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ - pub(super) file: &'file PeFile<'data, Pe, R>, - pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>, -} - -impl<'data, 'file, Pe, R> Iterator for PeSegmentIterator<'data, 'file, Pe, R> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ - type Item = PeSegment<'data, 'file, Pe, R>; - - fn next(&mut self) -> Option<Self::Item> { - self.iter.next().map(|section| PeSegment { - file: self.file, - section, - }) - } -} - -/// A loadable section in a [`PeFile32`](super::PeFile32). -pub type PeSegment32<'data, 'file, R = &'data [u8]> = - PeSegment<'data, 'file, pe::ImageNtHeaders32, R>; -/// A loadable section in a [`PeFile64`](super::PeFile64). -pub type PeSegment64<'data, 'file, R = &'data [u8]> = - PeSegment<'data, 'file, pe::ImageNtHeaders64, R>; - -/// A loadable section in a [`PeFile`]. -/// -/// Most functionality is provided by the [`ObjectSegment`] trait implementation. -#[derive(Debug)] -pub struct PeSegment<'data, 'file, Pe, R = &'data [u8]> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ - file: &'file PeFile<'data, Pe, R>, - section: &'data pe::ImageSectionHeader, -} - -impl<'data, 'file, Pe, R> read::private::Sealed for PeSegment<'data, 'file, Pe, R> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Pe, R> ObjectSegment<'data> for PeSegment<'data, 'file, Pe, R> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ - #[inline] - fn address(&self) -> u64 { - u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base) - } - - #[inline] - fn size(&self) -> u64 { - u64::from(self.section.virtual_size.get(LE)) - } - - #[inline] - fn align(&self) -> u64 { - self.file.section_alignment() - } - - #[inline] - fn file_range(&self) -> (u64, u64) { - let (offset, size) = self.section.pe_file_range(); - (u64::from(offset), u64::from(size)) - } - - fn data(&self) -> Result<&'data [u8]> { - self.section.pe_data(self.file.data) - } - - fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { - Ok(read::util::data_range( - self.data()?, - self.address(), - address, - size, - )) - } - - #[inline] - fn name_bytes(&self) -> Result<Option<&[u8]>> { - self.section - .name(self.file.common.symbols.strings()) - .map(Some) - } - - #[inline] - fn name(&self) -> Result<Option<&str>> { - let name = self.section.name(self.file.common.symbols.strings())?; - Ok(Some( - str::from_utf8(name) - .ok() - .read_error("Non UTF-8 PE section name")?, - )) - } - - #[inline] - fn flags(&self) -> SegmentFlags { - let characteristics = self.section.characteristics.get(LE); - SegmentFlags::Coff { characteristics } - } -} - -/// An iterator for the sections in a [`PeFile32`](super::PeFile32). -pub type PeSectionIterator32<'data, 'file, R = &'data [u8]> = - PeSectionIterator<'data, 'file, pe::ImageNtHeaders32, R>; -/// An iterator for the sections in a [`PeFile64`](super::PeFile64). -pub type PeSectionIterator64<'data, 'file, R = &'data [u8]> = - PeSectionIterator<'data, 'file, pe::ImageNtHeaders64, R>; - -/// An iterator for the sections in a [`PeFile`]. -#[derive(Debug)] -pub struct PeSectionIterator<'data, 'file, Pe, R = &'data [u8]> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ - pub(super) file: &'file PeFile<'data, Pe, R>, - pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>, -} - -impl<'data, 'file, Pe, R> Iterator for PeSectionIterator<'data, 'file, Pe, R> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ - type Item = PeSection<'data, 'file, Pe, R>; - - fn next(&mut self) -> Option<Self::Item> { - self.iter.next().map(|(index, section)| PeSection { - file: self.file, - index: SectionIndex(index + 1), - section, - }) - } -} - -/// A section in a [`PeFile32`](super::PeFile32). -pub type PeSection32<'data, 'file, R = &'data [u8]> = - PeSection<'data, 'file, pe::ImageNtHeaders32, R>; -/// A section in a [`PeFile64`](super::PeFile64). -pub type PeSection64<'data, 'file, R = &'data [u8]> = - PeSection<'data, 'file, pe::ImageNtHeaders64, R>; - -/// A section in a [`PeFile`]. -/// -/// Most functionality is provided by the [`ObjectSection`] trait implementation. -#[derive(Debug)] -pub struct PeSection<'data, 'file, Pe, R = &'data [u8]> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ - pub(super) file: &'file PeFile<'data, Pe, R>, - pub(super) index: SectionIndex, - pub(super) section: &'data pe::ImageSectionHeader, -} - -impl<'data, 'file, Pe, R> read::private::Sealed for PeSection<'data, 'file, Pe, R> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ -} - -impl<'data, 'file, Pe, R> ObjectSection<'data> for PeSection<'data, 'file, Pe, R> -where - Pe: ImageNtHeaders, - R: ReadRef<'data>, -{ - type RelocationIterator = PeRelocationIterator<'data, 'file, R>; - - #[inline] - fn index(&self) -> SectionIndex { - self.index - } - - #[inline] - fn address(&self) -> u64 { - u64::from(self.section.virtual_address.get(LE)).wrapping_add(self.file.common.image_base) - } - - #[inline] - fn size(&self) -> u64 { - u64::from(self.section.virtual_size.get(LE)) - } - - #[inline] - fn align(&self) -> u64 { - self.file.section_alignment() - } - - #[inline] - fn file_range(&self) -> Option<(u64, u64)> { - let (offset, size) = self.section.pe_file_range(); - if size == 0 { - None - } else { - Some((u64::from(offset), u64::from(size))) - } - } - - fn data(&self) -> Result<&'data [u8]> { - self.section.pe_data(self.file.data) - } - - fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { - Ok(read::util::data_range( - self.data()?, - self.address(), - address, - size, - )) - } - - #[inline] - fn compressed_file_range(&self) -> Result<CompressedFileRange> { - Ok(CompressedFileRange::none(self.file_range())) - } - - #[inline] - fn compressed_data(&self) -> Result<CompressedData<'data>> { - self.data().map(CompressedData::none) - } - - #[inline] - fn name_bytes(&self) -> Result<&[u8]> { - self.section.name(self.file.common.symbols.strings()) - } - - #[inline] - fn name(&self) -> Result<&str> { - let name = self.name_bytes()?; - str::from_utf8(name) - .ok() - .read_error("Non UTF-8 PE section name") - } - - #[inline] - fn segment_name_bytes(&self) -> Result<Option<&[u8]>> { - Ok(None) - } - - #[inline] - fn segment_name(&self) -> Result<Option<&str>> { - Ok(None) - } - - #[inline] - fn kind(&self) -> SectionKind { - self.section.kind() - } - - fn relocations(&self) -> PeRelocationIterator<'data, 'file, R> { - PeRelocationIterator(PhantomData) - } - - fn flags(&self) -> SectionFlags { - SectionFlags::Coff { - characteristics: self.section.characteristics.get(LE), - } - } -} - -impl<'data> SectionTable<'data> { - /// Return the file offset of the given virtual address, and the size up - /// to the end of the section containing it. - /// - /// Returns `None` if no section contains the address. - pub fn pe_file_range_at(&self, va: u32) -> Option<(u32, u32)> { - self.iter().find_map(|section| section.pe_file_range_at(va)) - } - - /// Return the data starting at the given virtual address, up to the end of the - /// section containing it. - /// - /// Ignores sections with invalid data. - /// - /// Returns `None` if no section contains the address. - pub fn pe_data_at<R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> { - self.iter().find_map(|section| section.pe_data_at(data, va)) - } - - /// Return the data of the section that contains the given virtual address in a PE file. - /// - /// Also returns the virtual address of that section. - /// - /// Ignores sections with invalid data. - pub fn pe_data_containing<R: ReadRef<'data>>( - &self, - data: R, - va: u32, - ) -> Option<(&'data [u8], u32)> { - self.iter() - .find_map(|section| section.pe_data_containing(data, va)) - } - - /// Return the section that contains a given virtual address. - pub fn section_containing(&self, va: u32) -> Option<&'data ImageSectionHeader> { - self.iter().find(|section| section.contains_rva(va)) - } -} - -impl pe::ImageSectionHeader { - /// Return the offset and size of the section in a PE file. - /// - /// The size of the range will be the minimum of the file size and virtual size. - pub fn pe_file_range(&self) -> (u32, u32) { - // Pointer and size will be zero for uninitialized data; we don't need to validate this. - let offset = self.pointer_to_raw_data.get(LE); - let size = cmp::min(self.virtual_size.get(LE), self.size_of_raw_data.get(LE)); - (offset, size) - } - - /// Return the file offset of the given virtual address, and the remaining size up - /// to the end of the section. - /// - /// Returns `None` if the section does not contain the address. - pub fn pe_file_range_at(&self, va: u32) -> Option<(u32, u32)> { - let section_va = self.virtual_address.get(LE); - let offset = va.checked_sub(section_va)?; - let (section_offset, section_size) = self.pe_file_range(); - // Address must be within section (and not at its end). - if offset < section_size { - Some((section_offset.checked_add(offset)?, section_size - offset)) - } else { - None - } - } - - /// Return the virtual address and size of the section. - pub fn pe_address_range(&self) -> (u32, u32) { - (self.virtual_address.get(LE), self.virtual_size.get(LE)) - } - - /// Return the section data in a PE file. - /// - /// The length of the data will be the minimum of the file size and virtual size. - pub fn pe_data<'data, R: ReadRef<'data>>(&self, data: R) -> Result<&'data [u8]> { - let (offset, size) = self.pe_file_range(); - data.read_bytes_at(offset.into(), size.into()) - .read_error("Invalid PE section offset or size") - } - - /// Return the data starting at the given virtual address, up to the end of the - /// section. - /// - /// Ignores sections with invalid data. - /// - /// Returns `None` if the section does not contain the address. - pub fn pe_data_at<'data, R: ReadRef<'data>>(&self, data: R, va: u32) -> Option<&'data [u8]> { - let (offset, size) = self.pe_file_range_at(va)?; - data.read_bytes_at(offset.into(), size.into()).ok() - } - - /// Tests whether a given RVA is part of this section - pub fn contains_rva(&self, va: u32) -> bool { - let section_va = self.virtual_address.get(LE); - match va.checked_sub(section_va) { - None => false, - Some(offset) => { - // Address must be within section (and not at its end). - offset < self.virtual_size.get(LE) - } - } - } - - /// Return the section data if it contains the given virtual address. - /// - /// Also returns the virtual address of that section. - /// - /// Ignores sections with invalid data. - pub fn pe_data_containing<'data, R: ReadRef<'data>>( - &self, - data: R, - va: u32, - ) -> Option<(&'data [u8], u32)> { - let section_va = self.virtual_address.get(LE); - let offset = va.checked_sub(section_va)?; - let (section_offset, section_size) = self.pe_file_range(); - // Address must be within section (and not at its end). - if offset < section_size { - let section_data = data - .read_bytes_at(section_offset.into(), section_size.into()) - .ok()?; - Some((section_data, section_va)) - } else { - None - } - } -} - -/// An iterator for the relocations in an [`PeSection`]. -/// -/// This is a stub that doesn't implement any functionality. -#[derive(Debug)] -pub struct PeRelocationIterator<'data, 'file, R = &'data [u8]>( - PhantomData<(&'data (), &'file (), R)>, -); - -impl<'data, 'file, R> Iterator for PeRelocationIterator<'data, 'file, R> { - type Item = (u64, Relocation); - - fn next(&mut self) -> Option<Self::Item> { - None - } -} |