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
Add dependencies
Add to your 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" }
Create build.rs
Create build.rs to link Binary Ninja core: 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
);
}
}
Write code
Start using the API: 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
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:
Configure as cdylib
In Cargo.toml: [ lib ]
crate-type = [ "cdylib" ]
Implement CorePluginInit
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
}
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