2

I'm working on a project related to Process Injection for learning Rust. I have to inject shellcode at some points and use the Keystone engine for assembling shellcode from source.

I detected that the rust bindings were not successful assembling syscall; ret shellcode.

I then tried to reproduce by creating a python and rust minimal version and ensuring the syntax in use was the same for both version (also both bindings has the same major and minor versions, which is v0.9)

Python version:

from keystone import *
from capstone import *

code = "syscall; ret"

ks = Ks(KS_ARCH_X86, KS_MODE_64)
ks.syntax = KS_OPT_SYNTAX_INTEL
encoding, count = ks.asm(code)

cs = Cs(CS_ARCH_X86, CS_MODE_64)
disass = cs.disasm(bytes(encoding), 0x1000)

print("Assembly: %s" % code)
print("Binary: %s" % encoding)
print("Disassembly:")
for i in disass:
    print("0x%x:\t%s\t%s" % (i.address, i.mnemonic, i.op_str))

Rust version:

use keystone::{self, MODE_64};
use capstone::{self, prelude::BuildsCapstone};

fn main() {
    let code = "syscall; ret";

    let ks = keystone::Keystone::new(keystone::Arch::X86, MODE_64).unwrap();
    ks.option(keystone::OptionType::SYNTAX, keystone::OPT_SYNTAX_INTEL).unwrap();

    let encoding = ks.asm(code.to_string(), 0x1000).unwrap();

    let cs = capstone::Capstone::new()
                .x86()
                .mode(capstone::arch::x86::ArchMode::Mode64)
                .build().unwrap();
    
    let insns = cs.disasm_all(&encoding.bytes, 0x1000).unwrap();
    println!("Assembly: {}", code);
    println!("Binary: {:?}", encoding.bytes);
    println!("Disassembly:");
    for i in insns.iter() {
        println!("{}", i);
    }
}

Here is the result of running the programs: Testing of both programs

As you can see, the Rust implementation outputs random binary code and I would like to know why.

Is it related to a misunderstanding of rust ? or of the rust bindings ? A bug in the rust bindings ?

I'm kinda stuck in my comprehension of the problem so if anyone can help me.

Regards.

1
  • C:\>python -c "from keystone import *;print(Ks(KS_ARCH_X86 , KS_MODE_64).asm(b'syscall;ret')") ([15, 5, 195], 2) =>0x0f0x050xc3
    – blabb
    Commented Oct 24, 2023 at 18:34

2 Answers 2

3

There is a problem with the keystone crate available on crates.io - It runs with the version 0.9.0 and hasn't been updated for a while. It also has a few bugs which have now been fixed in 0.9.2.

You can use an unofficial binding like this which is getting updates. Or you can use the ones https://github.com/keystone-engine/keystone/tree/master/bindings/rust with your project where it'll build the latest compatible binding with cmake

2

Cmake Version

D:\>cmake --version
cmake version 3.28.0-rc3

CMake suite maintained and supported by Kitware (kitware.com/cmake).

rust version

D:\>cargo -V
cargo 1.73.0 (9c4383fb5 2023-08-26)   
  1. create a project directory md dir
  2. init the project in the directory with cargo init
  3. add the Dependency "keystone-engine" to Cargo.toml with cargo add

D:\>md rustkey

D:\>cd rustkey

D:\rustkey>cargo init
     Created binary (application) package

D:\rustkey>cargo add keystone-engine
    Updating crates.io index
      Adding keystone-engine v0.1.0 to dependencies.
             Features:
             + build-from-src
             + cmake
             - pkg-config
             - use-system-lib
    Updating crates.io index

source to compile

D:\rustkey>cd src

D:\rustkey\src>notepad main.rs

D:\rustkey\src>type main.rs
use keystone_engine::*;
fn main() {
        let engine = Keystone::new(Arch::X86, Mode::MODE_64).expect("Could not initialize Keystone engine");
        let result = engine.asm("syscall;ret".to_string(),0).expect("Could Not Assemble");
        println!("{}",result);
}

D:\rustkey\src>cd ..

build the project

D:\rustkey>cargo build
   Compiling cc v1.0.83
   Compiling libc v0.2.149
   Compiling bitflags v1.3.2
   Compiling cmake v0.1.50
   Compiling keystone-engine v0.1.0
   Compiling rustkey v0.1.0 (D:\rustkey)
    Finished dev [unoptimized + debuginfo] target(s) in 5m 49s

running the project multiple times

    D:\rustkey>cargo -q run
0f05c3

D:\rustkey>cargo -q run
0f05c3

D:\rustkey>cargo -q run
0f05c3

D:\rustkey>cargo -q run
0f05c3
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.