use anyhow::Result;
use byteorder::ByteOrder;
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![];
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)?;
if let crate::module::Arch::X64 = pe.module.arch {
candidates.extend(
sec_buf
.windows(8)
.map(|b| byteorder::LittleEndian::read_u64(b) as VA)
.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| pe.module.probe_va(va, Permissions::X)),
)
}
}
const CC: u8 = 0xCC;
const NOP: u8 = 0x90;
const RET: u8 = 0xC3;
Ok(candidates
.into_iter()
.filter(|&va| {
if let Ok(b) = pe.module.address_space.read_u8(va - 1) {
matches!(b, CC | NOP | RET)
} else {
false
}
})
.filter(|&va| {
if let Ok(ptr) = pe.module.read_va_at_va(va) {
!pe.module.probe_va(ptr, Permissions::R)
} else {
true
}
})
.filter(|&va| matches!(pe.module.address_space.read_ascii(va), Err(_)))
.collect())
}