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:

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.