capstone-rust / capstone-rs

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

How to access the inner arm_op_mem struct? #128

Closed pr0me closed 2 years ago

pr0me commented 2 years ago

Hey, I can't seem to figure out how to access the inner arm_op_mem in a Mem(ArmOpMem). The following code gives me Mem(ArmOpMem(arm_op_mem { base: 11, index: 0, scale: 1, disp: 8, lshift: 0 })) from which I want to access, e.g., disp:

let arch_detail = detail.arch_detail();
let mut ops = arch_detail.arm().unwrap().operands();

println!("{:?}", "", &ops.nth(1).unwrap().op_type);

Sorry if it's obvious but I can't seem to see through the ffi.

pr0me commented 2 years ago

Found a (super dirty) solution:

unsafe {
    let op = ops.nth(1).unwrap();
    let mem_op: capstone_sys::arm_op_mem = 
        *((&(*((core::ptr::addr_of!(op.op_type) as u32 + std::mem::size_of::<usize>()) 
        as *const ArmOperandType)) as *const _) 
        as *const capstone_sys::arm_op_mem);
}

Feel free to let me know whether there is a better way.

tmfink commented 2 years ago

The .op_type field gives you an instance of the ArmOperandType enum. Just like any enum, you can use a match or if let statement to destructure the value. The Mem variant contains a ArmOpMem which you want.

The underlying cs_op_mem is not directly accessible, but you don't need the ArmOpMem has accessor methods.

use capstone::arch::arm::ArmOperandType;
use capstone::prelude::*;
use capstone::InsnDetail;

const ARM_CODE: &[u8] = b"\x04\xe0\x2d\xe5";

fn main() {
    let cs: Capstone = Capstone::new()
        .arm()
        .mode(arch::arm::ArchMode::Arm)
        .detail(true)
        .build()
        .unwrap();

    let insns = cs.disasm_all(ARM_CODE, 0x1000).unwrap();

    let insn = insns.iter().next().unwrap();
    println!("{}", insn);

    let detail: InsnDetail = cs.insn_detail(&insn).unwrap();
    let arch_detail: ArchDetail = detail.arch_detail();
    let arm_detail = arch_detail.arm().unwrap();
    let op = arm_detail.operands().nth(1).unwrap();

    println!("op = {:?}", op);

    match op.op_type {
        ArmOperandType::Mem(arm_op_mem) => {
            println!("disp = {}", arm_op_mem.disp());
        }
        _ => (), // ignored for now
    }
}
tmfink commented 2 years ago

Found a (super dirty) solution: ... Feel free to let me know whether there is a better way.

I think my above solution is preferred since this invokes undefined behavior (could not work on different host platform or different compiler version). 😉

pr0me commented 2 years ago

ah right! Yea, definitely more idiomatic and less UB :P

Thank you