capstone-rust / capstone-rs

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

Exposing `Insn::detail` to the public API #127

Open clubby789 opened 2 years ago

clubby789 commented 2 years ago

I'm writing a project which involves analysing large binaries with Capstone. I'd like to perform the disassembly in a single-thread, then parallelise the higher-level analysis of the disassembled instructions.

However, Capstone is not Send/Sync ( #71 ), and as accessing the detail field can only be done (currently) via the Capstone struct.

Would you consider exposing the pub(crate) function Insn::detail (https://github.com/capstone-rust/capstone-rs/blob/0202ebb1ebd5b64ec7d0167da6baf2b16d285465/capstone-rs/src/instruction.rs#L266-L268) to the public API? This would prevent having to unsafely pass a Capstone handle across threads, as long as the user ensures that the Arch is correct/the pointer is non-null.

tmfink commented 2 years ago

I need to think about it more, but it's possible that it would be safe for Capstone to implement Send (move to completely new thread) but I don't think it would be sound for Capstone to implement Sync (due to the C libraries memory model).

As you disassemble with one thread, you can create your own structure with a copy of the information you want to save and need for analysis. Then, there will be nothing in this library that will prevent you from working in parallel.

This Rust library is designed to to be safe while adding minimal (if any) overhead compared to using the C library directly. Sometimes the compromise makes it less ergonomic (like Capstone not being Sync).

clubby789 commented 2 years ago

I did end up making my own structure with a copy, but it took me a while to sort out lifetimes because InsnDetail references rather than copying the original cs_detail. Since cs_detail is POD and Copy, it might help to introduce a second type which owns this data.

jduck commented 1 year ago

I found this ticket because I'm trying to access some specific members of instruction details. For example, I want to know if a "call" has an immediate operand and if so, what is the immediate value. Is it not currently possible to get access to this information with capston-rs ?

jduck commented 1 year ago

I figured it out:

    fn get_call_target(&self, _my_insn: &MyInsn, cs_det: &InsnDetail) -> Result<u64, String> {
        let ops = cs_det.arch_detail().operands();
        let op0 = &ops[0];
        let op0 = match op0 {
            X86Operand(op) => { op }
            _ => { return Err("Invalid operand type".to_string()) }
        };
        let ea: u64 = match &op0.op_type {
            Imm(op) => { *op as u64 }
            _ => { return Err("Invalid operand type (not immediate)".to_string()) }
        };
        Ok(ea)
   }