Skip to main content
The Binary Ninja Rust API provides safe, idiomatic Rust bindings for the Binary Ninja core. It’s actively developed and used for production plugins.
The Rust API is under active development. Compatibility may break between versions. Pin to a specific commit in production.

Features

Type safety

Leverage Rust’s type system for safer binary analysis

Memory safety

Automatic memory management with reference counting

Performance

Zero-cost abstractions over the C++ core

Headless support

Full headless automation capabilities

Installation

Requirements

  • Binary Ninja installed with a registered license
  • Headless license for standalone executables
  • Clang (for building)
  • Rust toolchain

Adding to your project

1

Add dependencies

Add to your Cargo.toml:
Cargo.toml
[dependencies]
binaryninja = { git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev" }
binaryninjacore-sys = { git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev" }
Pin to a specific commit for production use:
binaryninja = { git = "...", rev = "abc123" }
2

Create build.rs

Create build.rs to link Binary Ninja core:
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(target_os = "linux")]
    {
        println!(
            "cargo::rustc-link-arg=-Wl,-rpath,{0},-L{0}",
            link_path.to_string_lossy()
        );
    }

    #[cfg(target_os = "macos")]
    {
        let crate_name = std::env::var("CARGO_PKG_NAME")
            .expect("CARGO_PKG_NAME not set");
        let lib_name = crate_name.replace('-', "_");
        println!(
            "cargo::rustc-link-arg=-Wl,-install_name,@rpath/lib{}.dylib",
            lib_name
        );
    }
}
3

Write code

Start using the API:
main.rs
use binaryninja::headless::Session;
use binaryninja::binary_view::{BinaryViewBase, BinaryViewExt};

fn main() {
    let session = Session::new()
        .expect("Failed to initialize Binary Ninja");

    let bv = session.load("/bin/ls")
        .expect("Failed to open binary");

    println!("Functions: {}", bv.functions().len());
    // Session automatically shuts down when dropped
}

Quick example

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

fn main() {
    let session = Session::new().expect("Failed to initialize session");
    let bv = session.load("/bin/cat").expect("Couldn't open `/bin/cat`");

    println!("File: `{}`", bv.file().filename());
    println!("File size: `{:#x}`", bv.len());
    println!("Function count: {}", bv.functions().len());

    for func in &bv.functions() {
        println!("{:#x}: {}", func.start(), func.symbol().full_name());
    }
}
From rust/examples/simple.rs

Writing plugins

Rust plugins are dynamic libraries loaded by Binary Ninja:
1

Configure as cdylib

In Cargo.toml:
[lib]
crate-type = ["cdylib"]
2

Implement CorePluginInit

lib.rs
use binaryninja::command::Command;

struct MyCommand;

impl Command for MyCommand {
    fn name(&self) -> &'static str {
        "My Plugin"
    }

    fn description(&self) -> &'static str {
        "Does something cool"
    }

    fn action(&self, view: &binaryninja::binary_view::BinaryView) {
        println!("Plugin running on {}", view.file().filename());
    }
}

#[no_mangle]
pub extern "C" fn CorePluginInit() -> bool {
    binaryninja::command::register(
        "My Plugin",
        "Description",
        MyCommand
    );
    true
}
3

Build and install

cargo build --release
cp target/release/libmyplugin.so ~/.binaryninja/plugins/

Logging

Use the tracing crate for logging:
use binaryninja::tracing_init;
use tracing::{info, warn, error};

#[no_mangle]
pub extern "C" fn CorePluginInit() -> bool {
    // Initialize tracing subscriber
    tracing_init!();

    info!("Plugin initialized");
    warn!("This is a warning");
    error!("This is an error");

    true
}
Call tracing_init!() at the start of CorePluginInit() to enable logging.

Memory management

The Rust API uses Ref<T> smart pointers that automatically manage reference counts:
use binaryninja::rc::Ref;
use binaryninja::binary_view::BinaryView;

// Ref automatically increments/decrements reference count
fn process_view(bv: &Ref<BinaryView>) {
    // Use bv
    println!("Processing {}", bv.file().filename());
} // bv reference count decremented here

Error handling

Most operations return Result types:
use binaryninja::binary_view::BinaryViewExt;

match session.load("/path/to/binary") {
    Ok(bv) => {
        // Successfully loaded
        analyze_binary(&bv);
    }
    Err(_) => {
        eprintln!("Failed to load binary");
    }
}

Type system

The Rust API provides type-safe access to Binary Ninja types:
use binaryninja::types::{Type, Conf};

// Create types
let int_type = Type::int(4, false);  // 32-bit signed int
let ptr_type = Type::pointer(&arch, &int_type);  // int32_t*

// Types with confidence
let conf_type = Conf::new(int_type, 255);  // Maximum confidence

Module organization

The Rust API is organized into modules:
  • binary_view - Binary views and file access
  • architecture - CPU architectures
  • function - Functions and analysis
  • low_level_il, medium_level_il, high_level_il - IL representations
  • types - Type system
  • platform - Platform definitions
  • settings - Configuration
  • headless - Headless initialization

Examples

Complete examples are available:

API documentation

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

Next steps

Binary view

Work with binary files

Functions

Analyze functions

Headless

Automation and scripting

Examples

See complete examples

Build docs developers (and LLMs) love