Skip to content

Commit

Permalink
Resolves #2521
Browse files Browse the repository at this point in the history
  • Loading branch information
ElykDeer committed Jun 29, 2021
1 parent 58e515b commit e629200
Show file tree
Hide file tree
Showing 11 changed files with 537 additions and 131 deletions.
55 changes: 2 additions & 53 deletions rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

> :warning: **These bindings are in a very early beta, only have partial support for the core APIs and are still actively under development. Compatibility _will_ break and conventions _will_ change! They are being used for core Binary Ninja features however, so we expect much of what is already there to be reliable enough to build on, just don't be surprised if your plugins/scripts need to hit a moving target.**
> :warning: This project requires Rust Nightly to build with those fancy linker arguments
> :warning: This project requires **Rust Nightly** to build with those fancy linker arguments

## Dependencies
Expand All @@ -16,58 +16,7 @@ Rust **Nightly**

## How to use

### To write a plugin:

`Cargo.toml`:
```
[lib]
crate-type = ["cdylib"]
[dependencies]
binaryninja = {git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
```

`src/main.rs`:
See the `./examples/`. Plugin registration commands are in `binaryninja::command::*`


### To write a headless script:

`Cargo.toml`:
```
[dependencies]
binaryninja = { git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
```

`src/main.rs`:
```
use binaryninja::version;
use binaryninja::architecture::Architecture;
use binaryninja::binaryview::{BinaryViewBase, BinaryViewExt};
fn main() {
println!("BinaryNinja Version: `{}`", version());
println!("Loading plugins..."); // This loads all the core architecture, platform, etc plugins
binaryninja::headless::init();
println!("Loading binary...");
let bv = binaryninja::open_view("/bin/cat").expect("Couldn't open `/bin/cat`");
println!("Filename: `{}`", bv.metadata().filename());
println!("File size: `{:#x}`", bv.len());
println!("Function count: {}", bv.functions().len());
for func in &bv.functions() {
println!(" `{}`:", func.symbol().full_name());
}
// Important! You need to call shutdown or your script will hang forever
binaryninja::headless::shutdown();
}
```

All headless scripts should call both `binaryninja::headless::init()` and `binaryninja::headless::shutdown()`.
See [`examples/template`](examples/template).

---

Expand Down
92 changes: 14 additions & 78 deletions rust/binaryninjacore-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,6 @@ use std::io::BufRead;
use std::io::BufReader;
use std::path::PathBuf;

#[cfg(target_os = "macos")]
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");

#[cfg(target_os = "linux")]
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");

#[cfg(windows)]
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");

// Check last run location for path to BinaryNinja; Otherwise check the default install locations
fn link_path() -> PathBuf {
use std::io::prelude::*;

let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);

File::open(lastrun)
.and_then(|f| {
let mut binja_path = String::new();
let mut reader = BufReader::new(f);

reader.read_line(&mut binja_path)?;
Ok(PathBuf::from(binja_path.trim()))
})
.unwrap_or_else(|_| {
#[cfg(target_os = "macos")]
return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");

#[cfg(target_os = "linux")]
return home.join("binaryninja");

#[cfg(windows)]
return PathBuf::from(env::var("PROGRAMFILES").unwrap())
.join("Vector35\\BinaryNinja\\");
})
}

fn main() {
println!("cargo:rerun-if-changed=../../binaryninjacore.h");

Expand All @@ -54,38 +17,6 @@ fn main() {
let llvm_version = env::var("LLVM_VERSION");
let llvm_install_dir = env::var("LLVM_INSTALL_DIR");

// Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
let install_path = env::var("BINARYNINJADIR")
.map(PathBuf::from)
.unwrap_or_else(|_| link_path());

#[cfg(target_os = "linux")]
println!(
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
install_path.to_str().unwrap(),
install_path.to_str().unwrap(),
);

#[cfg(not(target_os = "linux"))]
println!(
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
install_path.to_str().unwrap(),
install_path.to_str().unwrap(),
);

// TODO : Clean this up even more
#[warn(unused_assignments)]
let is_mac = {
#[cfg(target_os = "macos")]
{
true
}
#[cfg(not(target_os = "macos"))]
{
false
}
};

let current_line = "#define BN_CURRENT_UI_ABI_VERSION ";
let minimum_line = "#define BN_MINIMUM_UI_ABI_VERSION ";
let mut current_version = "0".to_string();
Expand All @@ -100,8 +31,6 @@ fn main() {
}
}

// Difference between global LLVM/Clang install and custom LLVM/Clang install...
// First option is for the build server, second option is being nice to our dev who have `LLVM_INSTALL_DIR` set, third is for people with "normal" setups (and Macs)
let mut bindings = bindgen::builder()
.header("../../binaryninjacore.h")
.clang_arg("-std=c++17")
Expand All @@ -121,13 +50,20 @@ fn main() {
minimum_version
))
.rustified_enum("BN.*");
if let (false, Ok(llvm_dir), Ok(llvm_version)) = (is_mac, llvm_dir, llvm_version) {
let llvm_include_path = format!("-I{}/clang/{}/include", llvm_dir, llvm_version);
bindings = bindings.clang_arg(llvm_include_path);
} else if let (false, Ok(llvm_install_dir)) = (is_mac, llvm_install_dir) {
let llvm_include_path = format!("-I{}/12.0.0/lib/clang/12.0.0/include", llvm_install_dir);
env::set_var("LIBCLANG_PATH", format!("{}/12.0.0/lib", llvm_install_dir));
bindings = bindings.clang_arg(llvm_include_path);

// Difference between global LLVM/Clang install and custom LLVM/Clang install...
// First option is for the build server, second option is being nice to our dev who have `LLVM_INSTALL_DIR` set, default is for people with "normal" setups (and Macs)
#[cfg(not(target_os = "macos"))]
{
if let (Ok(llvm_dir), Ok(llvm_version)) = (llvm_dir, llvm_version) {
let llvm_include_path = format!("-I{}/clang/{}/include", llvm_dir, llvm_version);
bindings = bindings.clang_arg(llvm_include_path);
} else if let Ok(llvm_install_dir) = llvm_install_dir {
let llvm_include_path =
format!("-I{}/12.0.0/lib/clang/12.0.0/include", llvm_install_dir);
env::set_var("LIBCLANG_PATH", format!("{}/12.0.0/lib", llvm_install_dir));
bindings = bindings.clang_arg(llvm_include_path);
}
}

bindings
Expand Down
85 changes: 85 additions & 0 deletions rust/examples/basic_script/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)

if(CMAKE_BUILD_TYPE MATCHES Debug)
set(TARGET_DIR ${PROJECT_BINARY_DIR}/target/debug)
set(CARGO_OPTS --target-dir=${PROJECT_BINARY_DIR}/target)
else()
set(TARGET_DIR ${PROJECT_BINARY_DIR}/target/release)
set(CARGO_OPTS --target-dir=${PROJECT_BINARY_DIR}/target --release)
endif()

project(test_headless)

file(GLOB PLUGIN_SOURCES
${PROJECT_SOURCE_DIR}/Cargo.toml
${PROJECT_SOURCE_DIR}/src/*.rs)

file(GLOB API_SOURCES
${PROJECT_SOURCE_DIR}/../../../binaryninjacore.h
${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/build.rs
${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/Cargo.toml
${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/src/*
${PROJECT_SOURCE_DIR}/../../Cargo.toml
${PROJECT_SOURCE_DIR}/../../src/*.rs)

set(OUTPUT_FILE basic_script${CMAKE_EXECUTABLE_SUFFIX})
set(OUTPUT_PATH ${CMAKE_BINARY_DIR}/out/bin/${OUTPUT_FILE})

add_custom_target(test_headless ALL DEPENDS ${OUTPUT_PATH})
add_dependencies(test_headless binaryninjaapi)

find_program(RUSTUP_PATH rustup REQUIRED HINTS ~/.cargo/bin)
set(INSTALL_UPDATE_NIGHTLY ${RUSTUP_PATH} install nightly)

if(APPLE)
if(UNIVERSAL)
add_custom_command(
OUTPUT ${OUTPUT_PATH}
COMMAND ${INSTALL_UPDATE_NIGHTLY}
COMMAND ${CMAKE_COMMAND} -E env
MACOSX_DEPLOYMENT_TARGET=10.14 LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
${RUSTUP_PATH} run nightly cargo build --target=aarch64-apple-darwin ${CARGO_OPTS}
COMMAND ${CMAKE_COMMAND} -E env
MACOSX_DEPLOYMENT_TARGET=10.14 LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
${RUSTUP_PATH} run nightly cargo build --target=x86_64-apple-darwin ${CARGO_OPTS}
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
else()
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/debug/${CMAKE_STATIC_LIBRARY_PREFIX}test_headless${CMAKE_SHARED_LIBRARY_SUFFIX})
else()
set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/release/${CMAKE_STATIC_LIBRARY_PREFIX}test_headless${CMAKE_SHARED_LIBRARY_SUFFIX})
endif()

add_custom_command(
OUTPUT ${OUTPUT_PATH}
COMMAND ${INSTALL_UPDATE_NIGHTLY}
COMMAND ${CMAKE_COMMAND} -E env
MACOSX_DEPLOYMENT_TARGET=10.14 LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
${RUSTUP_PATH} run nightly cargo build --target=x86_64-apple-darwin ${CARGO_OPTS}
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
endif()
elseif(WIN32)
add_custom_command(
OUTPUT ${OUTPUT_PATH}
COMMAND ${INSTALL_UPDATE_NIGHTLY}
COMMAND ${CMAKE_COMMAND} -E env
LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
${RUSTUP_PATH} run nightly cargo build ${CARGO_OPTS}
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
else()
add_custom_command(
OUTPUT ${OUTPUT_PATH}
COMMAND ${INSTALL_UPDATE_NIGHTLY}
COMMAND ${CMAKE_COMMAND} -E env
LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
${RUSTUP_PATH} run nightly cargo build ${CARGO_OPTS}
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
endif()
67 changes: 67 additions & 0 deletions rust/examples/basic_script/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;

#[cfg(target_os = "macos")]
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");

#[cfg(target_os = "linux")]
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");

#[cfg(windows)]
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");

// Check last run location for path to BinaryNinja; Otherwise check the default install locations
fn link_path() -> PathBuf {
use std::io::prelude::*;

let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);

File::open(lastrun)
.and_then(|f| {
let mut binja_path = String::new();
let mut reader = BufReader::new(f);

reader.read_line(&mut binja_path)?;
Ok(PathBuf::from(binja_path.trim()))
})
.unwrap_or_else(|_| {
#[cfg(target_os = "macos")]
return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");

#[cfg(target_os = "linux")]
return home.join("binaryninja");

#[cfg(windows)]
return PathBuf::from(env::var("PROGRAMFILES").unwrap()).join("Vector35\\BinaryNinja\\");
})
}

fn main() {
// Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
let install_path = env::var("BINARYNINJADIR")
.map(PathBuf::from)
.unwrap_or_else(|_| link_path());

#[cfg(target_os = "linux")]
println!(
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
install_path.to_str().unwrap(),
install_path.to_str().unwrap(),
);

#[cfg(target_os = "macos")]
println!(
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
install_path.to_str().unwrap(),
install_path.to_str().unwrap(),
);

#[cfg(target_os = "windows")]
{
println!("cargo:rustc-link-lib=binaryninjacore");
println!("cargo:rustc-link-search={}", install_path.to_str().unwrap());
}
}
Loading

0 comments on commit e629200

Please sign in to comment.