pelite\pe64/
imports.rs

1/*!
2Import Directory and the IAT.
3
4The import directory lists all the module dependencies and their imported symbols by this module.
5
6The Import Address Table (IAT) lists all the imported symbols for all the modules in one big list.
7When the imports are resolved the IAT is overwritten with pointers to the resolved functions.
8
9# Examples
10
11```
12# #![allow(unused_variables)]
13use pelite::pe64::{Pe, PeFile};
14
15# #[allow(dead_code)]
16fn example(file: PeFile<'_>) -> pelite::Result<()> {
17	// Access the import directory
18	let imports = file.imports()?;
19
20	// Iterate over the import descriptors
21	for desc in imports {
22		// DLL being imported from
23		let dll_name = desc.dll_name()?;
24
25		// Import Address Table and Import Name Table for this imported DLL
26		let iat = desc.iat()?;
27		let int = desc.int()?;
28
29		// Iterate over the imported functions from this DLL
30		for (va, import) in Iterator::zip(iat, int) {}
31	}
32
33	// Iterate over the IAT
34	for (va, import) in file.iat()?.iter() {
35		// The IAT may contains Null entries where the IAT of imported modules join
36		if let Ok(import) = import {}
37	}
38
39	Ok(())
40}
41```
42*/
43
44use std::{fmt, iter, mem, slice};
45
46use crate::{Error, Result};
47use crate::util::CStr;
48
49use super::image::*;
50use super::Pe;
51
52//----------------------------------------------------------------
53
54pub use crate::wrap::imports::Import;
55
56// Gets the import from the import name table.
57//
58// These aren't actually virtual addresses.
59// This function will decode them to get the import.
60fn import_from_va<'a, P: Pe<'a>>(pe: P, &va: &'a Va) -> Result<Import<'a>> {
61	if va & IMAGE_ORDINAL_FLAG == 0 {
62		// TODO! Validate that this really is an Rva in PE32+?
63		let rva = va as Rva;
64		let hint = pe.derva::<u16>(rva)?;
65		let name = pe.derva_c_str(rva + 2)?;
66		Ok(Import::ByName { hint: *hint as usize, name })
67	}
68	else {
69		Ok(Import::ByOrdinal { ord: va as Ordinal })
70	}
71}
72
73//----------------------------------------------------------------
74
75/// Import directory.
76///
77/// For more information see the [module-level documentation](index.html).
78#[derive(Copy, Clone)]
79pub struct Imports<'a, P> {
80	pe: P,
81	image: &'a [IMAGE_IMPORT_DESCRIPTOR],
82}
83impl<'a, P: Pe<'a>> Imports<'a, P> {
84	pub(crate) fn try_from(pe: P) -> Result<Imports<'a, P>> {
85		let datadir = pe.data_directory().get(IMAGE_DIRECTORY_ENTRY_IMPORT).ok_or(Error::Bounds)?;
86		let image = pe.derva_slice_f(datadir.VirtualAddress, |image: &IMAGE_IMPORT_DESCRIPTOR| image.is_null())?;
87		Ok(Imports { pe, image })
88	}
89	/// Gets the PE instance.
90	pub fn pe(&self) -> P {
91		self.pe
92	}
93	/// Returns the underlying import directory image array.
94	pub fn image(&self) -> &'a [IMAGE_IMPORT_DESCRIPTOR] {
95		self.image
96	}
97	/// Iterator over the import descriptors.
98	pub fn iter(&self) -> Iter<'a, P> {
99		Iter {
100			pe: self.pe,
101			iter: self.image.iter(),
102		}
103	}
104}
105impl<'a, P: Pe<'a>> IntoIterator for Imports<'a, P> {
106	type Item = Desc<'a, P>;
107	type IntoIter = Iter<'a, P>;
108	fn into_iter(self) -> Iter<'a, P> {
109		self.iter()
110	}
111}
112impl<'a, P: Pe<'a>> fmt::Debug for Imports<'a, P> {
113	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114		f.debug_list()
115			.entries(self.into_iter())
116			.finish()
117	}
118}
119
120//----------------------------------------------------------------
121
122/// Import Address Table.
123///
124/// For more information see the [module-level documentation](index.html).
125#[derive(Copy, Clone)]
126pub struct IAT<'a, P> {
127	pe: P,
128	image: &'a [Va],
129}
130impl<'a, P: Pe<'a>> IAT<'a, P> {
131	pub(crate) fn try_from(pe: P) -> Result<IAT<'a, P>> {
132		let datadir = pe.data_directory().get(IMAGE_DIRECTORY_ENTRY_IAT).ok_or(Error::Bounds)?;
133		// Ignore datadir.Size not being a multiple of sizeof(Va), not that big of a deal...
134		let image = pe.derva_slice(datadir.VirtualAddress, datadir.Size as usize / mem::size_of::<Va>())?;
135		Ok(IAT { pe, image })
136	}
137	/// Gets the PE instance.
138	pub fn pe(&self) -> P {
139		self.pe
140	}
141	/// Returns the underlying iat array.
142	pub fn image(&self) -> &'a [Va] {
143		self.image
144	}
145	/// Iterate over the IAT.
146	///
147	/// When the imports aren't resolved yet the IAT is an alias for the import name table.
148	pub fn iter(&self) -> iter::Map<slice::Iter<'a, Va>, impl Clone + FnMut(&'a Va) -> (&'a Va, Result<Import<'a>>)> {
149		let pe = self.pe;
150		self.image.iter().map(move |va| (va, import_from_va(pe, va)))
151	}
152}
153impl<'a, P: Pe<'a>> fmt::Debug for IAT<'a, P> {
154	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155		f.debug_struct("IAT")
156			.field("iat.len", &self.image.len())
157			.finish()
158	}
159}
160
161//----------------------------------------------------------------
162
163#[derive(Clone)]
164pub struct Iter<'a, P> {
165	pe: P,
166	iter: slice::Iter<'a, IMAGE_IMPORT_DESCRIPTOR>,
167}
168impl<'a, P: Pe<'a>> Iter<'a, P> {
169	pub fn image(&self) -> &'a [IMAGE_IMPORT_DESCRIPTOR] {
170		self.iter.as_slice()
171	}
172}
173impl<'a, P: Pe<'a>> Iterator for Iter<'a, P> {
174	type Item = Desc<'a, P>;
175	fn next(&mut self) -> Option<Desc<'a, P>> {
176		self.iter.next().map(|image| Desc { pe: self.pe, image })
177	}
178	fn size_hint(&self) -> (usize, Option<usize>) {
179		self.iter.size_hint()
180	}
181	fn count(self) -> usize {
182		self.iter.count()
183	}
184	fn nth(&mut self, n: usize) -> Option<Desc<'a, P>> {
185		self.iter.nth(n).map(|image| Desc { pe: self.pe, image })
186	}
187}
188impl<'a, P: Pe<'a>> DoubleEndedIterator for Iter<'a, P> {
189	fn next_back(&mut self) -> Option<Desc<'a, P>> {
190		self.iter.next_back().map(|image| Desc { pe: self.pe, image })
191	}
192}
193impl<'a, P: Pe<'a>> ExactSizeIterator for Iter<'a, P> {}
194impl<'a, P: Pe<'a>> iter::FusedIterator for Iter<'a, P> {}
195
196//----------------------------------------------------------------
197
198/// Import library descriptor.
199#[derive(Copy, Clone)]
200pub struct Desc<'a, P> {
201	pe: P,
202	image: &'a IMAGE_IMPORT_DESCRIPTOR,
203}
204impl<'a, P: Pe<'a>> Desc<'a, P> {
205	/// Gets the PE instance.
206	pub fn pe(&self) -> P {
207		self.pe
208	}
209	/// Returns the underlying import descriptor image.
210	pub fn image(&self) -> &'a IMAGE_IMPORT_DESCRIPTOR {
211		self.image
212	}
213	/// Gets the name of the DLL imported from.
214	pub fn dll_name(&self) -> Result<&'a CStr> {
215		self.pe.derva_c_str(self.image.Name)
216	}
217	/// Gets the import address table.
218	///
219	/// After being loaded as a library their values are resolved to the addresses of the imported functions.
220	///
221	/// Otherwise these contain references to the imported functions.
222	/// See [`import_from_va`](struct.Desc.html#import_from_va) to get their names.
223	pub fn iat(&self) -> Result<slice::Iter<'a, Va>> {
224		let slice = self.pe.derva_slice_s(self.image.FirstThunk, 0)?;
225		Ok(slice.iter())
226	}
227	/// Gets the import name table.
228	pub fn int(&self) -> Result<iter::Map<slice::Iter<'a, Va>, impl Clone + FnMut(&'a Va) -> Result<Import<'a>>>> {
229		let slice = self.pe.derva_slice_s(self.image.OriginalFirstThunk, 0)?;
230		let pe = self.pe;
231		Ok(slice.iter().map(move |va| import_from_va(pe, va)))
232	}
233}
234impl<'a, P: Pe<'a>> fmt::Debug for Desc<'a, P> {
235	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236		f.debug_struct("Imports")
237			.field("dll_name", &format_args!("{:?}", self.dll_name()))
238			.field("iat.len", &format_args!("{:?}", &self.iat().map(|iter| iter.len())))
239			.field("int.len", &format_args!("{:?}", &self.int().map(|iter| iter.len())))
240			.finish()
241	}
242}
243
244//----------------------------------------------------------------
245
246/*
247	imports: [
248		{
249			"dll_name": "KERNEL32.dll",
250			"int": [
251				{
252					"ByName": { .. }
253				},
254				{
255					"ByOrdinal": { .. }
256				}
257			]
258		}
259	]
260*/
261
262#[cfg(feature = "serde")]
263mod serde {
264	use crate::util::serde_helper::*;
265	use super::{Pe, Imports, IAT, Desc};
266
267	impl<'a, P: Pe<'a>> Serialize for Imports<'a, P> {
268		fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
269			serializer.collect_seq(self.into_iter())
270		}
271	}
272	impl<'a, P: Pe<'a>> Serialize for IAT<'a, P> {
273		fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
274			let iat = self.iter().filter_map(|(_va, import)| import.ok());
275			serializer.collect_seq(iat)
276		}
277	}
278	impl<'a, P: Pe<'a>> Serialize for Desc<'a, P> {
279		fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
280			let mut state = serializer.serialize_struct("Desc", 2)?;
281			state.serialize_field("dll_name", &self.dll_name().ok())?;
282			let int = self.int().map(|int| {
283				SerdeIter(int.filter_map(|import| {
284					import.ok()
285				}))
286			});
287			state.serialize_field("int", &int.ok())?;
288			state.end()
289		}
290	}
291}
292
293//----------------------------------------------------------------
294
295#[cfg(test)]
296pub(crate) fn test<'a, P: Pe<'a>>(pe: P) -> Result<()> {
297	let imports = pe.imports()?;
298	let _ = format!("{:?}", imports);
299
300	for desc in imports {
301		let _ = format!("{:?}", desc);
302		let _dll_name = desc.dll_name();
303		for _ in desc.iat() {}
304		for _ in desc.int() {}
305	}
306
307	let iat = pe.iat()?;
308	for (va, import) in iat.iter() {
309		let _ = format!("{:?}", import);
310		if import.is_ok() {
311			assert_eq!(import_from_va(pe, va), import);
312		}
313	}
314
315	Ok(())
316}