use anyhow::Result;
use byteorder::ByteOrder;
use log::debug;
use crate::{aspace::AddressSpace, loader::pe::PE, module::Permissions, VA};
pub fn find_pe_nonrelocated_executable_pointers(pe: &PE) -> Result<Vec<VA>> {
let mut candidates: Vec<VA> = vec![];
let min_addr = pe.module.address_space.base_address;
let max_addr = pe
.module
.sections
.iter()
.map(|section| section.virtual_range.end)
.max()
.unwrap();
for section in pe.module.sections.iter() {
let vstart: VA = section.virtual_range.start;
let vsize = (section.virtual_range.end - section.virtual_range.start) as usize;
let sec_buf = pe.module.address_space.read_bytes(vstart, vsize)?;
debug!(
"pointers: scanning section {:#x}-{:#x}",
section.virtual_range.start, section.virtual_range.end
);
if let crate::arch::Arch::X64 = pe.module.arch {
candidates.extend(
sec_buf
.windows(8)
.map(|b| byteorder::LittleEndian::read_u64(b) as VA)
.filter(|&va| va >= min_addr && va < max_addr)
.filter(|&va| pe.module.probe_va(va, Permissions::X)),
)
} else {
candidates.extend(
sec_buf
.windows(4)
.map(|b| byteorder::LittleEndian::read_u32(b) as VA)
.filter(|&va| va >= min_addr && va < max_addr)
.filter(|&va| pe.module.probe_va(va, Permissions::X)),
)
}
}
const CC: u8 = 0xCC;
const NOP: u8 = 0x90;
const RET: u8 = 0xC3;
const RET_FAR: u8 = 0xCB;
const RETN: u8 = 0xC2;
Ok(candidates
.into_iter()
.filter(|&va| {
let mut buf = [0u8; 3];
if matches!(pe.module.address_space.read_into(va - 3, &mut buf), Ok(_)) {
if buf[0] == RETN {
return true;
}
match buf[2] {
CC => return true,
NOP => return true,
RET => return true,
RET_FAR => return true,
_ => (),
}
debug!("pointers: candidate does not follow ret/filler byte: {:#x}", va);
false
} else {
true
}
})
.filter(|&va| {
if let Ok(ptr) = pe.module.read_va_at_va(va) {
if pe.module.probe_va(ptr, Permissions::R) {
debug!("pointers: candidate is a valid pointer: {:#x}", va);
false
} else {
true
}
} else {
true
}
})
.filter(|&va| {
if matches!(pe.module.address_space.read_ascii(va, 4), Ok(_)) {
debug!("pointers: candidate is a string: {:#x}", va);
false
} else {
true
}
})
.map(|va| {
debug!("pointers: valid candidate: {:#x}", va);
va
})
.collect())
}