use alloc::vec::Vec;
pub mod characteristic;
pub mod data_directories;
pub mod debug;
pub mod exception;
pub mod export;
pub mod header;
pub mod import;
pub mod optional_header;
pub mod options;
pub mod relocation;
pub mod section_table;
pub mod symbol;
pub mod utils;
use crate::container;
use crate::error;
use crate::strtab;
use log::debug;
#[derive(Debug)]
pub struct PE<'a> {
pub header: header::Header,
pub sections: Vec<section_table::SectionTable>,
pub size: usize,
pub name: Option<&'a str>,
pub is_lib: bool,
pub is_64: bool,
pub entry: usize,
pub image_base: usize,
pub export_data: Option<export::ExportData<'a>>,
pub import_data: Option<import::ImportData<'a>>,
pub exports: Vec<export::Export<'a>>,
pub imports: Vec<import::Import<'a>>,
pub libraries: Vec<&'a str>,
pub debug_data: Option<debug::DebugData<'a>>,
pub exception_data: Option<exception::ExceptionData<'a>>,
}
impl<'a> PE<'a> {
pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
Self::parse_with_opts(bytes, &options::ParseOptions::default())
}
pub fn parse_with_opts(bytes: &'a [u8], opts: &options::ParseOptions) -> error::Result<Self> {
let header = header::Header::parse(bytes)?;
debug!("{:#?}", header);
let offset = &mut (header.dos_header.pe_pointer as usize
+ header::SIZEOF_PE_MAGIC
+ header::SIZEOF_COFF_HEADER
+ header.coff_header.size_of_optional_header as usize);
let sections = header.coff_header.sections(bytes, offset)?;
let is_lib = characteristic::is_dll(header.coff_header.characteristics);
let mut entry = 0;
let mut image_base = 0;
let mut exports = vec![];
let mut export_data = None;
let mut name = None;
let mut imports = vec![];
let mut import_data = None;
let mut libraries = vec![];
let mut debug_data = None;
let mut exception_data = None;
let mut is_64 = false;
if let Some(optional_header) = header.optional_header {
entry = optional_header.standard_fields.address_of_entry_point as usize;
image_base = optional_header.windows_fields.image_base as usize;
is_64 = optional_header.container()? == container::Container::Big;
debug!(
"entry {:#x} image_base {:#x} is_64: {}",
entry, image_base, is_64
);
let file_alignment = optional_header.windows_fields.file_alignment;
if let Some(export_table) = *optional_header.data_directories.get_export_table() {
if let Ok(ed) = export::ExportData::parse_with_opts(
bytes,
export_table,
§ions,
file_alignment,
opts,
) {
debug!("export data {:#?}", ed);
exports = export::Export::parse_with_opts(
bytes,
&ed,
§ions,
file_alignment,
opts,
)?;
name = ed.name;
debug!("name: {:#?}", name);
export_data = Some(ed);
}
}
debug!("exports: {:#?}", exports);
if let Some(import_table) = *optional_header.data_directories.get_import_table() {
let id = if is_64 {
import::ImportData::parse_with_opts::<u64>(
bytes,
import_table,
§ions,
file_alignment,
opts,
)?
} else {
import::ImportData::parse_with_opts::<u32>(
bytes,
import_table,
§ions,
file_alignment,
opts,
)?
};
debug!("import data {:#?}", id);
if is_64 {
imports = import::Import::parse::<u64>(bytes, &id, §ions)?
} else {
imports = import::Import::parse::<u32>(bytes, &id, §ions)?
}
libraries = id
.import_data
.iter()
.map(|data| data.name)
.collect::<Vec<&'a str>>();
libraries.sort();
libraries.dedup();
import_data = Some(id);
}
debug!("imports: {:#?}", imports);
if let Some(debug_table) = *optional_header.data_directories.get_debug_table() {
debug_data = Some(debug::DebugData::parse_with_opts(
bytes,
debug_table,
§ions,
file_alignment,
opts,
)?);
}
if header.coff_header.machine == header::COFF_MACHINE_X86_64 {
debug!("exception data: {:#?}", exception_data);
if let Some(exception_table) =
*optional_header.data_directories.get_exception_table()
{
exception_data = Some(exception::ExceptionData::parse_with_opts(
bytes,
exception_table,
§ions,
file_alignment,
opts,
)?);
}
}
}
Ok(PE {
header,
sections,
size: 0,
name,
is_lib,
is_64,
entry,
image_base,
export_data,
import_data,
exports,
imports,
libraries,
debug_data,
exception_data,
})
}
}
#[derive(Debug)]
pub struct Coff<'a> {
pub header: header::CoffHeader,
pub sections: Vec<section_table::SectionTable>,
pub symbols: symbol::SymbolTable<'a>,
pub strings: strtab::Strtab<'a>,
}
impl<'a> Coff<'a> {
pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
let offset = &mut 0;
let header = header::CoffHeader::parse(bytes, offset)?;
debug!("{:#?}", header);
*offset += header.size_of_optional_header as usize;
let sections = header.sections(bytes, offset)?;
let symbols = header.symbols(bytes)?;
let strings = header.strings(bytes)?;
Ok(Coff {
header,
sections,
symbols,
strings,
})
}
}