use crate::cache::cached_function_guid; use crate::matcher::cached_function_matcher; use binaryninja::backgroundtask::BackgroundTask; use binaryninja::binaryview::{BinaryView, BinaryViewExt}; use binaryninja::command::Command; use binaryninja::llil; use binaryninja::workflow::{Activity, AnalysisContext, Workflow}; use std::time::Instant; pub const MATCHER_ACTIVITY_NAME: &str = "analysis.warp.matcher"; const MATCHER_ACTIVITY_CONFIG: &str = r#"{ "name": "analysis.warp.matcher", "title" : "WARP Matcher", "description": "This analysis step applies WARP info to matched functions...", "eligibility": { "auto": {}, "runOnce": true } }"#; pub const GUID_ACTIVITY_NAME: &str = "analysis.warp.guid"; const GUID_ACTIVITY_CONFIG: &str = r#"{ "name": "analysis.warp.guid", "title" : "WARP GUID Generator", "description": "This analysis step generates the GUID for all analyzed functions...", "eligibility": { "auto": {}, "runOnce": true } }"#; pub struct RunMatcher; impl Command for RunMatcher { fn action(&self, view: &BinaryView) { let view = view.to_owned(); // TODO: Check to see if the GUID cache is empty and ask the user if they want to regenerate the guids. std::thread::spawn(move || { let undo_id = view.file().begin_undo_actions(true); let background_task = BackgroundTask::new("Matching on functions...", false).unwrap(); let start = Instant::now(); view.functions() .iter() .for_each(|function| cached_function_matcher(&function)); log::info!("Function matching took {:?}", start.elapsed()); background_task.finish(); view.file().commit_undo_actions(undo_id); // Now we want to trigger re-analysis. view.update_analysis(); }); } fn valid(&self, _view: &BinaryView) -> bool { true } } pub fn insert_workflow() { let matcher_activity = |ctx: &AnalysisContext| { let view = ctx.view(); let undo_id = view.file().begin_undo_actions(true); let background_task = BackgroundTask::new("Matching on functions...", false).unwrap(); let start = Instant::now(); view.functions() .iter() .for_each(|function| cached_function_matcher(&function)); log::info!("Function matching took {:?}", start.elapsed()); background_task.finish(); view.file().commit_undo_actions(undo_id); // Now we want to trigger re-analysis. view.update_analysis(); }; let guid_activity = |ctx: &AnalysisContext| { let function = ctx.function(); if let Some(llil) = unsafe { ctx.llil_function::>() } { cached_function_guid(&function, &llil); } }; let function_meta_workflow = Workflow::new_from_copy("core.function.metaAnalysis"); let guid_activity = Activity::new_with_action(GUID_ACTIVITY_CONFIG, guid_activity); function_meta_workflow .register_activity(&guid_activity) .unwrap(); function_meta_workflow.insert("core.function.runFunctionRecognizers", [GUID_ACTIVITY_NAME]); function_meta_workflow.register().unwrap(); let module_meta_workflow = Workflow::new_from_copy("core.module.metaAnalysis"); let matcher_activity = Activity::new_with_action(MATCHER_ACTIVITY_CONFIG, matcher_activity); module_meta_workflow .register_activity(&matcher_activity) .unwrap(); module_meta_workflow.insert("core.module.notifyCompletion", [MATCHER_ACTIVITY_NAME]); module_meta_workflow.register().unwrap(); }