pelite\pe64/
exports.rs

1/*!
2Export Directory.
3
4The export directory contains a list of symbols, well, exported by this module.
5A symbol can refer to a function, static data or a forwarded reference to an exported symbol in another module.
6
7Symbols can be exported by name or by their ordinal number. The ordinal number of an exported function is its index in the exported function list plus the ordinal base.
8
9# Examples
10
11```
12# #![allow(unused_variables)]
13use pelite::pe64::{Pe, PeFile};
14use pelite::pe64::exports::GetProcAddress;
15
16# #[allow(dead_code)]
17fn example(file: PeFile<'_>) -> pelite::Result<()> {
18	// Most convenient way to get the address of an export
19	file.get_proc_address("ThrowException")?;
20
21	// Access the export directory
22	let exports = file.exports()?;
23
24	// Print the export DLL name
25	let dll_name = exports.dll_name()?;
26	println!("dll_name: {}", dll_name);
27
28	// To query the exports
29	let by = exports.by()?;
30
31	// For example: query an export by name
32	by.name("?__autoclassinit2@Passwds@@QEAAX_K@Z")?;
33
34	// For example: query an export by ordinal
35	by.ordinal(6)?;
36
37	// For example: iterate over all the exports.
38	for result in by.iter() {
39		if let Ok(export) = result {
40			println!("export: {:?}", export);
41		}
42	}
43
44	// For example: iterate over the named exports
45	for result in by.iter_names() {
46		if let (Ok(name), Ok(export)) = result {
47			println!("export {}: {:?}", name, export);
48		}
49	}
50
51	Ok(())
52}
53```
54*/
55
56use std::{fmt, ops};
57
58use crate::{Error, Result};
59use crate::util::CStr;
60
61use super::image::*;
62use super::imports::Import;
63use super::Pe;
64
65//----------------------------------------------------------------
66
67pub use crate::wrap::exports::Export;
68
69//----------------------------------------------------------------
70
71/// Export directory.
72///
73/// For more information see the [module-level documentation](index.html).
74#[derive(Copy, Clone)]
75pub struct Exports<'a, P> {
76	pe: P,
77	datadir: &'a IMAGE_DATA_DIRECTORY,
78	image: &'a IMAGE_EXPORT_DIRECTORY,
79}
80impl<'a, P: Pe<'a>> Exports<'a, P> {
81	pub(crate) fn try_from(pe: P) -> Result<Exports<'a, P>> {
82		let datadir = pe.data_directory().get(IMAGE_DIRECTORY_ENTRY_EXPORT).ok_or(Error::Bounds)?;
83		let image = pe.derva(datadir.VirtualAddress)?;
84		Ok(Exports { pe, datadir, image })
85	}
86	/// Gets the PE instance.
87	pub fn pe(&self) -> P {
88		self.pe
89	}
90	/// Returns the underlying export directory image.
91	pub fn image(&self) -> &'a IMAGE_EXPORT_DIRECTORY {
92		self.image
93	}
94	/// Gets the export directory's name for this library.
95	pub fn dll_name(&self) -> Result<&'a CStr> {
96		self.pe.derva_c_str(self.image.Name)
97	}
98	/// Gets the ordinal base for the exported functions.
99	pub fn ordinal_base(&self) -> Ordinal {
100		self.image.Base as Ordinal
101	}
102	/// Gets the export address table.
103	pub fn functions(&self) -> Result<&'a [Rva]> {
104		self.pe.derva_slice(self.image.AddressOfFunctions, self.image.NumberOfFunctions as usize)
105	}
106	/// Gets the name address table.
107	///
108	/// The values are RVAs to the exported function's name, to find its export look at the name index table with the same index.
109	///
110	/// The names are sorted allowing binary search lookup.
111	pub fn names(&self) -> Result<&'a [Rva]> {
112		self.pe.derva_slice(self.image.AddressOfNames, self.image.NumberOfNames as usize)
113	}
114	/// Gets the name index table.
115	///
116	/// The values are indices (not ordinals!) into the export address table matching name with the same index in the name address table.
117	pub fn name_indices(&self) -> Result<&'a [u16]> {
118		self.pe.derva_slice(self.image.AddressOfNameOrdinals, self.image.NumberOfNames as usize)
119	}
120	/// Query the exports.
121	///
122	/// This specifically validates whether the functions, names and name indices are valid.
123	pub fn by(&self) -> Result<By<'a, P>> {
124		let functions = match self.functions() {
125			Ok(functions) => functions,
126			Err(Error::Null) => &[],
127			Err(e) => return Err(e),
128		};
129		let names = match self.names() {
130			Ok(names) => names,
131			Err(Error::Null) => &[],
132			Err(e) => return Err(e),
133		};
134		let name_indices = match self.name_indices() {
135			Ok(name_indices) => name_indices,
136			Err(Error::Null) => &[],
137			Err(e) => return Err(e),
138		};
139		Ok(By { exp: *self, functions, names, name_indices })
140	}
141	fn is_forwarded(&self, rva: Rva) -> bool {
142		// An export is forward if its rva points within data directory bounds
143		rva >= self.datadir.VirtualAddress && rva < self.datadir.VirtualAddress + self.datadir.Size
144	}
145	pub(crate) fn symbol_from_rva(&self, rva: &'a Rva) -> Result<Export<'a>> {
146		if *rva == 0 {
147			Err(Error::Null)
148		}
149		else if self.is_forwarded(*rva) {
150			let fwd = self.pe.derva_c_str(*rva)?;
151			Ok(Export::Forward(fwd))
152		}
153		else {
154			Ok(Export::Symbol(rva))
155		}
156	}
157}
158impl<'a, P: Pe<'a>> fmt::Debug for Exports<'a, P> {
159	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160		match self.by() {
161			Ok(by) => by.fmt(f),
162			Err(err) => err.fmt(f),
163		}
164	}
165}
166
167//----------------------------------------------------------------
168
169/// Export directory symbol lookup.
170#[derive(Copy, Clone)]
171pub struct By<'a, P> {
172	exp: Exports<'a, P>,
173	functions: &'a [Rva],
174	names: &'a [Rva],
175	name_indices: &'a [u16],
176}
177impl<'a, P: Pe<'a>> ops::Deref for By<'a, P> {
178	type Target = Exports<'a, P>;
179	fn deref(&self) -> &Exports<'a, P> {
180		&self.exp
181	}
182}
183impl<'a, P: Pe<'a>> By<'a, P> {
184	/// Gets the export address table.
185	pub fn functions(&self) -> &'a [Rva] {
186		self.functions
187	}
188	/// Gets the name address table.
189	///
190	/// The values are RVAs to the exported function's name, to find its export look at the name index table with the same index.
191	///
192	/// The names are sorted allowing binary search lookup.
193	pub fn names(&self) -> &'a [Rva] {
194		self.names
195	}
196	/// Gets the name index table.
197	///
198	/// The values are indices (not ordinals!) into the export address table matching name with the same index in the name address table.
199	pub fn name_indices(&self) -> &'a [u16] {
200		self.name_indices
201	}
202	/// Validates and checks if the name table is sorted.
203	///
204	/// The PE specification says that the list of names should be sorted to allow binary search.
205	/// This function checks if the names table is actually sorted, if not then various name based lookup functions may fail to find certain exports.
206	///
207	/// Returns an error if a name entry cannot be read or is otherwise corrupt.
208	pub fn check_sorted(&self) -> Result<bool> {
209		let mut last = CStr::empty();
210		for (name, _export) in self.iter_names() {
211			let name = name?;
212			if last > name {
213				return Ok(false);
214			}
215			last = name;
216		}
217		Ok(true)
218	}
219	/// Looks up an `Export` by its ordinal.
220	pub fn ordinal(&self, ordinal: Ordinal) -> Result<Export<'a>> {
221		let base = self.exp.image.Base;
222		if (ordinal as u32) < base {
223			Err(Error::Bounds)
224		}
225		else {
226			let index = (ordinal as u32 - base) as usize;
227			self.index(index)
228		}
229	}
230	/// Looks up an `Export` by its name.
231	///
232	/// Does a linear scan over the name table.
233	/// If the name table isn't sorted this will still be able to find exported functions by name.
234	///
235	/// Gracefully handles corrupted name entries by ignoring them.
236	pub fn name_linear<S: AsRef<[u8]> + ?Sized>(&self, name: &S) -> Result<Export<'a>> {
237		self.name_linear_(name.as_ref())
238	}
239	fn name_linear_(&self, name: &[u8]) -> Result<Export<'a>> {
240		for hint in 0..self.names.len() {
241			match self.name_of_hint(hint) {
242				Ok(name_it) if name_it == name => return self.hint(hint),
243				_ => (),
244			}
245		}
246		Err(Error::Null)
247	}
248	/// Looks up an `Export` by its name.
249	///
250	/// If the name table isn't sorted, certain exported functions may fail to be found.
251	pub fn name<S: AsRef<[u8]> + ?Sized>(&self, name: &S) -> Result<Export<'a>> {
252		self.name_(name.as_ref())
253	}
254	fn name_(&self, name: &[u8]) -> Result<Export<'a>> {
255		// Binary search for the name
256		let mut lower_bound = 0;
257		let mut upper_bound = self.names.len();
258		while lower_bound != upper_bound {
259			let i = lower_bound + (upper_bound - lower_bound) / 2;
260			let name_rva = self.names[i];
261			let name_it = self.exp.pe.derva_c_str(name_rva)?.as_ref();
262			use std::cmp::Ordering::*;
263			match name.cmp(name_it) {
264				Less => upper_bound = i,
265				Greater => lower_bound = i + 1,
266				Equal => {
267					let &index = self.name_indices.get(i).ok_or(Error::Bounds)?;
268					return self.index(index as usize);
269				},
270			};
271		}
272		// Name not found, return null
273		Err(Error::Null)
274	}
275	/// Looks up an `Export` by its import.
276	pub fn import(&self, import: Import) -> Result<Export<'a>> {
277		match import {
278			Import::ByName { hint, name } => {
279				self.hint_name_(hint, name)
280			},
281			Import::ByOrdinal { ord } => {
282				self.ordinal(ord)
283			}
284		}
285	}
286	/// Looks up an export by its index.
287	pub fn index(&self, index: usize) -> Result<Export<'a>> {
288		let rva = self.functions.get(index).ok_or(Error::Bounds)?;
289		self.exp.symbol_from_rva(rva)
290	}
291	/// Looks up an export by its hint.
292	pub fn hint(&self, hint: usize) -> Result<Export<'a>> {
293		let &index = self.name_indices.get(hint).ok_or(Error::Bounds)?;
294		self.index(index as usize)
295	}
296	/// Looks up an export by its hint and falls back to the name if the hint is incorrect.
297	pub fn hint_name<S: AsRef<[u8]> + ?Sized>(&self, hint: usize, name: &S) -> Result<Export<'a>> {
298		self.hint_name_(hint, name.as_ref())
299	}
300	fn hint_name_(&self, hint: usize, name: &[u8]) -> Result<Export<'a>> {
301		// Try the hint first
302		if let Ok(export) = self.hint(hint) {
303			// Double check that this is the correct export
304			if let Ok(export_name) = self.name_of_hint(hint) {
305				if export_name == name {
306					return Ok(export);
307				}
308			}
309		}
310		// Otherwise fallback to the name
311		self.name(name)
312	}
313	/// Looks up the name for a hint.
314	pub fn name_of_hint(&self, hint: usize) -> Result<&'a CStr> {
315		let &name_rva = self.names.get(hint).ok_or(Error::Bounds)?;
316		self.exp.pe.derva_c_str(name_rva)
317	}
318	/// Given an index in the functions array, gets the named export.
319	///
320	/// Note that this does a linear scan to find its name,
321	/// if this is called in a loop over all the exported functions you are accidentally quadratic.
322	///
323	/// See [`iter_names`](#method.iter_names) to iterate over the exported names in linear time.
324	pub fn name_lookup(&self, index: usize) -> Result<Import<'a>> {
325		// Lookup the name index, accidentally quadratic :)
326		match self.name_indices.iter().position(|&i| i as usize == index) {
327			Some(hint) => {
328				// Lookup the name
329				let name_rva = self.names[hint];
330				let name = self.exp.pe.derva_c_str(name_rva)?;
331				Ok(Import::ByName { hint, name })
332			},
333			None => {
334				// Name not found
335				let ord = (index as u32 + self.exp.image.Base) as Ordinal;
336				Ok(Import::ByOrdinal { ord })
337			},
338		}
339	}
340	/// Iterate over exported functions.
341	///
342	/// Not every exported function has a name, some are exported by ordinal.
343	/// Looking up the exported function's name with [`name_lookup`](#method.name_lookup) results in quadratic performance.
344	/// If the exported function's name is important consider building a cache or using [`iter_names`](#method.iter_names) instead.
345	pub fn iter<'s>(&'s self) -> impl 's + Clone + Iterator<Item = Result<Export<'a>>> {
346		self.functions.iter().map(move |rva| self.symbol_from_rva(rva))
347	}
348	/// Iterate over functions exported by name.
349	pub fn iter_names<'s>(&'s self) -> impl 's + Clone + Iterator<Item = (Result<&'a CStr>, Result<Export<'a>>)> {
350		(0..self.names().len() as u32)
351			.map(move |hint| (
352				self.name_of_hint(hint as usize),
353				self.hint(hint as usize),
354			))
355	}
356	/// Iterate over functions exported by name, returning their name and index in the functions table.
357	pub fn iter_name_indices<'s>(&'s self) -> impl 's + Clone + Iterator<Item = (Result<&'a CStr>, usize)> {
358		(0..self.names().len() as u32)
359			.map(move |hint| (
360				self.name_of_hint(hint as usize),
361				self.name_indices[hint as usize] as usize,
362			))
363	}
364}
365impl<'a, P: Pe<'a>> fmt::Debug for By<'a, P> {
366	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
367		f.debug_struct("Exports")
368			.field("dll_name", &format_args!("{:?}", self.dll_name()))
369			.field("time_date_stamp", &self.image.TimeDateStamp)
370			.field("version", &self.image.Version)
371			.field("ordinal_base", &self.ordinal_base())
372			.field("functions.len", &self.functions().len())
373			.field("names.len", &self.names.len())
374			.finish()
375	}
376}
377
378//----------------------------------------------------------------
379
380/// Convenient way to get an exported address.
381pub trait GetProcAddress<'a, T>: Pe<'a> {
382	/// Convenient method to get an exported function.
383	///
384	/// Note that calling this method many times is less efficient than caching a [`By`](struct.By.html) instance, such is the trade-off for convenience.
385	fn get_export(self, name: T) -> Result<Export<'a>>;
386	/// Convenient method to get the address of an exported function.
387	///
388	/// Note that this method does not support forwarded exports and will return `Err(Null)` instead.
389	///
390	/// Note that calling this method many times is less efficient than caching a [`By`](struct.By.html) instance, such is the trade-off for convenience.
391	#[inline(never)]
392	fn get_proc_address(self, name: T) -> Result<Va> {
393		self.rva_to_va(self.get_export(name)?.symbol().ok_or(Error::Null)?)
394	}
395}
396impl<'a, P: Pe<'a>> GetProcAddress<'a, Ordinal> for P {
397	fn get_export(self, name: Ordinal) -> Result<Export<'a>> {
398		self.exports()?.by()?.ordinal(name)
399	}
400}
401impl<'b, 'a, P: Pe<'a>> GetProcAddress<'a, Import<'b>> for P {
402	fn get_export(self, name: Import<'b>) -> Result<Export<'a>> {
403		self.exports()?.by()?.import(name)
404	}
405}
406impl<'b, 'a, P: Pe<'a>, S: AsRef<[u8]> + ?Sized> GetProcAddress<'a, &'b S> for P {
407	fn get_export(self, name: &'b S) -> Result<Export<'a>> {
408		self.exports()?.by()?.name(name)
409	}
410}
411
412//----------------------------------------------------------------
413
414/*
415	"exports": {
416		"dll_name": "Demo.dll",
417		"time_date_stamp": 0,
418		"version": "0.0",
419		"ordinal_base": 1,
420		"functions": [ .. ],
421		"names": {
422			"__autoclassinit": 5,
423			..
424		}
425	}
426*/
427
428#[cfg(feature = "serde")]
429mod serde {
430	use crate::util::serde_helper::*;
431	use super::{Pe, Exports, By};
432
433	impl<'a, P: Pe<'a>> Serialize for Exports<'a, P> {
434		fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
435			self.by().ok().serialize(serializer)
436		}
437	}
438	impl<'a, P: Pe<'a>> Serialize for By<'a, P> {
439		fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
440			let mut state = serializer.serialize_struct("Exports", 6)?;
441			state.serialize_field("dll_name", &self.dll_name().ok())?;
442			state.serialize_field("time_date_stamp", &self.image.TimeDateStamp)?;
443			state.serialize_field("version", &self.image.Version)?;
444			state.serialize_field("ordinal_base", &self.ordinal_base())?;
445			state.serialize_field("functions", &self.functions())?;
446			let names = self.iter_name_indices().filter_map(|(name, index)| {
447				name.ok().and_then(|name| name.to_str().ok()).map(|name| (name, index))
448			});
449			state.serialize_field("names", &SerdeKV(names))?;
450			state.end()
451		}
452	}
453}
454
455//----------------------------------------------------------------
456
457#[cfg(test)]
458pub(crate) fn test<'a, P: Pe<'a>>(pe: P) -> Result<()> {
459	let by = pe.exports()?.by()?;
460	let _ = format!("{:?}", by);
461
462	let _dll_name = by.dll_name();
463	let _ordinal_base = by.ordinal_base();
464
465	// If the name table isn't sorted, skip some tests
466	let sorted = by.check_sorted()?;
467
468	// Count occurances of each export name
469	use std::collections::HashMap;
470	let mut occurances = HashMap::<_, i32>::new();
471	for (name, _) in by.iter_names() {
472		if let Ok(name) = name {
473			*occurances.entry(name).or_default() += 1;
474		}
475	}
476
477	for (hint, (name, export)) in by.iter_names().enumerate() {
478		// println!("hint:{:?} name:{:?} export:{:?}", hint, name, export);
479
480		assert_eq!(name, by.name_of_hint(hint));
481		assert_eq!(export, by.hint(hint));
482
483		if let Ok(name) = name {
484			// Only do some name lookups if the export is actually unique
485			let unique = occurances[name] == 1;
486
487			// Lookup the export by its name
488			if unique {
489				assert_eq!(export, by.name_linear(name));
490				if sorted {
491					assert_eq!(export, by.name(name));
492				}
493			}
494
495			// Lookup the export by its name and hint
496			assert_eq!(export, by.hint_name(hint, name));
497			assert_eq!(export, by.import(Import::ByName { hint, name }));
498			if sorted && unique {
499				assert_eq!(export, by.hint_name(0, name));
500				assert_eq!(export, by.import(Import::ByName { hint: 0, name }));
501			}
502		}
503	}
504	Ok(())
505}