diff options
Diffstat (limited to 'plugins/warp/src/lib.rs')
| -rw-r--r-- | plugins/warp/src/lib.rs | 111 |
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); } } } |
