use crate::analysis::aarch64;
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,
}
fn fmt_x86(insn: &Instruction) -> String {
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 s = String::new();
fmt.format(insn, &mut s);
s
}
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() || arch == Arch::Aarch64
}
pub fn disassemble(
bytes: &[u8],
file_off: u64,
va: u64,
bits: u32,
arch: Arch,
count: usize,
) -> Vec<Insn> {
let start = file_off as usize;
if start >= bytes.len() {
return Vec::new();
}
let code = &bytes[start..];
if arch == Arch::Aarch64 {
let mut out = Vec::with_capacity(count);
let mut ip = va;
let mut pos = 0usize;
while out.len() < count && pos + 4 <= code.len() {
let Some(w) = aarch64::decode(&code[pos..], ip) else {
break;
};
out.push(Insn {
addr: w.addr,
bytes: code[pos..pos + w.len].to_vec(),
text: w.text,
});
pos += w.len;
ip += w.len as u64;
}
return out;
}
let mut decoder = Decoder::with_ip(bits, code, va, DecoderOptions::NONE);
let mut out = Vec::with_capacity(count);
let mut insn = Instruction::default();
while out.len() < count && decoder.can_decode() {
decoder.decode_out(&mut insn);
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: fmt_x86(&insn),
});
}
out
}