use crate::model::{Arch, Binary};
use iced_x86::{Decoder, DecoderOptions, Formatter, Instruction, IntelFormatter};
pub struct Insn {
pub addr: u64,
pub bytes: Vec<u8>,
pub text: String,
}
pub fn vaddr_to_off(bin: &Binary, vaddr: u64) -> Option<u64> {
for s in &bin.sections {
let span = s.vsize.max(s.file_size);
if s.vaddr != 0 && vaddr >= s.vaddr && vaddr < s.vaddr + span {
return Some(s.file_off + (vaddr - s.vaddr));
}
}
None
}
pub fn entry_location(bin: &Binary, bytes: &[u8]) -> Option<(u64, u64)> {
let (off, va) = match bin.format {
crate::model::Format::Pe => (vaddr_to_off(bin, bin.entry)?, bin.image_base + bin.entry),
crate::model::Format::Elf => (vaddr_to_off(bin, bin.entry)?, bin.entry),
_ => {
if let Some(o) = vaddr_to_off(bin, bin.entry) {
(o, bin.entry)
} else if bin.entry < bytes.len() as u64 {
(bin.entry, bin.entry)
} else {
return None;
}
}
};
if off < bytes.len() as u64 {
Some((off, va))
} else {
None
}
}
pub fn supported(arch: Arch) -> bool {
arch.is_x86()
}
pub fn disassemble(bytes: &[u8], file_off: u64, va: u64, bits: u32, count: usize) -> Vec<Insn> {
let start = file_off as usize;
if start >= bytes.len() {
return Vec::new();
}
let code = &bytes[start..];
let mut decoder = Decoder::with_ip(bits, code, va, DecoderOptions::NONE);
let mut fmt = IntelFormatter::new();
fmt.options_mut().set_uppercase_hex(false);
fmt.options_mut().set_hex_prefix("0x");
fmt.options_mut().set_hex_suffix("");
fmt.options_mut().set_space_after_operand_separator(true);
let mut out = Vec::with_capacity(count);
let mut insn = Instruction::default();
let mut text = String::new();
while out.len() < count && decoder.can_decode() {
decoder.decode_out(&mut insn);
text.clear();
fmt.format(&insn, &mut text);
let lo = (insn.ip() - va) as usize;
let hi = lo + insn.len();
let raw = code.get(lo..hi).unwrap_or(&[]).to_vec();
out.push(Insn {
addr: insn.ip(),
bytes: raw,
text: text.clone(),
});
}
out
}