1use core::fmt::Debug;
2use core::mem;
34use crate::endian::{LittleEndian as LE, U16Bytes};
5use crate::pe;
6use crate::pod::Pod;
7use crate::read::{Bytes, ReadError, Result};
89use super::ImageNtHeaders;
1011/// Information for parsing a PE import table.
12///
13/// Returned by [`DataDirectories::import_table`](super::DataDirectories::import_table).
14#[derive(Debug, Clone)]
15pub struct ImportTable<'data> {
16 section_data: Bytes<'data>,
17 section_address: u32,
18 import_address: u32,
19}
2021impl<'data> ImportTable<'data> {
22/// Create a new import table parser.
23 ///
24 /// The import descriptors start at `import_address`.
25 /// The size declared in the `IMAGE_DIRECTORY_ENTRY_IMPORT` data directory is
26 /// ignored by the Windows loader, and so descriptors will be parsed until a null entry.
27 ///
28 /// `section_data` should be from the section containing `import_address`, and
29 /// `section_address` should be the address of that section. Pointers within the
30 /// descriptors and thunks may point to anywhere within the section data.
31pub fn new(section_data: &'data [u8], section_address: u32, import_address: u32) -> Self {
32 ImportTable {
33 section_data: Bytes(section_data),
34 section_address,
35 import_address,
36 }
37 }
3839/// Return an iterator for the import descriptors.
40pub fn descriptors(&self) -> Result<ImportDescriptorIterator<'data>> {
41let offset = self.import_address.wrapping_sub(self.section_address);
42let mut data = self.section_data;
43 data.skip(offset as usize)
44 .read_error("Invalid PE import descriptor address")?;
45Ok(ImportDescriptorIterator { data, null: false })
46 }
4748/// Return a library name given its address.
49 ///
50 /// This address may be from [`pe::ImageImportDescriptor::name`].
51pub fn name(&self, address: u32) -> Result<&'data [u8]> {
52self.section_data
53 .read_string_at(address.wrapping_sub(self.section_address) as usize)
54 .read_error("Invalid PE import descriptor name")
55 }
5657/// Return a list of thunks given its address.
58 ///
59 /// This address may be from [`pe::ImageImportDescriptor::original_first_thunk`]
60 /// or [`pe::ImageImportDescriptor::first_thunk`].
61pub fn thunks(&self, address: u32) -> Result<ImportThunkList<'data>> {
62let offset = address.wrapping_sub(self.section_address);
63let mut data = self.section_data;
64 data.skip(offset as usize)
65 .read_error("Invalid PE import thunk table address")?;
66Ok(ImportThunkList { data })
67 }
6869/// Parse a thunk.
70pub fn import<Pe: ImageNtHeaders>(&self, thunk: Pe::ImageThunkData) -> Result<Import<'data>> {
71if thunk.is_ordinal() {
72Ok(Import::Ordinal(thunk.ordinal()))
73 } else {
74let (hint, name) = self.hint_name(thunk.address())?;
75Ok(Import::Name(hint, name))
76 }
77 }
7879/// Return the hint and name at the given address.
80 ///
81 /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`].
82 ///
83 /// The hint is an index into the export name pointer table in the target library.
84pub fn hint_name(&self, address: u32) -> Result<(u16, &'data [u8])> {
85let offset = address.wrapping_sub(self.section_address);
86let mut data = self.section_data;
87 data.skip(offset as usize)
88 .read_error("Invalid PE import thunk address")?;
89let hint = data
90 .read::<U16Bytes<LE>>()
91 .read_error("Missing PE import thunk hint")?
92.get(LE);
93let name = data
94 .read_string()
95 .read_error("Missing PE import thunk name")?;
96Ok((hint, name))
97 }
98}
99100/// A fallible iterator for the descriptors in the import data directory.
101#[derive(Debug, Clone)]
102pub struct ImportDescriptorIterator<'data> {
103 data: Bytes<'data>,
104 null: bool,
105}
106107impl<'data> ImportDescriptorIterator<'data> {
108/// Return the next descriptor.
109 ///
110 /// Returns `Ok(None)` when a null descriptor is found.
111pub fn next(&mut self) -> Result<Option<&'data pe::ImageImportDescriptor>> {
112if self.null {
113return Ok(None);
114 }
115let result = self
116.data
117 .read::<pe::ImageImportDescriptor>()
118 .read_error("Missing PE null import descriptor");
119match result {
120Ok(import_desc) => {
121if import_desc.is_null() {
122self.null = true;
123Ok(None)
124 } else {
125Ok(Some(import_desc))
126 }
127 }
128Err(e) => {
129self.null = true;
130Err(e)
131 }
132 }
133 }
134}
135136impl<'data> Iterator for ImportDescriptorIterator<'data> {
137type Item = Result<&'data pe::ImageImportDescriptor>;
138139fn next(&mut self) -> Option<Self::Item> {
140self.next().transpose()
141 }
142}
143144/// A list of import thunks.
145///
146/// These may be in the import lookup table, or the import address table.
147#[derive(Debug, Clone)]
148pub struct ImportThunkList<'data> {
149 data: Bytes<'data>,
150}
151152impl<'data> ImportThunkList<'data> {
153/// Get the thunk at the given index.
154pub fn get<Pe: ImageNtHeaders>(&self, index: usize) -> Result<Pe::ImageThunkData> {
155let thunk = self
156.data
157 .read_at(index * mem::size_of::<Pe::ImageThunkData>())
158 .read_error("Invalid PE import thunk index")?;
159Ok(*thunk)
160 }
161162/// Return the first thunk in the list, and update `self` to point after it.
163 ///
164 /// Returns `Ok(None)` when a null thunk is found.
165pub fn next<Pe: ImageNtHeaders>(&mut self) -> Result<Option<Pe::ImageThunkData>> {
166let thunk = self
167.data
168 .read::<Pe::ImageThunkData>()
169 .read_error("Missing PE null import thunk")?;
170if thunk.address() == 0 {
171Ok(None)
172 } else {
173Ok(Some(*thunk))
174 }
175 }
176}
177178/// A parsed import thunk.
179#[derive(Debug, Clone, Copy)]
180pub enum Import<'data> {
181/// Import by ordinal.
182Ordinal(u16),
183/// Import by name.
184 ///
185 /// Includes a hint for the index into the export name pointer table in the target library.
186Name(u16, &'data [u8]),
187}
188189/// A trait for generic access to [`pe::ImageThunkData32`] and [`pe::ImageThunkData64`].
190#[allow(missing_docs)]
191pub trait ImageThunkData: Debug + Pod {
192/// Return the raw thunk value.
193fn raw(self) -> u64;
194195/// Returns true if the ordinal flag is set.
196fn is_ordinal(self) -> bool;
197198/// Return the ordinal portion of the thunk.
199 ///
200 /// Does not check the ordinal flag.
201fn ordinal(self) -> u16;
202203/// Return the RVA portion of the thunk.
204 ///
205 /// Does not check the ordinal flag.
206fn address(self) -> u32;
207}
208209impl ImageThunkData for pe::ImageThunkData64 {
210fn raw(self) -> u64 {
211self.0.get(LE)
212 }
213214fn is_ordinal(self) -> bool {
215self.0.get(LE) & pe::IMAGE_ORDINAL_FLAG64 != 0
216}
217218fn ordinal(self) -> u16 {
219self.0.get(LE) as u16
220 }
221222fn address(self) -> u32 {
223self.0.get(LE) as u32 & 0x7fff_ffff
224}
225}
226227impl ImageThunkData for pe::ImageThunkData32 {
228fn raw(self) -> u64 {
229self.0.get(LE).into()
230 }
231232fn is_ordinal(self) -> bool {
233self.0.get(LE) & pe::IMAGE_ORDINAL_FLAG32 != 0
234}
235236fn ordinal(self) -> u16 {
237self.0.get(LE) as u16
238 }
239240fn address(self) -> u32 {
241self.0.get(LE) & 0x7fff_ffff
242}
243}
244245/// Information for parsing a PE delay-load import table.
246///
247/// Returned by
248/// [`DataDirectories::delay_load_import_table`](super::DataDirectories::delay_load_import_table).
249#[derive(Debug, Clone)]
250pub struct DelayLoadImportTable<'data> {
251 section_data: Bytes<'data>,
252 section_address: u32,
253 import_address: u32,
254}
255256impl<'data> DelayLoadImportTable<'data> {
257/// Create a new delay load import table parser.
258 ///
259 /// The import descriptors start at `import_address`.
260 /// This table works in the same way the import table does: descriptors will be
261 /// parsed until a null entry.
262 ///
263 /// `section_data` should be from the section containing `import_address`, and
264 /// `section_address` should be the address of that section. Pointers within the
265 /// descriptors and thunks may point to anywhere within the section data.
266pub fn new(section_data: &'data [u8], section_address: u32, import_address: u32) -> Self {
267 DelayLoadImportTable {
268 section_data: Bytes(section_data),
269 section_address,
270 import_address,
271 }
272 }
273274/// Return an iterator for the import descriptors.
275pub fn descriptors(&self) -> Result<DelayLoadDescriptorIterator<'data>> {
276let offset = self.import_address.wrapping_sub(self.section_address);
277let mut data = self.section_data;
278 data.skip(offset as usize)
279 .read_error("Invalid PE delay-load import descriptor address")?;
280Ok(DelayLoadDescriptorIterator { data, null: false })
281 }
282283/// Return a library name given its address.
284 ///
285 /// This address may be from [`pe::ImageDelayloadDescriptor::dll_name_rva`].
286pub fn name(&self, address: u32) -> Result<&'data [u8]> {
287self.section_data
288 .read_string_at(address.wrapping_sub(self.section_address) as usize)
289 .read_error("Invalid PE import descriptor name")
290 }
291292/// Return a list of thunks given its address.
293 ///
294 /// This address may be from the INT, i.e. from
295 /// [`pe::ImageDelayloadDescriptor::import_name_table_rva`].
296 ///
297 /// Please note that others RVA values from [`pe::ImageDelayloadDescriptor`] are used
298 /// by the delay loader at runtime to store values, and thus do not point inside the same
299 /// section as the INT. Calling this function on those addresses will fail.
300pub fn thunks(&self, address: u32) -> Result<ImportThunkList<'data>> {
301let offset = address.wrapping_sub(self.section_address);
302let mut data = self.section_data;
303 data.skip(offset as usize)
304 .read_error("Invalid PE delay load import thunk table address")?;
305Ok(ImportThunkList { data })
306 }
307308/// Parse a thunk.
309pub fn import<Pe: ImageNtHeaders>(&self, thunk: Pe::ImageThunkData) -> Result<Import<'data>> {
310if thunk.is_ordinal() {
311Ok(Import::Ordinal(thunk.ordinal()))
312 } else {
313let (hint, name) = self.hint_name(thunk.address())?;
314Ok(Import::Name(hint, name))
315 }
316 }
317318/// Return the hint and name at the given address.
319 ///
320 /// This address may be from [`pe::ImageThunkData32`] or [`pe::ImageThunkData64`].
321 ///
322 /// The hint is an index into the export name pointer table in the target library.
323pub fn hint_name(&self, address: u32) -> Result<(u16, &'data [u8])> {
324let offset = address.wrapping_sub(self.section_address);
325let mut data = self.section_data;
326 data.skip(offset as usize)
327 .read_error("Invalid PE delay load import thunk address")?;
328let hint = data
329 .read::<U16Bytes<LE>>()
330 .read_error("Missing PE delay load import thunk hint")?
331.get(LE);
332let name = data
333 .read_string()
334 .read_error("Missing PE delay load import thunk name")?;
335Ok((hint, name))
336 }
337}
338339/// A fallible iterator for the descriptors in the delay-load data directory.
340#[derive(Debug, Clone)]
341pub struct DelayLoadDescriptorIterator<'data> {
342 data: Bytes<'data>,
343 null: bool,
344}
345346impl<'data> DelayLoadDescriptorIterator<'data> {
347/// Return the next descriptor.
348 ///
349 /// Returns `Ok(None)` when a null descriptor is found.
350pub fn next(&mut self) -> Result<Option<&'data pe::ImageDelayloadDescriptor>> {
351if self.null {
352return Ok(None);
353 }
354let result = self
355.data
356 .read::<pe::ImageDelayloadDescriptor>()
357 .read_error("Missing PE null delay-load import descriptor");
358match result {
359Ok(import_desc) => {
360if import_desc.is_null() {
361self.null = true;
362Ok(None)
363 } else {
364Ok(Some(import_desc))
365 }
366 }
367Err(e) => {
368self.null = true;
369Err(e)
370 }
371 }
372 }
373}
374375impl<'data> Iterator for DelayLoadDescriptorIterator<'data> {
376type Item = Result<&'data pe::ImageDelayloadDescriptor>;
377378fn next(&mut self) -> Option<Self::Item> {
379self.next().transpose()
380 }
381}