use crate::error::Error;
pub struct PeOverlay<'a> {
file: &'a [u8],
overlay_offset: usize,
}
impl<'a> PeOverlay<'a> {
pub fn from_bytes(file: &'a [u8]) -> Result<Self, Error> {
let pe = goblin::pe::PE::parse(file).map_err(Error::from)?;
Self::from_goblin(file, &pe)
}
pub fn from_goblin(file: &'a [u8], pe: &goblin::pe::PE<'_>) -> Result<Self, Error> {
if let Some(oh) = pe.header.optional_header {
let magic = oh.standard_fields.magic;
if magic != goblin::pe::optional_header::MAGIC_32 {
return Err(Error::Not32Bit { magic });
}
}
let overlay_offset = pe
.sections
.iter()
.map(|s| (s.pointer_to_raw_data as usize).saturating_add(s.size_of_raw_data as usize))
.max()
.unwrap_or(0);
if overlay_offset == 0 || overlay_offset >= file.len() {
return Err(Error::OverlayNotFound);
}
Ok(Self {
file,
overlay_offset,
})
}
pub fn overlay(&self) -> &'a [u8] {
self.file.get(self.overlay_offset..).unwrap_or(&[])
}
pub fn overlay_offset(&self) -> usize {
self.overlay_offset
}
pub fn has_ndata_section(pe: &goblin::pe::PE<'_>) -> bool {
pe.sections.iter().any(|s| {
let name = s.name().unwrap_or("");
name == ".ndata"
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn overlay_not_found_on_empty() {
let data = [0u8; 64];
let result = PeOverlay::from_bytes(&data);
assert!(result.is_err());
}
}