Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 150 additions & 8 deletions rust/src/architecture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@
data_buffer::DataBuffer,
disassembly::InstructionTextToken,
ffi::INVALID_REGISTER,
function::Function,
function::{Function, Location, NativeBlock},
platform::Platform,
rc::*,
relocation::CoreRelocationHandler,
string::{IntoCStr, *},
types::{NameAndType, Type},
Endianness,
};
use std::collections::{HashMap, HashSet};
use std::ops::Deref;
use std::{
borrow::Borrow,
Expand All @@ -48,7 +49,9 @@
use crate::function_recognizer::FunctionRecognizer;
use crate::relocation::{CustomRelocationHandlerHandle, RelocationHandler};

use crate::basic_block::BasicBlock;
use crate::confidence::Conf;
use crate::logger::Logger;
use crate::low_level_il::expression::ValueExpr;
use crate::low_level_il::lifting::{
get_default_flag_cond_llil, get_default_flag_write_llil, LowLevelILFlagWriteOp,
Expand Down Expand Up @@ -592,13 +595,151 @@

pub struct FunctionLifterContext {
pub(crate) handle: *mut BNFunctionLifterContext,
pub function: Ref<LowLevelILMutableFunction>,
pub platform: Ref<Platform>,
pub logger: Ref<Logger>,
pub blocks: Vec<Ref<BasicBlock<NativeBlock>>>,
pub no_return_calls: HashSet<Location>,
pub contextual_returns: HashMap<Location, bool>,
pub inlined_remapping: HashMap<Location, Location>,
pub user_indirect_branches: HashMap<Location, HashSet<Location>>,
pub auto_indirect_branches: HashMap<Location, HashSet<Location>>,
pub inlined_calls: HashSet<u64>,
}

unsafe fn lifter_context_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
if len == 0 {
&[]
} else {
debug_assert!(!ptr.is_null());
unsafe { std::slice::from_raw_parts(ptr, len) }
}
}

impl FunctionLifterContext {
pub unsafe fn from_raw(handle: *mut BNFunctionLifterContext) -> Self {
pub unsafe fn from_raw(
function: *mut BNLowLevelILFunction,
handle: *mut BNFunctionLifterContext,
) -> Self {
Self::from_raw_with_arch(function, handle, None)
}

pub(crate) unsafe fn from_raw_with_arch(
function: *mut BNLowLevelILFunction,
handle: *mut BNFunctionLifterContext,
arch: Option<CoreArchitecture>,
) -> Self {
debug_assert!(!function.is_null());
debug_assert!(!handle.is_null());
let flc_ref = &*handle;
let platform = unsafe { Platform::ref_from_raw(BNNewPlatformReference(flc_ref.platform)) };
let logger = unsafe { Logger::ref_from_raw(BNNewLoggerReference(flc_ref.logger)) };

let mut blocks = Vec::new();
for i in 0..flc_ref.basicBlockCount {
let block = unsafe {
Some(BasicBlock::ref_from_raw(
BNNewBasicBlockReference(*flc_ref.basicBlocks.add(i)),
NativeBlock::new(),
))
};

blocks.push(block.unwrap());
}

let raw_no_return_calls: &[BNArchitectureAndAddress] =
lifter_context_slice(flc_ref.noReturnCalls, flc_ref.noReturnCallsCount);
let no_return_calls: HashSet<Location> =
raw_no_return_calls.iter().map(Location::from).collect();

FunctionLifterContext { handle }
let raw_contextual_return_locs: &[BNArchitectureAndAddress] = unsafe {
lifter_context_slice(
flc_ref.contextualFunctionReturnLocations,
flc_ref.contextualFunctionReturnCount,
)
};
let raw_contextual_return_vals: &[bool] = unsafe {
lifter_context_slice(
flc_ref.contextualFunctionReturnValues,
flc_ref.contextualFunctionReturnCount,
)
};
let contextual_returns: HashMap<Location, bool> = raw_contextual_return_locs
.iter()
.map(Location::from)
.zip(raw_contextual_return_vals.iter().copied())
.collect();

let inlined_remapping: HashMap<Location, Location> = {
let raw_inline_remap_locs: &[BNArchitectureAndAddress] = lifter_context_slice(
flc_ref.inlinedRemappingKeys,
flc_ref.inlinedRemappingEntryCount,
);

let raw_inline_remap_dests: &[BNArchitectureAndAddress] = lifter_context_slice(
flc_ref.inlinedRemappingValues,
flc_ref.inlinedRemappingEntryCount,
);

raw_inline_remap_locs
.iter()
.map(Location::from)
.zip(raw_inline_remap_dests.iter().map(Location::from))
.collect()
};

let mut user_indirect_branches: HashMap<Location, HashSet<Location>> = HashMap::new();
let mut auto_indirect_branches: HashMap<Location, HashSet<Location>> = HashMap::new();
for i in 0..flc_ref.indirectBranchesCount {
let entry = unsafe { *flc_ref.indirectBranches.add(i) };
let src = Location::new(
Some(CoreArchitecture::from_raw(entry.sourceArch)),
entry.sourceAddr,
);
let dest = Location::new(
Some(CoreArchitecture::from_raw(entry.destArch)),
entry.destAddr,
);
if entry.autoDefined {
auto_indirect_branches.entry(src).or_default().insert(dest);
} else {
user_indirect_branches.entry(src).or_default().insert(dest);
}
}

let inlined_calls: HashSet<u64> =
lifter_context_slice(flc_ref.inlinedCalls, flc_ref.inlinedCallsCount)
.iter()
.copied()
.collect();

FunctionLifterContext {
handle,
function: LowLevelILMutableFunction::ref_from_raw_with_arch(
BNNewLowLevelILFunctionReference(function),
arch,
),
platform,
logger,
blocks,
no_return_calls,
contextual_returns,
inlined_remapping,
user_indirect_branches,
auto_indirect_branches,
inlined_calls,
}
}

pub fn prepare_block_translation(
&self,
func: &LowLevelILMutableFunction,
arch: &CoreArchitecture,
address: u64,
) {
unsafe {
BNPrepareBlockTranslation(func.handle, arch.handle, address);
}
}

pub fn get_function_arch_context<A: ArchitectureWithFunctionContext>(
Expand Down Expand Up @@ -1630,12 +1771,14 @@
A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
{
let custom_arch = unsafe { &*(ctxt as *mut A) };
let function = unsafe {
let llil = unsafe {
LowLevelILMutableFunction::from_raw_with_arch(function, Some(*custom_arch.as_ref()))
};

Check warning on line 1776 in rust/src/architecture.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/binaryninja-api/binaryninja-api/rust/src/architecture.rs

Check warning on line 1776 in rust/src/architecture.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/binaryninja-api/binaryninja-api/rust/src/architecture.rs
let mut context: FunctionLifterContext =
unsafe { FunctionLifterContext::from_raw(context) };
custom_arch.lift_function(function, &mut context)

let mut ctx = unsafe {
FunctionLifterContext::from_raw_with_arch(function, context, Some(*custom_arch.as_ref()))
};
custom_arch.lift_function(llil, &mut ctx)
}

extern "C" fn cb_reg_name<A>(ctxt: *mut c_void, reg: u32) -> *mut c_char
Expand Down Expand Up @@ -2630,7 +2773,6 @@

unsafe {
let res = BNRegisterArchitecture(name.as_ptr(), &mut custom_arch as *mut _);

assert!(!res.is_null());

(*raw).arch.assume_init_mut()
Expand Down
16 changes: 13 additions & 3 deletions rust/src/binary_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1808,26 +1808,36 @@ impl BinaryView {
address: u64,
platform: &Platform,
) -> Option<Ref<Function>> {
self.add_auto_function_ext(address, platform, None)
self.add_auto_function_ext(address, platform, None, false)
}

/// Add an auto function at the given `address` with the `platform` and function type.
///
/// The `auto_discovered` flag is used to prevent or allow this created function to be deleted if
/// it is never used (the function has no xrefs), if you are confident that this is a valid function
/// set this to `false`.
///
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
pub fn add_auto_function_ext(
&self,
address: u64,
platform: &Platform,
func_type: Option<&Type>,
auto_discovered: bool,
) -> Option<Ref<Function>> {
unsafe {
let func_type = match func_type {
Some(func_type) => func_type.handle,
None => std::ptr::null_mut(),
};

let handle =
BNAddFunctionForAnalysis(self.handle, platform.handle, address, true, func_type);
let handle = BNAddFunctionForAnalysis(
self.handle,
platform.handle,
address,
auto_discovered,
func_type,
);

if handle.is_null() {
return None;
Expand Down
8 changes: 8 additions & 0 deletions rust/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ impl Logger {
Self::new_with_session(name, LOGGER_DEFAULT_SESSION_ID)
}

pub fn ref_from_raw(handle: *mut BNLogger) -> Ref<Logger> {
unsafe {
Ref::new(Logger {
handle: NonNull::new(handle).unwrap(),
})
}
}

/// Create a logger scoped with the specific [`SessionId`], hiding the logs when the session
/// is not active in the UI.
///
Expand Down
40 changes: 40 additions & 0 deletions rust/src/low_level_il.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

use std::borrow::Cow;
use std::collections::HashSet;
use std::fmt;
use std::fmt::{Debug, Display};
// TODO : provide some way to forbid emitting register reads for certain registers
Expand Down Expand Up @@ -316,3 +317,42 @@ pub enum VisitorAction {
Sibling,
Halt,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum ILInstructionAttribute {
ILAllowDeadStoreElimination,
ILPreventDeadStoreElimination,
MLILAssumePossibleUse,
MLILUnknownSize,
SrcInstructionUsesPointerAuth,
ILPreventAliasAnalysis,
ILIsCFGProtected,
MLILPossiblyUnusedIntermediate,
HLILFoldableExpr,
HLILInvertableCondition,
HLILEarlyReturnPossible,
HLILSwitchRecoveryPossible,
ILTransparentCopy,
}

impl ILInstructionAttribute {
pub fn value(&self) -> u32 {
match self {
Self::ILAllowDeadStoreElimination => 1,
Self::ILPreventDeadStoreElimination => 2,
Self::MLILAssumePossibleUse => 4,
Self::MLILUnknownSize => 8,
Self::SrcInstructionUsesPointerAuth => 16,
Self::ILPreventAliasAnalysis => 32,
Self::ILIsCFGProtected => 64,
Self::MLILPossiblyUnusedIntermediate => 128,
Self::HLILFoldableExpr => 256,
Self::HLILInvertableCondition => 512,
Self::HLILEarlyReturnPossible => 1024,
Self::HLILSwitchRecoveryPossible => 2048,
Self::ILTransparentCopy => 4096,
}
}
}

pub type ILInstructionAttributeSet = HashSet<ILInstructionAttribute>;
14 changes: 14 additions & 0 deletions rust/src/low_level_il/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,20 @@ where
Some(unsafe { BasicBlock::ref_from_raw(block, LowLevelILBlock { function: self }) })
}
}

pub fn set_indirect_branches(&self, branches: &[Location]) {
let mut bn_branches: Box<[BNArchitectureAndAddress]> = branches
.iter()
.map(|loc| BNArchitectureAndAddress {
address: loc.addr,
arch: loc.arch.unwrap_or_else(|| self.arch()).handle,
})
.collect();

unsafe {
BNLowLevelILSetIndirectBranches(self.handle, bn_branches.as_mut_ptr(), branches.len());
}
}
}

impl<M: FunctionMutability> LowLevelILFunction<M, NonSSA> {
Expand Down
35 changes: 32 additions & 3 deletions rust/src/low_level_il/lifting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@

use std::marker::PhantomData;

use binaryninjacore_sys::{BNAddLowLevelILLabelForAddress, BNLowLevelILOperation};
use binaryninjacore_sys::{BNLowLevelILLabel, BNRegisterOrConstant};
use binaryninjacore_sys::{
BNAddLowLevelILLabelForAddress, BNLowLevelILClearIndirectBranches, BNLowLevelILLabel,
BNLowLevelILOperation, BNRegisterOrConstant, BNSetLowLevelILExprAttributes,
};

use super::*;
use crate::architecture::{Architecture, FlagWriteId, RegisterId};
use crate::architecture::{CoreRegister, Register as ArchReg};
use crate::architecture::{
Flag, FlagClass, FlagCondition, FlagGroup, FlagRole, FlagWrite, Intrinsic,
};
use crate::function::Location;
use crate::basic_block::BasicBlock;
use crate::function::{Location, NativeBlock};

pub trait LiftableLowLevelIL<'func> {
type Result: ExpressionResultType;
Expand Down Expand Up @@ -1512,6 +1515,13 @@ impl LowLevelILMutableFunction {
}
}

pub fn set_current_source_block(&self, source: &BasicBlock<NativeBlock>) {
use binaryninjacore_sys::BNLowLevelILSetCurrentSourceBlock;
unsafe {
BNLowLevelILSetCurrentSourceBlock(self.handle, source.handle);
}
}

pub fn label_for_address<L: Into<Location>>(&self, loc: L) -> Option<LowLevelILLabel> {
use binaryninjacore_sys::BNGetLowLevelILLabelForAddress;

Expand Down Expand Up @@ -1561,6 +1571,25 @@ impl LowLevelILMutableFunction {
}
*label = new_label;
}

pub fn set_expr_attributes(
&self,
expr: LowLevelExpressionIndex,
value: &ILInstructionAttributeSet,
) {
let mut result = 0u32;
for flag in value {
result |= flag.value();
}

unsafe {
BNSetLowLevelILExprAttributes(self.handle, expr.0, result);
}
}

pub fn clear_indirect_branches(&self) {
unsafe { BNLowLevelILClearIndirectBranches(self.handle) };
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
Expand Down
Loading
Loading