Skip to content

Commit ecb8f07

Browse files
committed
[WARP] Recover register variables and re-add tags to matched functions
1 parent 796b8ac commit ecb8f07

File tree

3 files changed

+103
-22
lines changed

3 files changed

+103
-22
lines changed

plugins/warp/src/convert.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,31 @@ use binaryninja::function::Comment as BNComment;
55
use binaryninja::function::Function as BNFunction;
66
use binaryninja::platform::Platform;
77
use binaryninja::rc::Ref;
8+
use binaryninja::variable::{Variable as BNVariable, VariableSourceType};
89
pub use symbol::*;
910
pub use types::*;
11+
use warp::r#type::class::function::{Location, RegisterLocation, StackLocation};
1012
use warp::signature::comment::FunctionComment;
1113
use warp::target::Target;
1214

15+
pub fn bn_var_to_location(bn_variable: BNVariable) -> Option<Location> {
16+
match bn_variable.ty {
17+
VariableSourceType::StackVariableSourceType => {
18+
let stack_loc = StackLocation {
19+
offset: bn_variable.storage,
20+
};
21+
Some(Location::Stack(stack_loc))
22+
}
23+
VariableSourceType::RegisterVariableSourceType => {
24+
let reg_loc = RegisterLocation {
25+
id: bn_variable.storage as u64,
26+
};
27+
Some(Location::Register(reg_loc))
28+
}
29+
VariableSourceType::FlagVariableSourceType => None,
30+
}
31+
}
32+
1333
pub fn bn_comment_to_comment(func: &BNFunction, bn_comment: BNComment) -> FunctionComment {
1434
let offset = (bn_comment.addr as i64) - (func.start() as i64);
1535
FunctionComment {

plugins/warp/src/lib.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::cache::{cached_constraints, cached_function_guid};
2-
use crate::convert::{bn_comment_to_comment, from_bn_symbol, from_bn_type};
2+
use crate::convert::{bn_comment_to_comment, bn_var_to_location, from_bn_symbol, from_bn_type};
33
use binaryninja::architecture::{
44
Architecture, ImplicitRegisterExtend, Register as BNRegister, RegisterInfo,
55
};
@@ -16,13 +16,15 @@ use binaryninja::low_level_il::instruction::{
1616
};
1717
use binaryninja::low_level_il::{LowLevelILRegisterKind, VisitorAction};
1818
use binaryninja::rc::{Ref as BNRef, Ref};
19+
use binaryninja::tags::TagType;
20+
use binaryninja::variable::RegisterValueType;
21+
use itertools::Itertools;
1922
use std::ops::Range;
2023
use std::path::PathBuf;
2124
use warp::signature::basic_block::BasicBlockGUID;
2225
use warp::signature::function::{Function, FunctionGUID};
26+
use warp::signature::variable::FunctionVariable;
2327

24-
use binaryninja::tags::TagType;
25-
use binaryninja::variable::RegisterValueType;
2628
/// Re-export the warp crate that is used, this is useful for consumers of this crate.
2729
pub use warp;
2830

@@ -71,6 +73,38 @@ pub fn user_signature_dir() -> PathBuf {
7173
binaryninja::user_directory().join("signatures/")
7274
}
7375

76+
pub fn build_variables(func: &BNFunction) -> Vec<FunctionVariable> {
77+
let func_start = func.start();
78+
let mut variables = vec![];
79+
if let Ok(mlil) = func.medium_level_il() {
80+
let bn_vars = func.variables();
81+
for bn_var in &bn_vars {
82+
if mlil.is_var_user_defined(&bn_var.variable) {
83+
// TODO: live_instruction_for_variable only works for register types.
84+
if let Some(first_instr) = mlil
85+
.live_instruction_for_variable(&bn_var.variable, true)
86+
.iter()
87+
.sorted_by_key(|i| i.instr_index)
88+
.next()
89+
{
90+
if let Some(var_loc) = bn_var_to_location(bn_var.variable) {
91+
let var_name = bn_var.name;
92+
let var_type =
93+
from_bn_type(&func.view(), &bn_var.ty.contents, bn_var.ty.confidence);
94+
variables.push(FunctionVariable {
95+
offset: (first_instr.address as i64) - (func_start as i64),
96+
location: var_loc,
97+
name: Some(var_name),
98+
ty: Some(var_type),
99+
})
100+
}
101+
}
102+
}
103+
}
104+
}
105+
variables
106+
}
107+
74108
pub fn build_function<M: FunctionMutability>(
75109
func: &BNFunction,
76110
lifted_il: &LowLevelILFunction<M, NonSSA>,
@@ -97,10 +131,7 @@ pub fn build_function<M: FunctionMutability>(
97131
// NOTE: We do not filter out adjacent functions here.
98132
constraints: cached_constraints(func, |_| true),
99133
comments,
100-
// TODO: Gather relevant variables (only user?).
101-
// TODO: Will need MLIL SSA for this to locate def sites.
102-
// TODO: Add this info in a second pass?
103-
variables: vec![],
134+
variables: build_variables(func),
104135
}
105136
}
106137

plugins/warp/src/plugin/workflow.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::convert::{
88
};
99
use crate::matcher::{Matcher, MatcherSettings};
1010
use crate::{get_warp_tag_type, relocatable_regions};
11+
use binaryninja::architecture::RegisterId;
1112
use binaryninja::background_task::BackgroundTask;
1213
use binaryninja::binary_view::{BinaryView, BinaryViewExt};
1314
use binaryninja::command::Command;
@@ -16,6 +17,7 @@ use binaryninja::workflow::{Activity, AnalysisContext, Workflow};
1617
use itertools::Itertools;
1718
use std::collections::HashMap;
1819
use std::time::Instant;
20+
use warp::r#type::class::function::{Location, RegisterLocation, StackLocation};
1921
use warp::signature::function::{Function, FunctionGUID};
2022
use warp::target::Target;
2123

@@ -68,6 +70,9 @@ impl Command for RunMatcher {
6870
}
6971

7072
pub fn run_matcher(view: &BinaryView) {
73+
// TODO: Create the tag type so we dont have UB in the apply function workflow.
74+
let _ = get_warp_tag_type(view);
75+
7176
// Alert the user if we have no actual regions (one comes from the synthetic section).
7277
let regions = relocatable_regions(view);
7378
if regions.len() <= 1 && view.memory_map().is_activated() {
@@ -174,17 +179,41 @@ pub fn insert_workflow() {
174179
let bn_comment = comment_to_bn_comment(&function, comment);
175180
function.set_comment_at(bn_comment.addr, &bn_comment.comment);
176181
}
177-
// TODO: Fix this before release.
178-
// TODO: Any attempt to add a tag type will create a undo action
179-
// TODO: Those are currently not thread safe when running in headless python.
180-
// TODO: See Mason for more lore.
181-
// function.add_tag(
182-
// &get_warp_tag_type(&view),
183-
// &matched_function.guid.to_string(),
184-
// None,
185-
// false,
186-
// None,
187-
// );
182+
if let Some(mlil) = ctx.mlil_function() {
183+
for variable in matched_function.variables {
184+
let decl_addr = ((function.start() as i64) + variable.offset) as u64;
185+
if let Some(decl_instr) = mlil.instruction_at(decl_addr) {
186+
let decl_var = match variable.location {
187+
Location::Register(RegisterLocation { id, .. }) => {
188+
decl_instr.variable_for_register_after(RegisterId(id as u32))
189+
}
190+
Location::Stack(StackLocation { offset, .. }) => {
191+
decl_instr.variable_for_stack_location_after(offset)
192+
}
193+
};
194+
let decl_ty = match variable.ty {
195+
Some(decl_ty) => to_bn_type(&function.arch(), &decl_ty),
196+
None => {
197+
let Some(existing_var) = function.variable_type(&decl_var) else {
198+
continue;
199+
};
200+
existing_var.contents
201+
}
202+
};
203+
let decl_name = variable
204+
.name
205+
.unwrap_or_else(|| function.variable_name(&decl_var));
206+
mlil.create_auto_var(&decl_var, &decl_ty, &decl_name, false)
207+
}
208+
}
209+
}
210+
function.add_tag(
211+
&get_warp_tag_type(&view),
212+
&matched_function.guid.to_string(),
213+
None,
214+
false,
215+
None,
216+
);
188217
}
189218
};
190219

@@ -208,12 +237,13 @@ pub fn insert_workflow() {
208237
.register_activity(&guid_activity)
209238
.unwrap();
210239
// Because we are going to impact analysis with application we must make sure the function update is triggered to continue to update analysis.
211-
// TODO: need to ask why i cant do core.function.update like in the rtti plugin.
212240
function_meta_workflow
213-
.register_activity_with_subactivities::<Vec<String>>(&apply_activity, vec![])
241+
.register_activity(&apply_activity)
214242
.unwrap();
215-
function_meta_workflow.insert("core.function.runFunctionRecognizers", [GUID_ACTIVITY_NAME]);
216-
function_meta_workflow.insert("core.function.generateMediumLevelIL", [APPLY_ACTIVITY_NAME]);
243+
function_meta_workflow
244+
.insert_after("core.function.runFunctionRecognizers", [GUID_ACTIVITY_NAME]);
245+
function_meta_workflow
246+
.insert_after("core.function.generateMediumLevelIL", [APPLY_ACTIVITY_NAME]);
217247
function_meta_workflow.register().unwrap();
218248

219249
let old_module_meta_workflow = Workflow::instance("core.module.metaAnalysis");

0 commit comments

Comments
 (0)