use std::{fmt, iter, mem, slice};
use crate::{Error, Result};
use crate::util::CStr;
use super::image::*;
use super::Pe;
pub use crate::wrap::imports::Import;
fn import_from_va<'a, P: Pe<'a>>(pe: P, &va: &'a Va) -> Result<Import<'a>> {
if va & IMAGE_ORDINAL_FLAG == 0 {
let rva = va as Rva;
let hint = pe.derva::<u16>(rva)?;
let name = pe.derva_c_str(rva + 2)?;
Ok(Import::ByName { hint: *hint as usize, name })
}
else {
Ok(Import::ByOrdinal { ord: va as Ordinal })
}
}
#[derive(Copy, Clone)]
pub struct Imports<'a, P> {
pe: P,
image: &'a [IMAGE_IMPORT_DESCRIPTOR],
}
impl<'a, P: Pe<'a>> Imports<'a, P> {
pub(crate) fn try_from(pe: P) -> Result<Imports<'a, P>> {
let datadir = pe.data_directory().get(IMAGE_DIRECTORY_ENTRY_IMPORT).ok_or(Error::Bounds)?;
let image = pe.derva_slice_f(datadir.VirtualAddress, |image: &IMAGE_IMPORT_DESCRIPTOR| image.is_null())?;
Ok(Imports { pe, image })
}
pub fn pe(&self) -> P {
self.pe
}
pub fn image(&self) -> &'a [IMAGE_IMPORT_DESCRIPTOR] {
self.image
}
pub fn iter(&self) -> Iter<'a, P> {
Iter {
pe: self.pe,
iter: self.image.iter(),
}
}
}
impl<'a, P: Pe<'a>> IntoIterator for Imports<'a, P> {
type Item = Desc<'a, P>;
type IntoIter = Iter<'a, P>;
fn into_iter(self) -> Iter<'a, P> {
self.iter()
}
}
impl<'a, P: Pe<'a>> fmt::Debug for Imports<'a, P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list()
.entries(self.into_iter())
.finish()
}
}
#[derive(Copy, Clone)]
pub struct IAT<'a, P> {
pe: P,
image: &'a [Va],
}
impl<'a, P: Pe<'a>> IAT<'a, P> {
pub(crate) fn try_from(pe: P) -> Result<IAT<'a, P>> {
let datadir = pe.data_directory().get(IMAGE_DIRECTORY_ENTRY_IAT).ok_or(Error::Bounds)?;
let image = pe.derva_slice(datadir.VirtualAddress, datadir.Size as usize / mem::size_of::<Va>())?;
Ok(IAT { pe, image })
}
pub fn pe(&self) -> P {
self.pe
}
pub fn image(&self) -> &'a [Va] {
self.image
}
pub fn iter(&self) -> iter::Map<slice::Iter<'a, Va>, impl Clone + FnMut(&'a Va) -> (&'a Va, Result<Import<'a>>)> {
let pe = self.pe;
self.image.iter().map(move |va| (va, import_from_va(pe, va)))
}
}
impl<'a, P: Pe<'a>> fmt::Debug for IAT<'a, P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("IAT")
.field("iat.len", &self.image.len())
.finish()
}
}
#[derive(Clone)]
pub struct Iter<'a, P> {
pe: P,
iter: slice::Iter<'a, IMAGE_IMPORT_DESCRIPTOR>,
}
impl<'a, P: Pe<'a>> Iter<'a, P> {
pub fn image(&self) -> &'a [IMAGE_IMPORT_DESCRIPTOR] {
self.iter.as_slice()
}
}
impl<'a, P: Pe<'a>> Iterator for Iter<'a, P> {
type Item = Desc<'a, P>;
fn next(&mut self) -> Option<Desc<'a, P>> {
self.iter.next().map(|image| Desc { pe: self.pe, image })
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
fn count(self) -> usize {
self.iter.count()
}
fn nth(&mut self, n: usize) -> Option<Desc<'a, P>> {
self.iter.nth(n).map(|image| Desc { pe: self.pe, image })
}
}
impl<'a, P: Pe<'a>> DoubleEndedIterator for Iter<'a, P> {
fn next_back(&mut self) -> Option<Desc<'a, P>> {
self.iter.next_back().map(|image| Desc { pe: self.pe, image })
}
}
impl<'a, P: Pe<'a>> ExactSizeIterator for Iter<'a, P> {}
impl<'a, P: Pe<'a>> iter::FusedIterator for Iter<'a, P> {}
#[derive(Copy, Clone)]
pub struct Desc<'a, P> {
pe: P,
image: &'a IMAGE_IMPORT_DESCRIPTOR,
}
impl<'a, P: Pe<'a>> Desc<'a, P> {
pub fn pe(&self) -> P {
self.pe
}
pub fn image(&self) -> &'a IMAGE_IMPORT_DESCRIPTOR {
self.image
}
pub fn dll_name(&self) -> Result<&'a CStr> {
self.pe.derva_c_str(self.image.Name)
}
pub fn iat(&self) -> Result<slice::Iter<'a, Va>> {
let slice = self.pe.derva_slice_s(self.image.FirstThunk, 0)?;
Ok(slice.iter())
}
pub fn int(&self) -> Result<iter::Map<slice::Iter<'a, Va>, impl Clone + FnMut(&'a Va) -> Result<Import<'a>>>> {
let slice = self.pe.derva_slice_s(self.image.OriginalFirstThunk, 0)?;
let pe = self.pe;
Ok(slice.iter().map(move |va| import_from_va(pe, va)))
}
}
impl<'a, P: Pe<'a>> fmt::Debug for Desc<'a, P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Imports")
.field("dll_name", &format_args!("{:?}", self.dll_name()))
.field("iat.len", &format_args!("{:?}", &self.iat().map(|iter| iter.len())))
.field("int.len", &format_args!("{:?}", &self.int().map(|iter| iter.len())))
.finish()
}
}
#[cfg(feature = "serde")]
mod serde {
use crate::util::serde_helper::*;
use super::{Pe, Imports, IAT, Desc};
impl<'a, P: Pe<'a>> Serialize for Imports<'a, P> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.collect_seq(self.into_iter())
}
}
impl<'a, P: Pe<'a>> Serialize for IAT<'a, P> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let iat = self.iter().filter_map(|(_va, import)| import.ok());
serializer.collect_seq(iat)
}
}
impl<'a, P: Pe<'a>> Serialize for Desc<'a, P> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut state = serializer.serialize_struct("Desc", 2)?;
state.serialize_field("dll_name", &self.dll_name().ok())?;
let int = self.int().map(|int| {
SerdeIter(int.filter_map(|import| {
import.ok()
}))
});
state.serialize_field("int", &int.ok())?;
state.end()
}
}
}
#[cfg(test)]
pub(crate) fn test<'a, P: Pe<'a>>(pe: P) -> Result<()> {
let imports = pe.imports()?;
let _ = format!("{:?}", imports);
for desc in imports {
let _ = format!("{:?}", desc);
let _dll_name = desc.dll_name();
for _ in desc.iat() {}
for _ in desc.int() {}
}
let iat = pe.iat()?;
for (va, import) in iat.iter() {
let _ = format!("{:?}", import);
if import.is_ok() {
assert_eq!(import_from_va(pe, va), import);
}
}
Ok(())
}