Skip to content

Commit e629200

Browse files
committed
Resolves #2521
1 parent 58e515b commit e629200

File tree

11 files changed

+537
-131
lines changed

11 files changed

+537
-131
lines changed

rust/README.md

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
> :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.**
66
7-
> :warning: This project requires Rust Nightly to build with those fancy linker arguments
7+
> :warning: This project requires **Rust Nightly** to build with those fancy linker arguments
88
99

1010
## Dependencies
@@ -16,58 +16,7 @@ Rust **Nightly**
1616

1717
## How to use
1818

19-
### To write a plugin:
20-
21-
`Cargo.toml`:
22-
```
23-
[lib]
24-
crate-type = ["cdylib"]
25-
26-
[dependencies]
27-
binaryninja = {git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
28-
```
29-
30-
`src/main.rs`:
31-
See the `./examples/`. Plugin registration commands are in `binaryninja::command::*`
32-
33-
34-
### To write a headless script:
35-
36-
`Cargo.toml`:
37-
```
38-
[dependencies]
39-
binaryninja = { git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
40-
```
41-
42-
`src/main.rs`:
43-
```
44-
use binaryninja::version;
45-
use binaryninja::architecture::Architecture;
46-
use binaryninja::binaryview::{BinaryViewBase, BinaryViewExt};
47-
48-
fn main() {
49-
println!("BinaryNinja Version: `{}`", version());
50-
51-
println!("Loading plugins..."); // This loads all the core architecture, platform, etc plugins
52-
binaryninja::headless::init();
53-
54-
println!("Loading binary...");
55-
let bv = binaryninja::open_view("/bin/cat").expect("Couldn't open `/bin/cat`");
56-
57-
println!("Filename: `{}`", bv.metadata().filename());
58-
println!("File size: `{:#x}`", bv.len());
59-
println!("Function count: {}", bv.functions().len());
60-
61-
for func in &bv.functions() {
62-
println!(" `{}`:", func.symbol().full_name());
63-
}
64-
65-
// Important! You need to call shutdown or your script will hang forever
66-
binaryninja::headless::shutdown();
67-
}
68-
```
69-
70-
All headless scripts should call both `binaryninja::headless::init()` and `binaryninja::headless::shutdown()`.
19+
See [`examples/template`](examples/template).
7120

7221
---
7322

rust/binaryninjacore-sys/build.rs

Lines changed: 14 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,6 @@ use std::io::BufRead;
66
use std::io::BufReader;
77
use std::path::PathBuf;
88

9-
#[cfg(target_os = "macos")]
10-
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
11-
12-
#[cfg(target_os = "linux")]
13-
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
14-
15-
#[cfg(windows)]
16-
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
17-
18-
// Check last run location for path to BinaryNinja; Otherwise check the default install locations
19-
fn link_path() -> PathBuf {
20-
use std::io::prelude::*;
21-
22-
let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
23-
let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
24-
25-
File::open(lastrun)
26-
.and_then(|f| {
27-
let mut binja_path = String::new();
28-
let mut reader = BufReader::new(f);
29-
30-
reader.read_line(&mut binja_path)?;
31-
Ok(PathBuf::from(binja_path.trim()))
32-
})
33-
.unwrap_or_else(|_| {
34-
#[cfg(target_os = "macos")]
35-
return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
36-
37-
#[cfg(target_os = "linux")]
38-
return home.join("binaryninja");
39-
40-
#[cfg(windows)]
41-
return PathBuf::from(env::var("PROGRAMFILES").unwrap())
42-
.join("Vector35\\BinaryNinja\\");
43-
})
44-
}
45-
469
fn main() {
4710
println!("cargo:rerun-if-changed=../../binaryninjacore.h");
4811

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

57-
// Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
58-
let install_path = env::var("BINARYNINJADIR")
59-
.map(PathBuf::from)
60-
.unwrap_or_else(|_| link_path());
61-
62-
#[cfg(target_os = "linux")]
63-
println!(
64-
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
65-
install_path.to_str().unwrap(),
66-
install_path.to_str().unwrap(),
67-
);
68-
69-
#[cfg(not(target_os = "linux"))]
70-
println!(
71-
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
72-
install_path.to_str().unwrap(),
73-
install_path.to_str().unwrap(),
74-
);
75-
76-
// TODO : Clean this up even more
77-
#[warn(unused_assignments)]
78-
let is_mac = {
79-
#[cfg(target_os = "macos")]
80-
{
81-
true
82-
}
83-
#[cfg(not(target_os = "macos"))]
84-
{
85-
false
86-
}
87-
};
88-
8920
let current_line = "#define BN_CURRENT_UI_ABI_VERSION ";
9021
let minimum_line = "#define BN_MINIMUM_UI_ABI_VERSION ";
9122
let mut current_version = "0".to_string();
@@ -100,8 +31,6 @@ fn main() {
10031
}
10132
}
10233

103-
// Difference between global LLVM/Clang install and custom LLVM/Clang install...
104-
// 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)
10534
let mut bindings = bindgen::builder()
10635
.header("../../binaryninjacore.h")
10736
.clang_arg("-std=c++17")
@@ -121,13 +50,20 @@ fn main() {
12150
minimum_version
12251
))
12352
.rustified_enum("BN.*");
124-
if let (false, Ok(llvm_dir), Ok(llvm_version)) = (is_mac, llvm_dir, llvm_version) {
125-
let llvm_include_path = format!("-I{}/clang/{}/include", llvm_dir, llvm_version);
126-
bindings = bindings.clang_arg(llvm_include_path);
127-
} else if let (false, Ok(llvm_install_dir)) = (is_mac, llvm_install_dir) {
128-
let llvm_include_path = format!("-I{}/12.0.0/lib/clang/12.0.0/include", llvm_install_dir);
129-
env::set_var("LIBCLANG_PATH", format!("{}/12.0.0/lib", llvm_install_dir));
130-
bindings = bindings.clang_arg(llvm_include_path);
53+
54+
// Difference between global LLVM/Clang install and custom LLVM/Clang install...
55+
// 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)
56+
#[cfg(not(target_os = "macos"))]
57+
{
58+
if let (Ok(llvm_dir), Ok(llvm_version)) = (llvm_dir, llvm_version) {
59+
let llvm_include_path = format!("-I{}/clang/{}/include", llvm_dir, llvm_version);
60+
bindings = bindings.clang_arg(llvm_include_path);
61+
} else if let Ok(llvm_install_dir) = llvm_install_dir {
62+
let llvm_include_path =
63+
format!("-I{}/12.0.0/lib/clang/12.0.0/include", llvm_install_dir);
64+
env::set_var("LIBCLANG_PATH", format!("{}/12.0.0/lib", llvm_install_dir));
65+
bindings = bindings.clang_arg(llvm_include_path);
66+
}
13167
}
13268

13369
bindings
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
2+
3+
if(CMAKE_BUILD_TYPE MATCHES Debug)
4+
set(TARGET_DIR ${PROJECT_BINARY_DIR}/target/debug)
5+
set(CARGO_OPTS --target-dir=${PROJECT_BINARY_DIR}/target)
6+
else()
7+
set(TARGET_DIR ${PROJECT_BINARY_DIR}/target/release)
8+
set(CARGO_OPTS --target-dir=${PROJECT_BINARY_DIR}/target --release)
9+
endif()
10+
11+
project(test_headless)
12+
13+
file(GLOB PLUGIN_SOURCES
14+
${PROJECT_SOURCE_DIR}/Cargo.toml
15+
${PROJECT_SOURCE_DIR}/src/*.rs)
16+
17+
file(GLOB API_SOURCES
18+
${PROJECT_SOURCE_DIR}/../../../binaryninjacore.h
19+
${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/build.rs
20+
${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/Cargo.toml
21+
${PROJECT_SOURCE_DIR}/../../binaryninjacore-sys/src/*
22+
${PROJECT_SOURCE_DIR}/../../Cargo.toml
23+
${PROJECT_SOURCE_DIR}/../../src/*.rs)
24+
25+
set(OUTPUT_FILE basic_script${CMAKE_EXECUTABLE_SUFFIX})
26+
set(OUTPUT_PATH ${CMAKE_BINARY_DIR}/out/bin/${OUTPUT_FILE})
27+
28+
add_custom_target(test_headless ALL DEPENDS ${OUTPUT_PATH})
29+
add_dependencies(test_headless binaryninjaapi)
30+
31+
find_program(RUSTUP_PATH rustup REQUIRED HINTS ~/.cargo/bin)
32+
set(INSTALL_UPDATE_NIGHTLY ${RUSTUP_PATH} install nightly)
33+
34+
if(APPLE)
35+
if(UNIVERSAL)
36+
add_custom_command(
37+
OUTPUT ${OUTPUT_PATH}
38+
COMMAND ${INSTALL_UPDATE_NIGHTLY}
39+
COMMAND ${CMAKE_COMMAND} -E env
40+
MACOSX_DEPLOYMENT_TARGET=10.14 LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
41+
${RUSTUP_PATH} run nightly cargo build --target=aarch64-apple-darwin ${CARGO_OPTS}
42+
COMMAND ${CMAKE_COMMAND} -E env
43+
MACOSX_DEPLOYMENT_TARGET=10.14 LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
44+
${RUSTUP_PATH} run nightly cargo build --target=x86_64-apple-darwin ${CARGO_OPTS}
45+
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
46+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
47+
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
48+
else()
49+
if(CMAKE_BUILD_TYPE MATCHES Debug)
50+
set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/debug/${CMAKE_STATIC_LIBRARY_PREFIX}test_headless${CMAKE_SHARED_LIBRARY_SUFFIX})
51+
else()
52+
set(X86_64_LIB_PATH ${PROJECT_BINARY_DIR}/target/x86_64-apple-darwin/release/${CMAKE_STATIC_LIBRARY_PREFIX}test_headless${CMAKE_SHARED_LIBRARY_SUFFIX})
53+
endif()
54+
55+
add_custom_command(
56+
OUTPUT ${OUTPUT_PATH}
57+
COMMAND ${INSTALL_UPDATE_NIGHTLY}
58+
COMMAND ${CMAKE_COMMAND} -E env
59+
MACOSX_DEPLOYMENT_TARGET=10.14 LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
60+
${RUSTUP_PATH} run nightly cargo build --target=x86_64-apple-darwin ${CARGO_OPTS}
61+
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
62+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
63+
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
64+
endif()
65+
elseif(WIN32)
66+
add_custom_command(
67+
OUTPUT ${OUTPUT_PATH}
68+
COMMAND ${INSTALL_UPDATE_NIGHTLY}
69+
COMMAND ${CMAKE_COMMAND} -E env
70+
LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
71+
${RUSTUP_PATH} run nightly cargo build ${CARGO_OPTS}
72+
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
73+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
74+
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
75+
else()
76+
add_custom_command(
77+
OUTPUT ${OUTPUT_PATH}
78+
COMMAND ${INSTALL_UPDATE_NIGHTLY}
79+
COMMAND ${CMAKE_COMMAND} -E env
80+
LIBCLANG_PATH=${LLVM_PATH}/lib LLVM_VERSION=${LLVM_VERSION} BINARYNINJADIR=${BN_CORE_OUTPUT_DIR}
81+
${RUSTUP_PATH} run nightly cargo build ${CARGO_OPTS}
82+
COMMAND cp ${TARGET_DIR}/${OUTPUT_FILE} ${OUTPUT_PATH}
83+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
84+
DEPENDS ${PLUGIN_SOURCES} ${API_SOURCES})
85+
endif()

rust/examples/basic_script/build.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use std::env;
2+
use std::fs::File;
3+
use std::io::BufReader;
4+
use std::path::PathBuf;
5+
6+
#[cfg(target_os = "macos")]
7+
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
8+
9+
#[cfg(target_os = "linux")]
10+
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
11+
12+
#[cfg(windows)]
13+
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
14+
15+
// Check last run location for path to BinaryNinja; Otherwise check the default install locations
16+
fn link_path() -> PathBuf {
17+
use std::io::prelude::*;
18+
19+
let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
20+
let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
21+
22+
File::open(lastrun)
23+
.and_then(|f| {
24+
let mut binja_path = String::new();
25+
let mut reader = BufReader::new(f);
26+
27+
reader.read_line(&mut binja_path)?;
28+
Ok(PathBuf::from(binja_path.trim()))
29+
})
30+
.unwrap_or_else(|_| {
31+
#[cfg(target_os = "macos")]
32+
return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
33+
34+
#[cfg(target_os = "linux")]
35+
return home.join("binaryninja");
36+
37+
#[cfg(windows)]
38+
return PathBuf::from(env::var("PROGRAMFILES").unwrap()).join("Vector35\\BinaryNinja\\");
39+
})
40+
}
41+
42+
fn main() {
43+
// Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
44+
let install_path = env::var("BINARYNINJADIR")
45+
.map(PathBuf::from)
46+
.unwrap_or_else(|_| link_path());
47+
48+
#[cfg(target_os = "linux")]
49+
println!(
50+
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
51+
install_path.to_str().unwrap(),
52+
install_path.to_str().unwrap(),
53+
);
54+
55+
#[cfg(target_os = "macos")]
56+
println!(
57+
"cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
58+
install_path.to_str().unwrap(),
59+
install_path.to_str().unwrap(),
60+
);
61+
62+
#[cfg(target_os = "windows")]
63+
{
64+
println!("cargo:rustc-link-lib=binaryninjacore");
65+
println!("cargo:rustc-link-search={}", install_path.to_str().unwrap());
66+
}
67+
}

0 commit comments

Comments
 (0)