use super::images::*;
use crate::error;
pub trait Pe {
fn image(&self) -> &[u8];
fn dos_header(&self) -> &IMAGE_DOS_HEADER {
unsafe { &*(self.image().as_ptr() as *const IMAGE_DOS_HEADER) }
}
fn nt_headers(&self) -> &IMAGE_NT_HEADERS {
unsafe {
&*(self
.image()
.as_ptr()
.offset(self.dos_header().e_lfanew as isize)
as *mut IMAGE_NT_HEADERS)
}
}
fn file_header(&self) -> &IMAGE_FILE_HEADER {
&self.nt_headers().FileHeader
}
fn opt_header(&self) -> &IMAGE_OPTIONAL_HEADER {
&self.nt_headers().OptionalHeader
}
fn section_headers(&self) -> &[IMAGE_SECTION_HEADER] {
unsafe {
let len = self.file_header().NumberOfSections as usize;
let data = (self.file_header() as *const _ as *const u8)
.offset(20) .offset(self.file_header().SizeOfOptionalHeader as isize)
as *const IMAGE_SECTION_HEADER;
std::slice::from_raw_parts(data, len)
}
}
fn num_of_sections(&self) -> usize {
self.file_header().NumberOfSections as usize
}
fn rva_to_foa(&self, rva: Rva) -> error::Result<u32> {
if rva < self.opt_header().SizeOfHeaders {
return Ok(rva);
}
let sections = self.section_headers();
for sec in sections {
let sec: &IMAGE_SECTION_HEADER = sec;
let rva_end_bound = sec
.VirtualAddress
.wrapping_add(std::cmp::max(sec.SizeOfRawData, sec.VirtualSize));
if rva >= sec.VirtualAddress && rva < rva_end_bound {
if let None = sec.PointerToRawData.checked_add(sec.SizeOfRawData) {
return Err(error::Error::Overflow);
}
let sec_offset = rva - sec.VirtualAddress;
return if sec_offset < sec.SizeOfRawData {
Ok(sec_offset + sec.PointerToRawData)
} else if sec_offset < sec.VirtualSize {
Err(error::Error::ZeroFill)
} else {
Err(error::Error::Bounds)
};
}
}
Err(error::Error::Bounds)
}
fn foa_to_rva(&self, foa: u32) -> error::Result<Rva> {
if foa < self.opt_header().SizeOfHeaders {
return Ok(foa);
}
for sec in self.section_headers() {
let sec: &IMAGE_SECTION_HEADER = sec;
let foa_end_bound = sec.PointerToRawData.wrapping_add(sec.SizeOfRawData);
if foa >= sec.PointerToRawData && foa < foa_end_bound {
if let None = sec.VirtualAddress.checked_add(sec.VirtualSize) {
return Err(error::Error::Overflow);
}
let sec_offset = foa - sec.PointerToRawData;
return if sec_offset < sec.VirtualSize {
Ok(sec_offset + sec.VirtualAddress)
} else if sec_offset < sec.SizeOfRawData {
Err(error::Error::Unmapped)
} else {
Err(error::Error::Bounds)
};
}
}
Err(error::Error::Bounds)
}
}