diff options
Diffstat (limited to 'vendor/object/src/read/pe')
-rw-r--r-- | vendor/object/src/read/pe/data_directory.rs | 28 | ||||
-rw-r--r-- | vendor/object/src/read/pe/file.rs | 83 | ||||
-rw-r--r-- | vendor/object/src/read/pe/import.rs | 114 | ||||
-rw-r--r-- | vendor/object/src/read/pe/resource.rs | 30 |
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. |