summaryrefslogtreecommitdiff
path: root/rust/examples
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2024-10-19 19:02:06 -0400
committerMason Reed <mason@vector35.com>2024-10-19 19:03:26 -0400
commite34ddc02cb073d762931c2ea5217e7489ef6c4c2 (patch)
treeeef618583a2764b8f9044acbc38a0e7ab829adf5 /rust/examples
parent3a947674819c43e8de9902242a1b1748943bb025 (diff)
Rework rust workflow api and add workflow example
Diffstat (limited to 'rust/examples')
-rw-r--r--rust/examples/workflow/Cargo.toml11
-rw-r--r--rust/examples/workflow/build.rs68
-rw-r--r--rust/examples/workflow/src/lib.rs71
3 files changed, 150 insertions, 0 deletions
diff --git a/rust/examples/workflow/Cargo.toml b/rust/examples/workflow/Cargo.toml
new file mode 100644
index 00000000..4c2309ca
--- /dev/null
+++ b/rust/examples/workflow/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "workflow"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+binaryninja = { path="../../" }
+log = "0.4" \ No newline at end of file
diff --git a/rust/examples/workflow/build.rs b/rust/examples/workflow/build.rs
new file mode 100644
index 00000000..5ba9bcde
--- /dev/null
+++ b/rust/examples/workflow/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/workflow/src/lib.rs b/rust/examples/workflow/src/lib.rs
new file mode 100644
index 00000000..0392b3bf
--- /dev/null
+++ b/rust/examples/workflow/src/lib.rs
@@ -0,0 +1,71 @@
+use binaryninja::architecture::CoreArchitecture;
+use binaryninja::llil::{
+ ExprInfo, LiftedNonSSA, Mutable, NonSSA, RegularNonSSA, VisitorAction, SSA,
+};
+use binaryninja::workflow::{Activity, AnalysisContext, Workflow};
+use log::LevelFilter;
+
+const RUST_ACTIVITY_NAME: &'static str = "analysis.plugins.rustexample";
+// TODO: runOnce needs to be on...
+const RUST_ACTIVITY_CONFIG: &'static str = r#"{
+ "name": "analysis.plugins.rustexample",
+ "title" : "Rust Example",
+ "description": "This analysis step logs out some information about the function...",
+ "eligibility": {
+ "auto": { "default": true },
+ "runOnce": false
+ }
+}"#;
+
+fn example_activity(analysis_context: &AnalysisContext) {
+ let func = analysis_context.function();
+ log::info!(
+ "Activity `{}` called in function {} with workflow {:?}!",
+ RUST_ACTIVITY_NAME,
+ func.start(),
+ func.workflow().map(|wf| wf.name())
+ );
+ // If we have llil available, replace that as well.
+ if let Some(llil) = unsafe { analysis_context.llil_function::<NonSSA<LiftedNonSSA>>() } {
+ for basic_block in &func.basic_blocks() {
+ for instr in basic_block.iter() {
+ if let Some(llil_instr) = llil.instruction_at(instr) {
+ llil_instr.visit_tree(&mut |expr, info| {
+ match info {
+ ExprInfo::Const(op) => {
+ // Replace all consts with 0x1337.
+ log::info!(
+ "Replacing llil expression @ 0x{:x} : {}",
+ instr,
+ expr.index()
+ );
+ unsafe {
+ llil.replace_expression(expr.index(), llil.const_int(4, 0x1337))
+ };
+ }
+ _ => {}
+ }
+ VisitorAction::Descend
+ });
+ }
+ }
+ }
+ analysis_context.set_lifted_il_function(&llil);
+ }
+}
+
+#[no_mangle]
+#[allow(non_snake_case)]
+pub extern "C" fn CorePluginInit() -> bool {
+ binaryninja::logger::init(LevelFilter::Debug).unwrap();
+
+ log::info!("Initialized the plugin");
+
+ let meta_workflow = Workflow::new_from_copy("core.function.metaAnalysis");
+ let activity = Activity::new_with_action(RUST_ACTIVITY_CONFIG, example_activity);
+ meta_workflow.register_activity(&activity).unwrap();
+ meta_workflow.insert("core.function.runFunctionRecognizers", [RUST_ACTIVITY_NAME]);
+ // Re-register the meta workflow with our changes.
+ meta_workflow.register().unwrap();
+ true
+}