#![allow(non_snake_case)]
use anyhow::Result;
use regex::bytes::Regex;
use crate::{aspace::AddressSpace, loader::pe::PE, VA};
lazy_static! {
static ref PATTERNS: Regex = {
let CC = r"\xCC";
let CCCC = r"\xCC\xCC";
let NOP = r"\x90";
let RET = r"\xC3";
let LEAVE_RET = r"\xC9\xC3";
let JMP_FAR = r"\xFF\x25....";
let PREPATTERN = format!("(?P<prepattern>{})", vec![
CC,
CCCC,
NOP,
RET,
LEAVE_RET,
JMP_FAR,
].join("|"));
let P0 = r"\x55\x8B\xEC";
let P6 = r"\x8B\xFF\x55\x8B\xEC";
let POSTPATTERN = format!("(?P<postpattern>{})", vec![
P0,
P6,
].join("|"));
let re = format!(
r"(?x) # whitespace allowed
(?-u) # disable unicode mode, so we can match raw bytes
(:?{}) # capture the pre match
(:?{}) # capture the match
",
PREPATTERN,
POSTPATTERN,
);
Regex::new(&re).unwrap()
};
}
#[allow(dead_code)]
const INDEX_ALL: usize = 0;
#[allow(dead_code)]
const INDEX_PREMATCH: usize = 2;
const INDEX_MATCH: usize = 4;
pub fn find_function_prologues(pe: &PE) -> Result<Vec<VA>> {
let mut ret = vec![];
for section in pe.executable_sections() {
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)?;
for capture in PATTERNS.captures_iter(&sec_buf) {
let m = capture.get(INDEX_MATCH).unwrap();
let va = vstart + m.start() as u64;
ret.push(va);
}
}
Ok(ret)
}