4 use crate::read
::{Bytes, ReadError, Result}
;
5 use crate::{pe, LittleEndian as LE, Pod, U16Bytes}
;
7 use super::ImageNtHeaders
;
9 /// Information for parsing a PE import table.
10 #[derive(Debug, Clone)]
11 pub struct ImportTable
<'data
> {
12 section_data
: Bytes
<'data
>,
17 impl<'data
> ImportTable
<'data
> {
18 /// Create a new import table parser.
20 /// The import descriptors start at `import_address`.
21 /// The size declared in the `IMAGE_DIRECTORY_ENTRY_IMPORT` data directory is
22 /// ignored by the Windows loader, and so descriptors will be parsed until a null entry.
24 /// `section_data` should be from the section containing `import_address`, and
25 /// `section_address` should be the address of that section. Pointers within the
26 /// descriptors and thunks may point to anywhere within the section data.
27 pub fn new(section_data
: &'data
[u8], section_address
: u32, import_address
: u32) -> Self {
29 section_data
: Bytes(section_data
),
35 /// Return an iterator for the import descriptors.
36 pub fn descriptors(&self) -> Result
<ImportDescriptorIterator
<'data
>> {
37 let offset
= self.import_address
.wrapping_sub(self.section_address
);
38 let mut data
= self.section_data
;
39 data
.skip(offset
as usize)
40 .read_error("Invalid PE import descriptor address")?
;
41 Ok(ImportDescriptorIterator { data }
)
44 /// Return a library name given its address.
46 /// This address may be from [`pe::ImageImportDescriptor::name`].
47 pub fn name(&self, address
: u32) -> Result
<&'data
[u8]> {
49 .read_string_at(address
.wrapping_sub(self.section_address
) as usize)
50 .read_error("Invalid PE import descriptor name")
53 /// Return a list of thunks given its address.
55 /// This address may be from [`pe::ImageImportDescriptor::original_first_thunk`]
56 /// or [`pe::ImageImportDescriptor::first_thunk`].
57 pub fn thunks(&self, address
: u32) -> Result
<ImportThunkList
<'data
>> {
58 let offset
= address
.wrapping_sub(self.section_address
);
59 let mut data
= self.section_data
;
60 data
.skip(offset
as usize)
61 .read_error("Invalid PE import thunk table address")?
;
62 Ok(ImportThunkList { data }
)
66 pub fn import
<Pe
: ImageNtHeaders
>(&self, thunk
: Pe
::ImageThunkData
) -> Result
<Import
<'data
>> {
67 if thunk
.is_ordinal() {
68 Ok(Import
::Ordinal(thunk
.ordinal()))
70 let (hint
, name
) = self.hint_name(thunk
.address())?
;
71 Ok(Import
::Name(hint
, name
))
75 /// Return the hint and name at the given address.
77 /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`].
79 /// The hint is an index into the export name pointer table in the target library.
80 pub fn hint_name(&self, address
: u32) -> Result
<(u16, &'data
[u8])> {
81 let offset
= address
.wrapping_sub(self.section_address
);
82 let mut data
= self.section_data
;
83 data
.skip(offset
as usize)
84 .read_error("Invalid PE import thunk address")?
;
86 .read
::<U16Bytes
<LE
>>()
87 .read_error("Missing PE import thunk hint")?
91 .read_error("Missing PE import thunk name")?
;
96 /// A fallible iterator for the descriptors in the import data directory.
97 #[derive(Debug, Clone)]
98 pub struct ImportDescriptorIterator
<'data
> {
102 impl<'data
> ImportDescriptorIterator
<'data
> {
103 /// Return the next descriptor.
105 /// Returns `Ok(None)` when a null descriptor is found.
106 pub fn next(&mut self) -> Result
<Option
<&'data pe
::ImageImportDescriptor
>> {
107 let import_desc
= self
109 .read
::<pe
::ImageImportDescriptor
>()
110 .read_error("Missing PE null import descriptor")?
;
111 if import_desc
.is_null() {
114 Ok(Some(import_desc
))
119 /// A list of import thunks.
121 /// These may be in the import lookup table, or the import address table.
122 #[derive(Debug, Clone)]
123 pub struct ImportThunkList
<'data
> {
127 impl<'data
> ImportThunkList
<'data
> {
128 /// Get the thunk at the given index.
129 pub fn get
<Pe
: ImageNtHeaders
>(&self, index
: usize) -> Result
<Pe
::ImageThunkData
> {
132 .read_at(index
* mem
::size_of
::<Pe
::ImageThunkData
>())
133 .read_error("Invalid PE import thunk index")?
;
137 /// Return the first thunk in the list, and update `self` to point after it.
139 /// Returns `Ok(None)` when a null thunk is found.
140 pub fn next
<Pe
: ImageNtHeaders
>(&mut self) -> Result
<Option
<Pe
::ImageThunkData
>> {
143 .read
::<Pe
::ImageThunkData
>()
144 .read_error("Missing PE null import thunk")?
;
145 if thunk
.address() == 0 {
153 /// A parsed import thunk.
154 #[derive(Debug, Clone, Copy)]
155 pub enum Import
<'data
> {
156 /// Import by ordinal.
160 /// Includes a hint for the index into the export name pointer table in the target library.
161 Name(u16, &'data
[u8]),
164 /// A trait for generic access to [`pe::ImageThunkData32`] and [`pe::ImageThunkData64`].
165 #[allow(missing_docs)]
166 pub trait ImageThunkData
: Debug
+ Pod
{
167 /// Return the raw thunk value.
170 /// Returns true if the ordinal flag is set.
171 fn is_ordinal(self) -> bool
;
173 /// Return the ordinal portion of the thunk.
175 /// Does not check the ordinal flag.
176 fn ordinal(self) -> u16;
178 /// Return the RVA portion of the thunk.
180 /// Does not check the ordinal flag.
181 fn address(self) -> u32;
184 impl ImageThunkData
for pe
::ImageThunkData64
{
185 fn raw(self) -> u64 {
189 fn is_ordinal(self) -> bool
{
190 self.0.get(LE
) & pe
::IMAGE_ORDINAL_FLAG64
!= 0
193 fn ordinal(self) -> u16 {
194 self.0.get(LE
) as u16
197 fn address(self) -> u32 {
198 self.0.get(LE
) as u32 & 0x7fff_ffff
202 impl ImageThunkData
for pe
::ImageThunkData32
{
203 fn raw(self) -> u64 {
204 self.0.get(LE
).into()
207 fn is_ordinal(self) -> bool
{
208 self.0.get(LE
) & pe
::IMAGE_ORDINAL_FLAG32
!= 0
211 fn ordinal(self) -> u16 {
212 self.0.get(LE
) as u16
215 fn address(self) -> u32 {
216 self.0.get(LE
) & 0x7fff_ffff
220 /// Information for parsing a PE delay-load import table.
221 #[derive(Debug, Clone)]
222 pub struct DelayLoadImportTable
<'data
> {
223 section_data
: Bytes
<'data
>,
224 section_address
: u32,
228 impl<'data
> DelayLoadImportTable
<'data
> {
229 /// Create a new delay load import table parser.
231 /// The import descriptors start at `import_address`.
232 /// This table works in the same way the import table does: descriptors will be
233 /// parsed until a null entry.
235 /// `section_data` should be from the section containing `import_address`, and
236 /// `section_address` should be the address of that section. Pointers within the
237 /// descriptors and thunks may point to anywhere within the section data.
238 pub fn new(section_data
: &'data
[u8], section_address
: u32, import_address
: u32) -> Self {
239 DelayLoadImportTable
{
240 section_data
: Bytes(section_data
),
246 /// Return an iterator for the import descriptors.
247 pub fn descriptors(&self) -> Result
<DelayLoadDescriptorIterator
<'data
>> {
248 let offset
= self.import_address
.wrapping_sub(self.section_address
);
249 let mut data
= self.section_data
;
250 data
.skip(offset
as usize)
251 .read_error("Invalid PE delay-load import descriptor address")?
;
252 Ok(DelayLoadDescriptorIterator { data }
)
255 /// Return a library name given its address.
257 /// This address may be from [`pe::ImageDelayloadDescriptor::dll_name_rva`].
258 pub fn name(&self, address
: u32) -> Result
<&'data
[u8]> {
260 .read_string_at(address
.wrapping_sub(self.section_address
) as usize)
261 .read_error("Invalid PE import descriptor name")
264 /// Return a list of thunks given its address.
266 /// This address may be from the INT, i.e. from
267 /// [`pe::ImageDelayloadDescriptor::import_name_table_rva`].
269 /// Please note that others RVA values from [`pe::ImageDelayloadDescriptor`] are used
270 /// by the delay loader at runtime to store values, and thus do not point inside the same
271 /// section as the INT. Calling this function on those addresses will fail.
272 pub fn thunks(&self, address
: u32) -> Result
<ImportThunkList
<'data
>> {
273 let offset
= address
.wrapping_sub(self.section_address
);
274 let mut data
= self.section_data
;
275 data
.skip(offset
as usize)
276 .read_error("Invalid PE delay load import thunk table address")?
;
277 Ok(ImportThunkList { data }
)
281 pub fn import
<Pe
: ImageNtHeaders
>(&self, thunk
: Pe
::ImageThunkData
) -> Result
<Import
<'data
>> {
282 if thunk
.is_ordinal() {
283 Ok(Import
::Ordinal(thunk
.ordinal()))
285 let (hint
, name
) = self.hint_name(thunk
.address())?
;
286 Ok(Import
::Name(hint
, name
))
290 /// Return the hint and name at the given address.
292 /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`].
294 /// The hint is an index into the export name pointer table in the target library.
295 pub fn hint_name(&self, address
: u32) -> Result
<(u16, &'data
[u8])> {
296 let offset
= address
.wrapping_sub(self.section_address
);
297 let mut data
= self.section_data
;
298 data
.skip(offset
as usize)
299 .read_error("Invalid PE delay load import thunk address")?
;
301 .read
::<U16Bytes
<LE
>>()
302 .read_error("Missing PE delay load import thunk hint")?
306 .read_error("Missing PE delay load import thunk name")?
;
311 /// A fallible iterator for the descriptors in the delay-load data directory.
312 #[derive(Debug, Clone)]
313 pub struct DelayLoadDescriptorIterator
<'data
> {
317 impl<'data
> DelayLoadDescriptorIterator
<'data
> {
318 /// Return the next descriptor.
320 /// Returns `Ok(None)` when a null descriptor is found.
321 pub fn next(&mut self) -> Result
<Option
<&'data pe
::ImageDelayloadDescriptor
>> {
322 let import_desc
= self
324 .read
::<pe
::ImageDelayloadDescriptor
>()
325 .read_error("Missing PE null delay-load import descriptor")?
;
326 if import_desc
.is_null() {
329 Ok(Some(import_desc
))