summaryrefslogtreecommitdiff
path: root/rust/examples
diff options
context:
space:
mode:
authorRubens Brandao <git@rubens.io>2023-11-22 18:57:28 -0300
committerKyleMiles <krm504@nyu.edu>2024-02-02 13:32:45 -0500
commitf682ca69b356755fe6c06bcdd8f4fab73f7d2c78 (patch)
tree3cfc324cfe8043ccc8db1161f1f90c448d097c8a /rust/examples
parente1a6bdcd576f7caeaa6f97ff1e337a259057b333 (diff)
Rust API : Add HLIL Bindings
Diffstat (limited to 'rust/examples')
-rw-r--r--rust/examples/hlil_lifter/Cargo.toml16
-rw-r--r--rust/examples/hlil_lifter/build.rs68
-rw-r--r--rust/examples/hlil_lifter/src/main.rs52
-rw-r--r--rust/examples/hlil_visitor/Cargo.toml16
-rw-r--r--rust/examples/hlil_visitor/build.rs68
-rw-r--r--rust/examples/hlil_visitor/src/main.rs248
-rw-r--r--rust/examples/mlil_visitor/src/main.rs10
7 files changed, 474 insertions, 4 deletions
diff --git a/rust/examples/hlil_lifter/Cargo.toml b/rust/examples/hlil_lifter/Cargo.toml
new file mode 100644
index 00000000..c6c8794a
--- /dev/null
+++ b/rust/examples/hlil_lifter/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "hlil_lifter"
+version = "0.1.0"
+edition = "2021"
+
+# Uncomment this if you're writing a plugin (plugins are shared objects loaded by the core):
+# [lib]
+# crate-type = ["cdylib"]
+
+# You can point at the BinaryNinja dependency in one of two ways, via path:
+[dependencies]
+binaryninja = {path="../../"}
+
+# Or directly at the git repo:
+# [dependencies]
+# binaryninja = {git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
diff --git a/rust/examples/hlil_lifter/build.rs b/rust/examples/hlil_lifter/build.rs
new file mode 100644
index 00000000..5ba9bcde
--- /dev/null
+++ b/rust/examples/hlil_lifter/build.rs
@@ -0,0 +1,68 @@
+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());
+ }
+}
diff --git a/rust/examples/hlil_lifter/src/main.rs b/rust/examples/hlil_lifter/src/main.rs
new file mode 100644
index 00000000..2ac034f4
--- /dev/null
+++ b/rust/examples/hlil_lifter/src/main.rs
@@ -0,0 +1,52 @@
+use std::env;
+
+use binaryninja::binaryview::BinaryViewExt;
+
+// Standalone executables need to provide a main function for rustc
+// Plugins should refer to `binaryninja::command::*` for the various registration callbacks.
+fn main() {
+ let mut args = env::args();
+ let _ = args.next().unwrap();
+ let Some(filename) = args.next() else {
+ panic!("Expected input filename\n");
+ };
+
+ // This loads all the core architecture, platform, etc plugins
+ // Standalone executables probably need to call this, but plugins do not
+ println!("Loading plugins...");
+ binaryninja::headless::init();
+
+ // Your code here...
+ println!("Loading binary...");
+ let bv = binaryninja::load(filename).expect("Couldn't open binary file");
+
+ // Go through all functions in the binary
+ for func in bv.functions().iter() {
+ let sym = func.symbol();
+ println!("Function {}:", sym.full_name());
+
+ let Ok(il) = func.high_level_il(true) else {
+ println!(" Does not have HLIL\n");
+ continue;
+ };
+ // Get the SSA form for this function
+ let il = il.ssa_form();
+
+ // Loop through all blocks in the function
+ for block in il.basic_blocks().iter() {
+ // Loop though each instruction in the block
+ for instr in block.iter() {
+ // Uplift the instruction into a native rust format
+ let lifted = instr.lift();
+ let address = instr.address();
+
+ // print the lifted instruction
+ println!("{address:08x}: {lifted:x?}");
+ }
+ }
+ println!();
+ }
+
+ // Important! Standalone executables need to call shutdown or they will hang forever
+ binaryninja::headless::shutdown();
+}
diff --git a/rust/examples/hlil_visitor/Cargo.toml b/rust/examples/hlil_visitor/Cargo.toml
new file mode 100644
index 00000000..036414a5
--- /dev/null
+++ b/rust/examples/hlil_visitor/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "hlil_visitor"
+version = "0.1.0"
+edition = "2021"
+
+# Uncomment this if you're writing a plugin (plugins are shared objects loaded by the core):
+# [lib]
+# crate-type = ["cdylib"]
+
+# You can point at the BinaryNinja dependency in one of two ways, via path:
+[dependencies]
+binaryninja = {path="../../"}
+
+# Or directly at the git repo:
+# [dependencies]
+# binaryninja = {git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
diff --git a/rust/examples/hlil_visitor/build.rs b/rust/examples/hlil_visitor/build.rs
new file mode 100644
index 00000000..5ba9bcde
--- /dev/null
+++ b/rust/examples/hlil_visitor/build.rs
@@ -0,0 +1,68 @@
+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());
+ }
+}
diff --git a/rust/examples/hlil_visitor/src/main.rs b/rust/examples/hlil_visitor/src/main.rs
new file mode 100644
index 00000000..0e3d8c30
--- /dev/null
+++ b/rust/examples/hlil_visitor/src/main.rs
@@ -0,0 +1,248 @@
+use std::env;
+
+use binaryninja::binaryview::BinaryViewExt;
+use binaryninja::hlil::operation::HighLevelILOperand;
+use binaryninja::hlil::{HighLevelILFunction, HighLevelILInstruction};
+use binaryninja::types::Variable;
+
+fn print_indent(indent: usize) {
+ print!("{:<indent$}", "")
+}
+
+fn print_operation(operation: &HighLevelILInstruction) {
+ use HighLevelILInstruction::*;
+ match operation {
+ Adc(_op) => print!("Adc"),
+ Sbb(_op) => print!("Sbb"),
+ Rlc(_op) => print!("Rlc"),
+ Rrc(_op) => print!("Rrc"),
+ Add(_op) => print!("Add"),
+ Sub(_op) => print!("Sub"),
+ And(_op) => print!("And"),
+ Or(_op) => print!("Or"),
+ Xor(_op) => print!("Xor"),
+ Lsl(_op) => print!("Lsl"),
+ Lsr(_op) => print!("Lsr"),
+ Asr(_op) => print!("Asr"),
+ Rol(_op) => print!("Rol"),
+ Ror(_op) => print!("Ror"),
+ Mul(_op) => print!("Mul"),
+ MuluDp(_op) => print!("MuluDp"),
+ MulsDp(_op) => print!("MulsDp"),
+ Divu(_op) => print!("Divu"),
+ DivuDp(_op) => print!("DivuDp"),
+ Divs(_op) => print!("Divs"),
+ DivsDp(_op) => print!("DivsDp"),
+ Modu(_op) => print!("Modu"),
+ ModuDp(_op) => print!("ModuDp"),
+ Mods(_op) => print!("Mods"),
+ ModsDp(_op) => print!("ModsDp"),
+ CmpE(_op) => print!("CmpE"),
+ CmpNe(_op) => print!("CmpNe"),
+ CmpSlt(_op) => print!("CmpSlt"),
+ CmpUlt(_op) => print!("CmpUlt"),
+ CmpSle(_op) => print!("CmpSle"),
+ CmpUle(_op) => print!("CmpUle"),
+ CmpSge(_op) => print!("CmpSge"),
+ CmpUge(_op) => print!("CmpUge"),
+ CmpSgt(_op) => print!("CmpSgt"),
+ CmpUgt(_op) => print!("CmpUgt"),
+ TestBit(_op) => print!("TestBit"),
+ AddOverflow(_op) => print!("AddOverflow"),
+ Fadd(_op) => print!("Fadd"),
+ Fsub(_op) => print!("Fsub"),
+ Fmul(_op) => print!("Fmul"),
+ Fdiv(_op) => print!("Fdiv"),
+ FcmpE(_op) => print!("FcmpE"),
+ FcmpNe(_op) => print!("FcmpNe"),
+ FcmpLt(_op) => print!("FcmpLt"),
+ FcmpLe(_op) => print!("FcmpLe"),
+ FcmpGe(_op) => print!("FcmpGe"),
+ FcmpGt(_op) => print!("FcmpGt"),
+ FcmpO(_op) => print!("FcmpO"),
+ FcmpUo(_op) => print!("FcmpUo"),
+ ArrayIndex(_op) => print!("ArrayIndex"),
+ ArrayIndexSsa(_op) => print!("ArrayIndexSsa"),
+ Assign(_op) => print!("Assign"),
+ AssignMemSsa(_op) => print!("AssignMemSsa"),
+ AssignUnpack(_op) => print!("AssignUnpack"),
+ AssignUnpackMemSsa(_op) => print!("AssignUnpackMemSsa"),
+ Block(_op) => print!("Block"),
+ Call(_op) => print!("Call"),
+ Tailcall(_op) => print!("Tailcall"),
+ CallSsa(_op) => print!("CallSsa"),
+ Case(_op) => print!("Case"),
+ Const(_op) => print!("Const"),
+ ConstPtr(_op) => print!("ConstPtr"),
+ Import(_op) => print!("Import"),
+ ConstData(_op) => print!("ConstData"),
+ Deref(_op) => print!("Deref"),
+ AddressOf(_op) => print!("AddressOf"),
+ Neg(_op) => print!("Neg"),
+ Not(_op) => print!("Not"),
+ Sx(_op) => print!("Sx"),
+ Zx(_op) => print!("Zx"),
+ LowPart(_op) => print!("LowPart"),
+ BoolToInt(_op) => print!("BoolToInt"),
+ UnimplMem(_op) => print!("UnimplMem"),
+ Fsqrt(_op) => print!("Fsqrt"),
+ Fneg(_op) => print!("Fneg"),
+ Fabs(_op) => print!("Fabs"),
+ FloatToInt(_op) => print!("FloatToInt"),
+ IntToFloat(_op) => print!("IntToFloat"),
+ FloatConv(_op) => print!("FloatConv"),
+ RoundToInt(_op) => print!("RoundToInt"),
+ Floor(_op) => print!("Floor"),
+ Ceil(_op) => print!("Ceil"),
+ Ftrunc(_op) => print!("Ftrunc"),
+ DerefFieldSsa(_op) => print!("DerefFieldSsa"),
+ DerefSsa(_op) => print!("DerefSsa"),
+ ExternPtr(_op) => print!("ExternPtr"),
+ FloatConst(_op) => print!("FloatConst"),
+ For(_op) => print!("For"),
+ ForSsa(_op) => print!("ForSsa"),
+ Goto(_op) => print!("Goto"),
+ Label(_op) => print!("Label"),
+ If(_op) => print!("If"),
+ Intrinsic(_op) => print!("Intrinsic"),
+ IntrinsicSsa(_op) => print!("IntrinsicSsa"),
+ Jump(_op) => print!("Jump"),
+ MemPhi(_op) => print!("MemPhi"),
+ Nop(_op) => print!("Nop"),
+ Break(_op) => print!("Break"),
+ Continue(_op) => print!("Continue"),
+ Noret(_op) => print!("Noret"),
+ Unreachable(_op) => print!("Unreachable"),
+ Bp(_op) => print!("Bp"),
+ Undef(_op) => print!("Undef"),
+ Unimpl(_op) => print!("Unimpl"),
+ Ret(_op) => print!("Ret"),
+ Split(_op) => print!("Split"),
+ StructField(_op) => print!("StructField"),
+ DerefField(_op) => print!("DerefField"),
+ Switch(_op) => print!("Switch"),
+ Syscall(_op) => print!("Syscall"),
+ SyscallSsa(_op) => print!("SyscallSsa"),
+ Trap(_op) => print!("Trap"),
+ VarDeclare(_op) => print!("VarDeclare"),
+ Var(_op) => print!("Var"),
+ VarInit(_op) => print!("VarInit"),
+ VarInitSsa(_op) => print!("VarInitSsa"),
+ VarPhi(_op) => print!("VarPhi"),
+ VarSsa(_op) => print!("VarSsa"),
+ While(_op) => print!("While"),
+ DoWhile(_op) => print!("DoWhile"),
+ WhileSsa(_op) => print!("WhileSsa"),
+ DoWhileSsa(_op) => print!("DoWhileSsa"),
+ }
+}
+
+fn print_variable(func: &HighLevelILFunction, var: &Variable) {
+ print!("{}", func.get_function().get_variable_name(var));
+}
+
+fn print_il_expr(instr: &HighLevelILInstruction, mut indent: usize) {
+ print_indent(indent);
+ print_operation(instr);
+ println!("");
+
+ indent += 1;
+
+ use HighLevelILOperand::*;
+ for (_name, operand) in instr.operands() {
+ match operand {
+ Int(int) => {
+ print_indent(indent);
+ println!("int 0x{:x}", int);
+ }
+ Float(float) => {
+ print_indent(indent);
+ println!("int {:e}", float);
+ }
+ Expr(expr) => print_il_expr(&expr, indent),
+ Var(var) => {
+ print_indent(indent);
+ print!("var ");
+ print_variable(instr.function(), &var);
+ println!();
+ }
+ VarSsa(var) => {
+ print_indent(indent);
+ print!("ssa var ");
+ print_variable(instr.function(), &var.variable);
+ println!("#{}", var.version);
+ }
+ IntList(list) => {
+ print_indent(indent);
+ print!("index list ");
+ for i in list {
+ print!("{i} ");
+ }
+ println!();
+ }
+ VarSsaList(list) => {
+ print_indent(indent);
+ print!("ssa var list ");
+ for i in list {
+ print_variable(instr.function(), &i.variable);
+ print!("#{} ", i.version);
+ }
+ println!();
+ }
+ ExprList(list) => {
+ print_indent(indent);
+ println!("expr list");
+ for i in list {
+ print_il_expr(&i, indent + 1);
+ }
+ }
+ Label(label) => println!("label {}", label.name()),
+ MemberIndex(mem_idx) => println!("member_index {:?}", mem_idx),
+ ConstantData(_) => println!("constant_data TODO"),
+ Intrinsic(_) => println!("intrinsic TODO"),
+ }
+ }
+}
+
+// Standalone executables need to provide a main function for rustc
+// Plugins should refer to `binaryninja::command::*` for the various registration callbacks.
+fn main() {
+ let mut args = env::args();
+ let _ = args.next().unwrap();
+ let Some(filename) = args.next() else {
+ panic!("Expected input filename\n");
+ };
+
+ // This loads all the core architecture, platform, etc plugins
+ // Standalone executables probably need to call this, but plugins do not
+ println!("Loading plugins...");
+ binaryninja::headless::init();
+
+ // Your code here...
+ println!("Loading binary...");
+ let bv = binaryninja::load(filename).expect("Couldn't open binary file");
+
+ // Go through all functions in the binary
+ for func in bv.functions().iter() {
+ let sym = func.symbol();
+ println!("Function {}:", sym.full_name());
+
+ let Ok(il) = func.high_level_il(true) else {
+ println!(" Does not have HLIL\n");
+ continue;
+ };
+
+ // Loop through all blocks in the function
+ for block in il.basic_blocks().iter() {
+ // Loop though each instruction in the block
+ for instr in block.iter() {
+ // Generically parse the IL tree and display the parts
+ print_il_expr(&instr, 2);
+ }
+ }
+ println!();
+ }
+
+ // Important! Standalone executables need to call shutdown or they will hang forever
+ binaryninja::headless::shutdown();
+}
diff --git a/rust/examples/mlil_visitor/src/main.rs b/rust/examples/mlil_visitor/src/main.rs
index 3df005a7..403f239e 100644
--- a/rust/examples/mlil_visitor/src/main.rs
+++ b/rust/examples/mlil_visitor/src/main.rs
@@ -2,15 +2,15 @@ use std::env;
use binaryninja::binaryview::BinaryViewExt;
use binaryninja::mlil::operation::MediumLevelILOperand;
-use binaryninja::mlil::{MediumLevelILFunction, MediumLevelILInstruction, MediumLevelILOperation};
+use binaryninja::mlil::{MediumLevelILFunction, MediumLevelILInstruction};
use binaryninja::types::Variable;
fn print_indent(indent: usize) {
print!("{:<indent$}", "")
}
-fn print_operation(operation: &MediumLevelILOperation) {
- use MediumLevelILOperation::*;
+fn print_operation(operation: &MediumLevelILInstruction) {
+ use MediumLevelILInstruction::*;
match operation {
Nop(_) => print!("Nop"),
Noret(_) => print!("Noret"),
@@ -151,7 +151,7 @@ fn print_variable(func: &MediumLevelILFunction, var: &Variable) {
fn print_il_expr(instr: &MediumLevelILInstruction, mut indent: usize) {
print_indent(indent);
- print_operation(instr.operation());
+ print_operation(instr);
println!("");
indent += 1;
@@ -221,6 +221,8 @@ fn print_il_expr(instr: &MediumLevelILInstruction, mut indent: usize) {
}
println!();
}
+ ConstantData(_) => println!("contantdata"),
+ Intrinsic(intrinsic) => println!("intrinsic {}", intrinsic.name()),
}
}
}