summaryrefslogtreecommitdiff
path: root/plugins/warp/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/warp/src/lib.rs')
-rw-r--r--plugins/warp/src/lib.rs111
1 files changed, 58 insertions, 53 deletions
diff --git a/plugins/warp/src/lib.rs b/plugins/warp/src/lib.rs
index 6e195fc3..3f2fc276 100644
--- a/plugins/warp/src/lib.rs
+++ b/plugins/warp/src/lib.rs
@@ -1,25 +1,28 @@
+use crate::cache::{
+ cached_adjacency_constraints, cached_call_site_constraints, cached_function_guid,
+};
+use crate::convert::{from_bn_symbol, from_bn_type};
use binaryninja::architecture::{
Architecture, ImplicitRegisterExtend, Register as BNRegister, RegisterInfo,
};
-use binaryninja::basicblock::BasicBlock as BNBasicBlock;
-use binaryninja::binaryview::BinaryViewExt;
+use binaryninja::basic_block::BasicBlock as BNBasicBlock;
+use binaryninja::binary_view::BinaryViewExt;
+use binaryninja::confidence::MAX_CONFIDENCE;
use binaryninja::function::{Function as BNFunction, NativeBlock};
-use binaryninja::llil;
-use binaryninja::llil::{
- ExprInfo, FunctionMutability, InstrInfo, Instruction, NonSSA, NonSSAVariant, Register,
- VisitorAction,
+use binaryninja::low_level_il::expression::{ExpressionHandler, LowLevelILExpressionKind};
+use binaryninja::low_level_il::function::{
+ FunctionMutability, LowLevelILFunction, NonSSA, RegularNonSSA,
};
+use binaryninja::low_level_il::instruction::{
+ InstructionHandler, LowLevelILInstruction, LowLevelILInstructionKind,
+};
+use binaryninja::low_level_il::{LowLevelILRegister, VisitorAction};
use binaryninja::rc::Ref as BNRef;
use std::path::PathBuf;
use warp::signature::basic_block::BasicBlockGUID;
use warp::signature::function::constraints::FunctionConstraints;
use warp::signature::function::{Function, FunctionGUID};
-use crate::cache::{
- cached_adjacency_constraints, cached_call_site_constraints, cached_function_guid,
-};
-use crate::convert::{from_bn_symbol, from_bn_type};
-
pub mod cache;
pub mod convert;
mod matcher;
@@ -28,7 +31,7 @@ mod plugin;
pub fn core_signature_dir() -> PathBuf {
// Get core signatures for the given platform
- let install_dir = binaryninja::install_directory().unwrap();
+ let install_dir = binaryninja::install_directory();
// macOS core dir is separate from the install dir.
#[cfg(target_os = "macos")]
let core_dir = install_dir.parent().unwrap().join("Resources");
@@ -38,18 +41,18 @@ pub fn core_signature_dir() -> PathBuf {
}
pub fn user_signature_dir() -> PathBuf {
- binaryninja::user_directory().unwrap().join("signatures/")
+ binaryninja::user_directory().join("signatures/")
}
-pub fn build_function<A: Architecture, M: FunctionMutability, V: NonSSAVariant>(
+pub fn build_function<A: Architecture, M: FunctionMutability>(
func: &BNFunction,
- llil: &llil::Function<A, M, NonSSA<V>>,
+ llil: &LowLevelILFunction<A, M, NonSSA<RegularNonSSA>>,
) -> Function {
let bn_fn_ty = func.function_type();
Function {
guid: cached_function_guid(func, llil),
symbol: from_bn_symbol(&func.symbol()),
- ty: from_bn_type(&func.view(), &bn_fn_ty, 255),
+ ty: from_bn_type(&func.view(), &bn_fn_ty, MAX_CONFIDENCE),
constraints: FunctionConstraints {
// NOTE: Adding adjacent only works if analysis is complete.
// NOTE: We do not filter out adjacent functions here.
@@ -69,13 +72,13 @@ pub fn sorted_basic_blocks(func: &BNFunction) -> Vec<BNRef<BNBasicBlock<NativeBl
.iter()
.map(|bb| bb.clone())
.collect::<Vec<_>>();
- basic_blocks.sort_by_key(|f| f.raw_start());
+ basic_blocks.sort_by_key(|f| f.start_index());
basic_blocks
}
-pub fn function_guid<A: Architecture, M: FunctionMutability, V: NonSSAVariant>(
+pub fn function_guid<A: Architecture, M: FunctionMutability>(
func: &BNFunction,
- llil: &llil::Function<A, M, NonSSA<V>>,
+ llil: &LowLevelILFunction<A, M, NonSSA<RegularNonSSA>>,
) -> FunctionGUID {
let basic_blocks = sorted_basic_blocks(func);
let basic_block_guids = basic_blocks
@@ -85,9 +88,9 @@ pub fn function_guid<A: Architecture, M: FunctionMutability, V: NonSSAVariant>(
FunctionGUID::from_basic_blocks(&basic_block_guids)
}
-pub fn basic_block_guid<A: Architecture, M: FunctionMutability, V: NonSSAVariant>(
+pub fn basic_block_guid<A: Architecture, M: FunctionMutability>(
basic_block: &BNBasicBlock<NativeBlock>,
- llil: &llil::Function<A, M, NonSSA<V>>,
+ llil: &LowLevelILFunction<A, M, NonSSA<RegularNonSSA>>,
) -> BasicBlockGUID {
let func = basic_block.function();
let view = func.view();
@@ -95,14 +98,16 @@ pub fn basic_block_guid<A: Architecture, M: FunctionMutability, V: NonSSAVariant
let max_instr_len = arch.max_instr_len();
// NOPs and useless moves are blacklisted to allow for hot-patchable functions.
- let is_blacklisted_instr = |instr: &Instruction<A, M, NonSSA<V>>| {
- match instr.info() {
- InstrInfo::Nop(_) => true,
- InstrInfo::SetReg(op) => {
- match op.source_expr().info() {
- ExprInfo::Reg(source_op) if op.dest_reg() == source_op.source_reg() => {
+ let is_blacklisted_instr = |instr: &LowLevelILInstruction<A, M, NonSSA<RegularNonSSA>>| {
+ match instr.kind() {
+ LowLevelILInstructionKind::Nop(_) => true,
+ LowLevelILInstructionKind::SetReg(op) => {
+ match op.source_expr().kind() {
+ LowLevelILExpressionKind::Reg(source_op)
+ if op.dest_reg() == source_op.source_reg() =>
+ {
match op.dest_reg() {
- Register::ArchReg(r) => {
+ LowLevelILRegister::ArchReg(r) => {
// If this register has no implicit extend then we can safely assume it's a NOP.
// Ex. on x86_64 we don't want to remove `mov edi, edi` as it will zero the upper 32 bits.
// Ex. on x86 we do want to remove `mov edi, edi` as it will not have a side effect like above.
@@ -111,7 +116,7 @@ pub fn basic_block_guid<A: Architecture, M: FunctionMutability, V: NonSSAVariant
ImplicitRegisterExtend::NoExtend
)
}
- Register::Temp(_) => false,
+ LowLevelILRegister::Temp(_) => false,
}
}
_ => false,
@@ -121,16 +126,19 @@ pub fn basic_block_guid<A: Architecture, M: FunctionMutability, V: NonSSAVariant
}
};
- let is_variant_instr = |instr: &Instruction<A, M, NonSSA<V>>| {
- let is_variant_expr = |expr: &ExprInfo<A, M, NonSSA<V>>| {
+ let is_variant_instr = |instr: &LowLevelILInstruction<A, M, NonSSA<RegularNonSSA>>| {
+ let is_variant_expr = |expr: &LowLevelILExpressionKind<A, M, NonSSA<RegularNonSSA>>| {
+ // TODO: Checking the section here is slow, we should gather all section ranges outside of this.
match expr {
- ExprInfo::ConstPtr(op) if !view.sections_at(op.value()).is_empty() => {
+ LowLevelILExpressionKind::ConstPtr(op)
+ if !view.sections_at(op.value()).is_empty() =>
+ {
// Constant Pointer must be in a section for it to be relocatable.
// NOTE: We cannot utilize segments here as there will be a zero based segment.
true
}
- ExprInfo::ExternPtr(_) => true,
- ExprInfo::Const(op) if !view.sections_at(op.value()).is_empty() => {
+ LowLevelILExpressionKind::ExternPtr(_) => true,
+ LowLevelILExpressionKind::Const(op) if !view.sections_at(op.value()).is_empty() => {
// Constant value must be in a section for it to be relocatable.
// NOTE: We cannot utilize segments here as there will be a zero based segment.
true
@@ -140,8 +148,8 @@ pub fn basic_block_guid<A: Architecture, M: FunctionMutability, V: NonSSAVariant
};
// Visit instruction expressions looking for variant expression, [VisitorAction::Halt] means variant.
- instr.visit_tree(&mut |_expr, expr_info| {
- if is_variant_expr(expr_info) {
+ instr.visit_tree(&mut |expr| {
+ if is_variant_expr(&expr.kind()) {
// Found a variant expression
VisitorAction::Halt
} else {
@@ -150,12 +158,12 @@ pub fn basic_block_guid<A: Architecture, M: FunctionMutability, V: NonSSAVariant
}) == VisitorAction::Halt
};
- let basic_block_range = basic_block.raw_start()..basic_block.raw_end();
+ let basic_block_range = basic_block.start_index()..basic_block.end_index();
let mut basic_block_bytes = Vec::with_capacity(basic_block_range.count());
for instr_addr in basic_block.into_iter() {
let mut instr_bytes = view.read_vec(instr_addr, max_instr_len);
if let Some(instr_info) = arch.instruction_info(&instr_bytes, instr_addr) {
- instr_bytes.truncate(instr_info.len());
+ instr_bytes.truncate(instr_info.length);
if let Some(instr_llil) = llil.instruction_at(instr_addr) {
// If instruction is blacklisted don't include the bytes.
if !is_blacklisted_instr(&instr_llil) {
@@ -176,7 +184,7 @@ pub fn basic_block_guid<A: Architecture, M: FunctionMutability, V: NonSSAVariant
#[cfg(test)]
mod tests {
use crate::cache::cached_function_guid;
- use binaryninja::binaryview::BinaryViewExt;
+ use binaryninja::binary_view::BinaryViewExt;
use binaryninja::headless::Session;
use std::path::PathBuf;
use std::sync::OnceLock;
@@ -185,7 +193,7 @@ mod tests {
fn get_session<'a>() -> &'a Session {
// TODO: This is not shared between other test modules, should still be fine (mutex in core now).
- INIT.get_or_init(|| Session::new())
+ INIT.get_or_init(|| Session::new().expect("Failed to initialize session"))
}
#[test]
@@ -196,19 +204,16 @@ mod tests {
let entry = entry.expect("Failed to read directory entry");
let path = entry.path();
if path.is_file() {
- if let Some(path_str) = path.to_str() {
- if path_str.ends_with("library.o") {
- if let Some(inital_bv) = session.load(path_str) {
- let mut functions = inital_bv
- .functions()
- .iter()
- .map(|f| cached_function_guid(&f, &f.low_level_il().unwrap()))
- .collect::<Vec<_>>();
- functions.sort_by_key(|guid| guid.guid);
- insta::assert_debug_snapshot!(functions);
- }
- }
- }
+ let view = session.load(&path).expect("Failed to load view");
+ let mut functions = view
+ .functions()
+ .iter()
+ .map(|f| cached_function_guid(&f, &f.low_level_il().unwrap()))
+ .collect::<Vec<_>>();
+ functions.sort_by_key(|guid| guid.guid);
+ let snapshot_name =
+ format!("snapshot_{}", path.file_stem().unwrap().to_string_lossy());
+ insta::assert_debug_snapshot!(snapshot_name, functions);
}
}
}