diff options
| author | Mason Reed <mason@vector35.com> | 2024-11-11 22:37:14 -0500 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2024-11-11 22:37:40 -0500 |
| commit | 607da4f8e32617b17d0f4549b49baf9610797f18 (patch) | |
| tree | 99058629430a187f482ffcd68766ac339952f868 /plugins | |
| parent | 189ec853d318526e6b31f25ee4e39c52a6715a5f (diff) | |
WARP: More easily adjustable binja settings
Also fixes the issue of running sigem without already enabling WARP previously.
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/warp/src/bin/sigem.rs | 113 |
1 files changed, 34 insertions, 79 deletions
diff --git a/plugins/warp/src/bin/sigem.rs b/plugins/warp/src/bin/sigem.rs index 38cec17e..f13b56f4 100644 --- a/plugins/warp/src/bin/sigem.rs +++ b/plugins/warp/src/bin/sigem.rs @@ -10,9 +10,10 @@ use rayon::prelude::*; use binaryninja::binaryview::{BinaryView, BinaryViewExt}; use binaryninja::function::Function as BNFunction; use binaryninja::rc::Guard as BNGuard; -use serde_json::json; +use serde_json::{json, Value}; use walkdir::WalkDir; use warp::signature::Data; +use binaryninja::settings::Settings; use warp_ninja::cache::{cached_type_references, register_cache_destructor}; #[derive(Parser, Debug)] @@ -48,12 +49,28 @@ struct Args { debug_info: Option<PathBuf>, } +fn default_settings(bn_settings: &Settings) -> Value { + let mut settings = json!({ + "analysis.linearSweep.autorun": false, + "analysis.signatureMatcher.autorun": false, + "analysis.mode": "full", + }); + + // If WARP is enabled we must turn it off to prevent matching on other stuff. + if bn_settings.contains("analysis.warp.matcher") { + settings["analysis.warp.matcher"] = json!(false); + settings["analysis.warp.guid"] = json!(false); + } + + settings +} + fn main() { let args = Args::parse(); env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); // If no output file was given, just prepend binary with extension sbin - let output_file = args.output.unwrap_or(args.path.with_extension("sbin")); + let output_file = args.output.unwrap_or(args.path.to_owned()).with_extension("sbin"); if output_file.exists() && !args.overwrite.unwrap_or(false) { log::info!("Output file already exists, skipping... {:?}", output_file); @@ -64,7 +81,7 @@ fn main() { let _headless_session = binaryninja::headless::Session::new(); // Adjust the amount of worker threads so that we can actually free BinaryViews. - let bn_settings = binaryninja::settings::Settings::new(""); + let bn_settings = Settings::new(""); let worker_count = rayon::current_num_threads() * 4; log::debug!("Adjusting Binary Ninja worker count to {}...", worker_count); bn_settings.set_integer( @@ -76,10 +93,12 @@ fn main() { // Make sure caches are flushed when the views get destructed. register_cache_destructor(); + + let settings = default_settings(&bn_settings); log::info!("Creating functions for {:?}...", args.path); let start = std::time::Instant::now(); - let data = data_from_file(&args.path) + let data = data_from_file(&settings, &args.path) .expect("Failed to read data, check your license and Binary Ninja version!"); log::info!("Functions created in {:?}", start.elapsed()); @@ -128,7 +147,7 @@ fn data_from_view(view: &BinaryView) -> Data { data } -fn data_from_archive<R: Read>(mut archive: Archive<R>) -> Option<Data> { +fn data_from_archive<R: Read>(settings: &Value, mut archive: Archive<R>) -> Option<Data> { // TODO: I feel like this is a hack... let temp_dir = tempdir::TempDir::new("tmp_archive").ok()?; // Iterate through the entries in the ar file and make a temp dir with them @@ -159,14 +178,14 @@ fn data_from_archive<R: Read>(mut archive: Archive<R>) -> Option<Data> { .into_par_iter() .filter_map(|path| { log::debug!("Creating data for ENTRY {:?}...", path); - data_from_file(&path) + data_from_file(settings, &path) }) .collect::<Vec<_>>(); Some(Data::merge(entry_data)) } -fn data_from_directory(dir: PathBuf) -> Option<Data> { +fn data_from_directory(settings: &Value, dir: PathBuf) -> Option<Data> { let files = WalkDir::new(dir) .into_iter() .filter_map(|e| { @@ -183,7 +202,7 @@ fn data_from_directory(dir: PathBuf) -> Option<Data> { .into_par_iter() .filter_map(|path| { log::info!("Creating data for FILE {:?}...", path); - data_from_file(&path) + data_from_file(settings, &path) }) .collect::<Vec<_>>(); @@ -195,33 +214,22 @@ fn data_from_directory(dir: PathBuf) -> Option<Data> { } // TODO: Pass settings. -fn data_from_file(path: &Path) -> Option<Data> { - // TODO: Add external debug info files. - // TODO: Support IDB's through debug info - let settings_json = json!({ - "analysis.linearSweep.autorun": false, - "analysis.signatureMatcher.autorun": false, - "analysis.mode": "full", - // We don't need these - "analysis.warp.matcher": false, - "analysis.warp.guid": false, - }); - +fn data_from_file(settings: &Value, path: &Path) -> Option<Data> { match path.extension() { Some(ext) if ext == "a" || ext == "lib" || ext == "rlib" => { let archive_file = File::open(path).expect("Failed to open archive file"); let archive = Archive::new(archive_file); - data_from_archive(archive) + data_from_archive(settings, archive) } Some(ext) if ext == "sbin" => { let contents = std::fs::read(path).ok()?; Data::from_bytes(&contents) } - _ if path.is_dir() => data_from_directory(path.into()), + _ if path.is_dir() => data_from_directory(settings, path.into()), _ => { let path_str = path.to_str().unwrap(); let view = - binaryninja::load_with_options(path_str, true, Some(settings_json.to_string()))?; + binaryninja::load_with_options(path_str, true, Some(settings.to_string()))?; let data = data_from_view(&view); view.file().close(); Some(data) @@ -232,74 +240,21 @@ fn data_from_file(path: &Path) -> Option<Data> { #[cfg(test)] mod tests { use super::*; - use warp::r#type::guid::TypeGUID; - use warp_ninja::convert::from_bn_type; - #[test] fn test_data_from_file() { env_logger::init(); // TODO: Store oracles here to get more out of this test. let out_dir = env!("OUT_DIR").parse::<PathBuf>().unwrap(); let _headless_session = binaryninja::headless::Session::new(); + let bn_settings = Settings::new(""); + let settings = default_settings(&bn_settings); for entry in std::fs::read_dir(out_dir).expect("Failed to read OUT_DIR") { let entry = entry.expect("Failed to read directory entry"); let path = entry.path(); if path.is_file() { - let result = data_from_file(&path); + let result = data_from_file(&settings, &path); assert!(result.is_some()); } } } - - #[test] - fn check_for_leaks() { - let session = binaryninja::headless::Session::new(); - let out_dir = env!("OUT_DIR").parse::<PathBuf>().unwrap(); - for entry in std::fs::read_dir(out_dir).expect("Failed to read OUT_DIR") { - let entry = entry.expect("Failed to read directory entry"); - let path = entry.path(); - if path.is_file() { - if let Some(inital_bv) = session.load(path.to_str().unwrap()) { - let result = data_from_file(&path); - assert!(result.is_some()); - // Hold on to a reference to the core to prevent view getting dropped in worker thread. - let core_ref = inital_bv - .functions() - .iter() - .next() - .map(|f| f.unresolved_stack_adjustment_graph()); - // Drop the file and view. - inital_bv.file().close(); - std::mem::drop(inital_bv); - let initial_memory_info = binaryninja::memory_info(); - if let Some(second_bv) = session.load(path.to_str().unwrap()) { - let result = data_from_file(&path); - assert!(result.is_some()); - // Hold on to a reference to the core to prevent view getting dropped in worker thread. - let core_ref = second_bv - .functions() - .iter() - .next() - .map(|f| f.unresolved_stack_adjustment_graph()); - // Drop the file and view. - second_bv.file().close(); - std::mem::drop(second_bv); - let final_memory_info = binaryninja::memory_info(); - for info in initial_memory_info { - let initial_count = info.1; - if let Some(&final_count) = final_memory_info.get(&info.0) { - assert!( - final_count <= initial_count, - "{}: final objects {} vs initial objects {}", - info.0, - final_count, - initial_count - ); - } - } - } - } - } - } - } } |
