summaryrefslogtreecommitdiffstats
path: root/vendor/object/src/read/pe
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/object/src/read/pe')
-rw-r--r--vendor/object/src/read/pe/data_directory.rs28
-rw-r--r--vendor/object/src/read/pe/file.rs83
-rw-r--r--vendor/object/src/read/pe/import.rs114
-rw-r--r--vendor/object/src/read/pe/resource.rs30
4 files changed, 209 insertions, 46 deletions
diff --git a/vendor/object/src/read/pe/data_directory.rs b/vendor/object/src/read/pe/data_directory.rs
index 8c1955355..f5d98774e 100644
--- a/vendor/object/src/read/pe/data_directory.rs
+++ b/vendor/object/src/read/pe/data_directory.rs
@@ -3,7 +3,10 @@ use core::slice;
use crate::read::{Error, ReadError, ReadRef, Result};
use crate::{pe, LittleEndian as LE};
-use super::{ExportTable, ImportTable, RelocationBlockIterator, ResourceDirectory, SectionTable};
+use super::{
+ DelayLoadImportTable, ExportTable, ImportTable, RelocationBlockIterator, ResourceDirectory,
+ SectionTable,
+};
/// The table of data directories in a PE file.
#[derive(Debug, Clone, Copy)]
@@ -105,6 +108,29 @@ impl<'data> DataDirectories<'data> {
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.
diff --git a/vendor/object/src/read/pe/file.rs b/vendor/object/src/read/pe/file.rs
index 15b42074a..8dd85131a 100644
--- a/vendor/object/src/read/pe/file.rs
+++ b/vendor/object/src/read/pe/file.rs
@@ -304,49 +304,60 @@ where
None => return Ok(None),
};
let debug_data = data_dir.data(self.data, &self.common.sections).map(Bytes)?;
- let debug_dir = debug_data
- .read_at::<pe::ImageDebugDirectory>(0)
- .read_error("Invalid PE debug dir size")?;
+ let debug_data_size = data_dir.size.get(LE) as usize;
- if debug_dir.typ.get(LE) != pe::IMAGE_DEBUG_TYPE_CODEVIEW {
- return Ok(None);
+ 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 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" {
- return Ok(None);
- }
+ 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 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 age = info.read::<U32<LE>>().read_error("Invalid CodeView Age")?;
- let path = info
- .read_string()
- .read_error("Invalid CodeView file path")?;
+ let path = info
+ .read_string()
+ .read_error("Invalid CodeView file path")?;
- Ok(Some(CodeView {
- path: ByteString(path),
- guid,
- age: age.get(LE),
- }))
+ return Ok(Some(CodeView {
+ path: ByteString(path),
+ guid,
+ age: age.get(LE),
+ }));
+ }
+ Ok(None)
}
fn has_debug_symbols(&self) -> bool {
diff --git a/vendor/object/src/read/pe/import.rs b/vendor/object/src/read/pe/import.rs
index 809a96286..a5535dc36 100644
--- a/vendor/object/src/read/pe/import.rs
+++ b/vendor/object/src/read/pe/import.rs
@@ -216,3 +216,117 @@ impl ImageThunkData for pe::ImageThunkData32 {
self.0.get(LE) & 0x7fff_ffff
}
}
+
+/// Information for parsing a PE 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/resource.rs b/vendor/object/src/read/pe/resource.rs
index bfbb609f5..e667f0d98 100644
--- a/vendor/object/src/read/pe/resource.rs
+++ b/vendor/object/src/read/pe/resource.rs
@@ -1,7 +1,8 @@
use alloc::string::String;
+use core::char;
use crate::read::{ReadError, ReadRef, Result};
-use crate::{pe, LittleEndian as LE, U16};
+use crate::{pe, LittleEndian as LE, U16Bytes};
/// The `.rsrc` section of a PE file.
#[derive(Debug, Clone, Copy)]
@@ -17,7 +18,7 @@ impl<'data> ResourceDirectory<'data> {
/// Parses the root resource directory.
pub fn root(&self) -> Result<ResourceDirectoryTable<'data>> {
- ResourceDirectoryTable::parse(&self.data, 0)
+ ResourceDirectoryTable::parse(self.data, 0)
}
}
@@ -92,13 +93,13 @@ impl pe::ImageResourceDirectoryEntry {
) -> Result<ResourceDirectoryEntryData<'data>> {
if self.is_table() {
ResourceDirectoryTable::parse(section.data, self.data_offset())
- .map(|t| ResourceDirectoryEntryData::Table(t))
+ .map(ResourceDirectoryEntryData::Table)
} else {
section
.data
.read_at::<pe::ImageResourceDataEntry>(self.data_offset().into())
.read_error("Invalid resource entry")
- .map(|d| ResourceDirectoryEntryData::Data(d))
+ .map(ResourceDirectoryEntryData::Data)
}
}
}
@@ -143,22 +144,33 @@ pub struct ResourceName {
impl ResourceName {
/// Converts to a `String`.
pub fn to_string_lossy(&self, directory: ResourceDirectory) -> Result<String> {
- let d = self.data(directory)?;
- Ok(String::from_utf16_lossy(d))
+ 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 [u16]> {
+ pub fn data<'data>(
+ &self,
+ directory: ResourceDirectory<'data>,
+ ) -> Result<&'data [U16Bytes<LE>]> {
let mut offset = u64::from(self.offset);
let len = directory
.data
- .read::<U16<LE>>(&mut offset)
+ .read::<U16Bytes<LE>>(&mut offset)
.read_error("Invalid resource name offset")?;
directory
.data
- .read_slice::<u16>(&mut offset, len.get(LE).into())
+ .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.