|
|
|
@ -0,0 +1,136 @@ |
|
|
|
|
# bddisasm |
|
|
|
|
|
|
|
|
|
Rust bindings for the [bddisasm](https://github.com/bitdefender/bddisasm) x86/x64 decoder library, built on top |
|
|
|
|
of [bddisasm-sys](https://crates.io/crates/bddisasm-sys). |
|
|
|
|
|
|
|
|
|
It supports all existing x86 instruction, offering a wide range of information about each one, including: |
|
|
|
|
|
|
|
|
|
- operands (implicit and explicit) |
|
|
|
|
- access mode for each operand |
|
|
|
|
- CPUID feature flags |
|
|
|
|
- CPU modes in which an instruction is valid |
|
|
|
|
|
|
|
|
|
## Usage |
|
|
|
|
|
|
|
|
|
Add `bddisasm` to your `Cargo.toml`: |
|
|
|
|
|
|
|
|
|
```toml |
|
|
|
|
[dependencies] |
|
|
|
|
bddisasm = "0.1.0" |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
## Examples |
|
|
|
|
|
|
|
|
|
### Decoding one instruction |
|
|
|
|
|
|
|
|
|
```rust |
|
|
|
|
use bddisasm::decoded_instruction::{DecodedInstruction, DecodeMode, Mnemonic}; |
|
|
|
|
|
|
|
|
|
let code = vec![0x31, 0xc0]; |
|
|
|
|
match DecodedInstruction::decode(&code, DecodeMode::Bits32) { |
|
|
|
|
Ok(ins) => { |
|
|
|
|
assert_eq!(ins.mnemonic(), Mnemonic::Xor); |
|
|
|
|
println!("{}", ins); |
|
|
|
|
}, |
|
|
|
|
Err(err) => println!("Unable to decode: {}", err), |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### Decoding multiple instructions |
|
|
|
|
|
|
|
|
|
```rust |
|
|
|
|
use bddisasm::decoder::{Decoder, DecodeMode}; |
|
|
|
|
|
|
|
|
|
let code = [ |
|
|
|
|
// ENCLS |
|
|
|
|
0x0f, 0x01, 0xcf, |
|
|
|
|
// MOV rax, qword ptr [rbx+rcx*4+0x1234] |
|
|
|
|
0x48, 0x8b, 0x84, 0x8b, 0x34, 0x12, 0x00, 0x00, |
|
|
|
|
// Not a valid instruction |
|
|
|
|
0x0f, |
|
|
|
|
// WRMSR |
|
|
|
|
0x0f, 0x30, |
|
|
|
|
]; |
|
|
|
|
let decoder = Decoder::new(&code, DecodeMode::Bits64, 0x1234); |
|
|
|
|
|
|
|
|
|
for ins in decoder { |
|
|
|
|
match ins { |
|
|
|
|
Ok(ins) => println!("{}", ins), |
|
|
|
|
Err(e) => println!("{}", e), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
This will print: |
|
|
|
|
|
|
|
|
|
```text |
|
|
|
|
ENCLS |
|
|
|
|
MOV rax, qword ptr [rbx+rcx*4+0x1234] |
|
|
|
|
the provided input buffer is too small |
|
|
|
|
WRMSR |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
### Working with instruction operands |
|
|
|
|
|
|
|
|
|
Rich informaion is offered for each type of operand. Bellow is a minimal example that looks at a memory operand. |
|
|
|
|
|
|
|
|
|
```rust |
|
|
|
|
# use bddisasm::decode_error::DecodeError; |
|
|
|
|
# fn test() -> Result<(), DecodeError> { |
|
|
|
|
use bddisasm::decoded_instruction::{DecodedInstruction, DecodeMode}; |
|
|
|
|
use bddisasm::operand::OpInfo; |
|
|
|
|
|
|
|
|
|
// ` MOV rax, qword ptr [rcx+r15*2]` |
|
|
|
|
let code = b"\x4a\x8b\x04\x79"; |
|
|
|
|
let ins = DecodedInstruction::decode(code, DecodeMode::Bits64).unwrap(); |
|
|
|
|
// Get the operands |
|
|
|
|
let operands = ins.operands(); |
|
|
|
|
// Get the second operand which is the source (`[rcx+r15*2]`) |
|
|
|
|
let src = operands[1]; |
|
|
|
|
|
|
|
|
|
println!("Source operand type: {}", src.info); |
|
|
|
|
match src.info { |
|
|
|
|
OpInfo::Mem(mem) => { |
|
|
|
|
if let Some(base) = mem.base { |
|
|
|
|
println!("Base register: {}", base); |
|
|
|
|
} else { |
|
|
|
|
println!("No base register"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let Some(index) = mem.index { |
|
|
|
|
println!("Index register: {}", index); |
|
|
|
|
} else { |
|
|
|
|
println!("No index register"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let Some(scale) = mem.scale { |
|
|
|
|
println!("Scale: {}", scale); |
|
|
|
|
} else { |
|
|
|
|
println!("No scale"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if let Some(displacement) = mem.disp { |
|
|
|
|
println!("Displacement: {}", displacement); |
|
|
|
|
} else { |
|
|
|
|
println!("No displacement"); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
_ => unreachable!(), |
|
|
|
|
} |
|
|
|
|
# Ok(()) |
|
|
|
|
# } |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
Will print: |
|
|
|
|
|
|
|
|
|
```text |
|
|
|
|
Source operand type: memory |
|
|
|
|
Base register: 1 |
|
|
|
|
Index register: 15 |
|
|
|
|
Scale: 2 |
|
|
|
|
No displacement |
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
## Requirements |
|
|
|
|
|
|
|
|
|
Because [bddisasm-sys](https://crates.io/crates/bddisasm-sys) uses [bindgen](https://crates.io/crates/bindgen) to generate the bindings at build time, users need to have `clang` installed. Check the [bindgen documentation](https://rust-lang.github.io/rust-bindgen/requirements.html) for more information. |