diff options
Diffstat (limited to 'vendor/object/src/read/pe/export.rs')
-rw-r--r-- | vendor/object/src/read/pe/export.rs | 333 |
1 files changed, 0 insertions, 333 deletions
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) -} |