Rust-bindings for the ReOxide decompiler plugin framework
===========================
ReOxide adds a plugin system to the Ghidra decompiler, with the
larger goal of eventually improving the reverse engineering process
of Rust programs in open source tools. While anyone can extend the
Ghidra front end through its Java and Python API, the decompiler runs
as a separate C++ program. You cannot change the decompiler rules
through the Java API, but you can with ReOxide. You can define your
own decompiler actions or rules and better understand the inner
workings of the decompiler.
## Documentation
The [ReOxide homepage](https://reoxide.eu) offers a starting point
for the general documentation of the project:
* [Get started](https://reoxide.eu/guide/getting-started) by
installing the `reoxide` pip package and linking it with a
Ghidra installation.
* Follow the documentation on [how to load plugins](https://reoxide.eu/plugins/loading-plugins)
and [how to create plugins](https://reoxide.eu/plugins/creating-plugins)
yourself.
* For documentation related to the Rust API check out the
[docs.rs page of the ReOxide crate](https://docs.rs/reoxide).
## Examples
The `reoxide` Rust crate offers two different things:
* Allow driving the Ghidra decompiler from Rust.
* Allow writing plugins for the Ghidra decompiler using Rust.
Both require a working ReOxide setup, make sure you can run the
`reoxide` command in the environment where you run your Rust builds
from.
### Driving the Ghidra decompiler from Rust
The `decompile` example shows how to use the decompiler driver. When
you write programs by using the decompiler driver, you have to
tell the program where to find the `reoxide` shared library,
`libreoxide.so`. The `build.rs` build step should automatically link
the library correctly if it can run the `reoxide` command, but
for running the example you might have to set the `LD_LIBRARY_PATH`
manually:
```sh
LD_LIBRARY_PATH=$(reoxide print-ld-library-path)
```
Start off by importing the driver functions:
```rust
use reoxide::driver::*;
```
Currently the driver needs a full Ghidra installation for the processor
definition files. You need to set the path to the root folder of
the Ghidra installation, for example:
```rust
initialize_decompiler(Path::new("/opt/ghidra"), true).unwrap();
```
You can also enable or disable the ReOxide plugin system with the
last parameter. Afterwards you initialize a decompiler context with
the raw bytes of the program and the architecture specification string
from Ghidra:
```rust
let mut ctx = RawFileContext::from_bytes("x86:LE:64:default", &PROGRAM).unwrap();
```
Decompilation works on the *function* level, so you first need to define
a function at the address you want to decompile:
```rust
let addr = 0x0;
ctx.define_function(addr, "fibonacci").unwrap();
```
Finally, you can decompile the function at the address:
```rust
let decomp = ctx.decompile_function(addr)?;
println!("{}", decomp);
```
Here you can see the full example source code:
```rust
use std::env;
use std::path::Path;
use reoxide::driver::*;
const PROGRAM: &[u8] = &[
0x55, 0x48, 0x89, 0xe5, 0x53, 0x48, 0x83, 0xec, 0x18, 0x89, 0x7d, 0xec, 0x83, 0x7d, 0xec, 0x00,
0x74, 0x06, 0x83, 0x7d, 0xec, 0x01, 0x75, 0x07, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xeb, 0x1e, 0x8b,
0x45, 0xec, 0x83, 0xe8, 0x01, 0x89, 0xc7, 0xe8, 0xfb, 0xfe, 0xff, 0xff, 0x89, 0xc3, 0x8b, 0x45,
0xec, 0x83, 0xe8, 0x02, 0x89, 0xc7, 0xe8, 0xec, 0xfe, 0xff, 0xff, 0x01, 0xd8, 0x48, 0x8b, 0x5d,
0xf8, 0xc9, 0xc3,
];
fn main() -> Result<(), DecompError> {
let ghidra_dir = env::var("GHIDRA_INSTALL_DIR").expect(
"Please provide an environment variable \
GHIDRA_INSTALL_DIR with the path to the Ghidra root directory. \
This is needed to find the SLEIGH specification files",
);
initialize_decompiler(Path::new(&ghidra_dir), true)?;
let mut ctx = RawFileContext::from_bytes("x86:LE:64:default", &PROGRAM)?;
let addr = 0x0;
ctx.define_function(addr, "fib")?;
let decomp = ctx.decompile_function(addr)?;
println!("{}", decomp);
Ok(())
}
```
## Acknowledgements
Special thanks to [rust-sfml](https://github.com/jeremyletang/rust-sfml)
and the [foreign-types library](https://github.com/sfackler/foreign-types)
for showing how to do certain FFI related things.