1. Keystone Engine
#keystone-engine #assembler #golang-bindings
Keystone Engine
From the official website this is how keystone is described:
Keystone is a lightweight multi-platform, multi-architecture assembler framework.
Highlight features:
Multi-architecture, with support for Arm, Arm64 (AArch64/Armv8), Ethereum Virtual Machine, Hexagon, Mips, PowerPC, Sparc, SystemZ, & X86 (include 16/32/64bit).
Clean/simple/lightweight/intuitive architecture-neutral API.
Implemented in C/C++ languages, with bindings for Java, Masm, Visual Basic, C#, PowerShell, Perl, Python, NodeJS, Ruby, Go, Rust, Haskell & OCaml available.
Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed).
Thread-safe by design.
Open source.
Keystone is based on LLVM, but it goes much further with a lot more to offer. Find in this Blackhat USA 2016 slides more technical details behind our assembler engine.
Keystone with GoLang
A package with go bindings is provided here but unfortunately it requires cgo to compile. I love both go and c but cgo is appalling in my opinion. Thankfully the keystone engine provides a DLL we can use. The caveat when using the dll is that it will only run on windows.
If you need to run keystone on linux it's probably easier to use python instead (or cgo).
Documentation
There is no real documentation for the framework. A few examples can be found here and some on their github page.
What I found useful is to download the Windows-Core Engine from here (it includes the precompiled dll).
In the 'includes' folder the keystone.h file can be found with descriptions of the exported functions and how the framework should be used. A sample from the header is shown below:
Golang Implementation
Up until now I only needed to develop 32 and 64bit shellcode for x86 architecture, so I will not bother adding extra constants for arm etc.
Also I am not planning to implement this as part of a large project so I will not implement functions such as ks_free() that frees memory.
Keystone functions
The following functions will be implemented:
ks_open (creates a new instance of keystone)
ks_asm (it receives the assembly string and returns the assembly equivalent bytes)
Let's dive into it.
Code
Firstly we need to download the dll from here and include it in our current working path. We then import the dll using LoadLibrary from the windows package.
As mentioned previously from the exported functions we will only use ks_open and ks_asm. Using GetProcAddress from the windows package we can get the functions' addresses.
ks_open() function
As we can see from the above definition in the keystone header we need to define the architecture, mode and provide a pointer of the location where our session handle will be stored.
The architecture constants are defined below
And the modes:
From the definitions above we will only go ahead and implement the following :
With everything required in place we can go ahead and call the function. If 32-bit shellcode is required we should change MODE_64 to MODE_32.
ks_asm() function
From the above definition we will require the following:
the handle returned by ks_open stored in variable ksSession .
We then require a pointer to our null terminated string.
address can be ignored so it will be set to 0
A pointer for the buffer to be written
A pointer for the size of the buffer to be written
A pointer for the number of statements successfully processed
In order to get a pointer to null terminated string the following code can be used.
We now have everything we need to call the the ks_asm function
Bytes in a slice
We then go ahead and copy the memory contents to a byte slice using the following code .
Test code
Let's test our code to ensure we get the expected results.
With this sequence of commands we should expect the following output

The output of our script matches the expected results. Great :)

Last updated
Was this helpful?