capstone-rust / capstone-rs

high-level Capstone system bindings for Rust
213 stars 75 forks source link

Determining if an instruction is a conditional branch or not. #138

Closed vext01 closed 1 year ago

vext01 commented 1 year ago

Hi,

Maybe this is an upstream capstone problem, but I don't see a way to determine if an instruction is a conditional branch.

I'm looking at: https://docs.rs/capstone/0.11.0/capstone/InsnGroupType/index.html

The classifications are quite broad.

Would I be forced to enumerate all the mnemonics for conditional branch instructions and do string comparisons?

Thanks

tmfink commented 1 year ago

Sorry for the slow reply--I wanted to give you a good answer. You don't need to do a string comparison, you can instead do integer comparisons with the InsnGroupType and InsnId.

I know this is not as ergonomic as as a simple enum comparison, but that would require some more work with the underlying C library.

Here's some example code for how you could do with with X86:

use capstone::prelude::*;
use capstone::{arch::x86::X86Insn, Insn, InsnDetail, InsnGroupType};

const X86_CODE: &[u8] = b"\xe9\x04\x03\x02\x01\x74\x02\xff\xd0\xc3";

fn is_x86_conditional_branch(detail: &InsnDetail, insn: &Insn) -> bool {
    let is_branch = detail
        .groups()
        .contains(&InsnGroupId(InsnGroupType::CS_GRP_JUMP as u8));
    let is_unconditional_branch = insn.id().0 == X86Insn::X86_INS_JMP as u32;

    is_branch && !is_unconditional_branch
}

fn main() -> CsResult<()> {
    let cs = Capstone::new()
        .x86()
        .mode(arch::x86::ArchMode::Mode64)
        .syntax(arch::x86::ArchSyntax::Att)
        .detail(true)
        .build()?;

    let insns = cs.disasm_all(X86_CODE, 0x1000)?;
    println!("Found {} instructions", insns.len());

    for i in insns.iter() {
        println!();
        println!("{}", i);

        let detail: InsnDetail = cs.insn_detail(i)?;

        let output: &[(&str, String)] = &[
            ("insn id:", format!("{:?}", i.id().0)),
            ("bytes:", format!("{:02x?}", i.bytes())),
            (
                "is_cond_branch",
                format!("{:?}", is_x86_conditional_branch(&detail, i)),
            ),
        ];

        for &(ref name, ref message) in output.iter() {
            println!("{:4}{:12} {}", "", name, message);
        }
    }

    Ok(())
}