keystone icon indicating copy to clipboard operation
keystone copied to clipboard

Rust binding give out random values

Open zer0x64 opened this issue 6 years ago • 1 comments
trafficstars

Running on linux x86_64 with version crates.io version 0.9.0. When I assemble something for x86_64, the Rust keystone package returns inconsistent and seemingly random values. For example, if I try to assemble a single "nop", it gives out a single byte value between 0x00 and 0xF0 (a multiple of 0x10, so the right-most hex character is always 0). Haven't really checked if this is fixed on the current version that's not on crates.io.

zer0x64 avatar Jun 25 '19 19:06 zer0x64

Currently 0.9.0 is indeed currently the latest version on crates.io so that's a problem. I was able to reproduce the described issue with the following code:

use ::keystone::{
    Arch,
    keystone_const::*,
    Keystone,
};

fn main ()
{
    let keystone = Keystone::new(
        Arch::X86,
        Mode::MODE_32,
    ).unwrap();
    for _ in 0 .. 1_000 {
        let bytes = keystone.asm("nop".into(), 0).unwrap().bytes;
        assert_eq!(bytes, [0x90]);
    }
}

Their current version 0.10.0 seems to fix the issue, at least for a single threaded scenario. So you can fix this by using the following config in your Cargo.toml:

[dependencies.keystone]
git = "https://github.com/keystone-engine/keystone"
rev = "c4de98f71f05f356817f5e91fee0d509c7b0b440"  # latest master as of 2019/10/16

while waiting for the official release.


In a multi-threaded scenario, however, the API is at least buggy, and I even suspect it to be unsound: all the functions taking a Keystone instance to perform FFI operations just take it by &self, i.e., by shared reference. Moreover, since FFI raw pointers are represented as size_t = usize from the Rust side, the Sync trait was not auto-unimplemented as it should have; thus leading to Keystone : Sync. Combined with the &self API, this means that FFI functions can be called by multiple threads in parallel using the same Keystone instance, and I doubt that such thing is sound.

For instance, the following program panic!s when using the currently latest revision of master (c4de98f71f05f356817f5e91fee0d509c7b0b440) :

use ::keystone::{
    Arch,
    Mode,
    Keystone,
};

fn main ()
{
    let keystone = Keystone::new(
        Arch::X86,
        Mode::MODE_32,
    ).unwrap();
    
    ::crossbeam::thread::scope(|scope| {
        scope.spawn(|_| {
            loop {
                let bytes = keystone.asm("nop".into(), 0).unwrap().bytes;
                assert_eq!(bytes, [0x90]);
            }
        });
        loop {
            let bytes = keystone.asm("nop".into(), 0).unwrap().bytes;
            assert_eq!(bytes, [0x90]);
        }
    }).unwrap();
}

danielhenrymantilla avatar Oct 16 '19 14:10 danielhenrymantilla