Skip to content

Latest commit

 

History

History
 
 

rust

binaryninja-rs

Official Rust bindings for Binary Ninja.

WARNING

These bindings are still actively under development. Compatibility will break and conventions will change! It is encouraged that you reference a specific commit to avoid having your plugin/application break when the API changes. To specify a specific commit see the cargo documentation here.

If you are worried about breaking changes avoid modules with warnings about instability!

MSRV: The Rust version specified in the Cargo.toml.

Example

use binaryninja::headless::Session;
use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt};

fn main() {
    let headless_session = Session::new().expect("Failed to initialize session");
    let bv = headless_session
        .load("/bin/cat")
        .expect("Couldn't open `/bin/cat`");
    
    println!("Filename:  `{}`", bv.file().filename());
    println!("File size: `{:#x}`", bv.len());
    println!("Function count: {}", bv.functions().len());
    
    for func in &bv.functions() {
        println!("{}:", func.symbol().full_name());
    }
}

More examples can be found in here.

Getting Started

Requirements

  • Having BinaryNinja installed (and your license registered)
    • For headless operation you must have a headless supporting license.
  • Clang
  • Rust

Link to Binary Ninja

Writing a standalone executable or a plugin requires that you link to binaryninjacore directly. The process of locating that however is done for you within the binaryninjacore-sys crate. Because linker arguments are not transitive for executables you must specify them within your build.rs.

Cargo.toml:

[dependencies]
binaryninja = { git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
# Locates binaryninjacore on your system.
binaryninjacore-sys = { git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}

build.rs:

fn main() {
    let link_path =
        std::env::var_os("DEP_BINARYNINJACORE_PATH").expect("DEP_BINARYNINJACORE_PATH not specified");
    
    println!("cargo::rustc-link-lib=dylib=binaryninjacore");
    println!("cargo::rustc-link-search={}", link_path.to_str().unwrap());
    
    #[cfg(not(target_os = "windows"))]
    {
        println!(
            "cargo::rustc-link-arg=-Wl,-rpath,{0},-L{0}",
            link_path.to_string_lossy()
        );
    }
}

Write a Plugin

Plugins are loaded at runtime and as such will have their own initialization routine.

Cargo.toml:

[lib]
crate-type = ["cdylib"]

lib.rs:

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn CorePluginInit() -> bool {
    // Initialize logging
    // Register custom architectures, workflows, demanglers, 
    // function recognizers, platforms and views!
    true
}

Examples for writing a plugin can be found here.

Write a Standalone Executable

If you have a headless supporting license you are able to use Binary Ninja as a regular dynamically loaded library.

Standalone executables must initialize the core themselves. binaryninja::headless::init() to initialize the core, and binaryninja::headless::shutdown() to shutdown the core. Prefer using binaryninja::headless::Session as it will shut down for you once it is dropped.

main.rs:

fn main() {
  // You must initialize the core to use Binary Ninja.
  let session = binaryninja::headless::Session::new().expect("Failed to initialize!");
  // Once `session` is dropped, the core will be shutdown!
}

Offline Documentation

Offline documentation can be generated like any other rust crate, using cargo doc.

git clone https://github.com/Vector35/binaryninja-api
cd binaryninja-api
cargo doc --no-deps --open -p binaryninja

Contributing

If you're thinking of contributing to the Rust API, we encourage you to join the #rust-api channel in our Slack, especially for large-effort PRs.

Testing

When contributing new APIs or refactoring existing APIs it is vital that you test your code! If you do not have a headless supported license you should still be able to write them and open your PR. Once open a maintainer will approve tests to run and from there you can refine the test so that it passes in CI.

Documentation

When refactoring or making new changes make sure that the documentation for the respective APIs is up-to-date and not missing. Much of the APIs documentation exists only in the python bindings, so use that as a guide. If there is an API that confuses you it will likely confuse someone else, and you should make an issue or ask for guidance in the Slack channel above.


Attribution

This project makes use of: