From 3569571e1d6dc5637cf6ef567a79958a173d33cc Mon Sep 17 00:00:00 2001 From: Rubens Brandao Date: Fri, 14 Jun 2024 14:17:15 -0300 Subject: [PATCH 1/3] implement rust Component --- rust/src/binaryview.rs | 56 +++++++++ rust/src/component.rs | 276 +++++++++++++++++++++++++++++++++++++++++ rust/src/function.rs | 8 ++ rust/src/lib.rs | 1 + rust/src/types.rs | 18 +++ 5 files changed, 359 insertions(+) create mode 100644 rust/src/component.rs diff --git a/rust/src/binaryview.rs b/rust/src/binaryview.rs index 8d7a2db46..9fb963a7e 100644 --- a/rust/src/binaryview.rs +++ b/rust/src/binaryview.rs @@ -33,6 +33,7 @@ use std::{ops, slice}; use crate::architecture::Architecture; use crate::architecture::CoreArchitecture; use crate::basicblock::BasicBlock; +use crate::component::{Component, ComponentBuilder, IntoComponentGuid}; use crate::databuffer::DataBuffer; use crate::debuginfo::DebugInfo; use crate::fileaccessor::FileAccessor; @@ -1362,6 +1363,61 @@ pub trait BinaryViewExt: BinaryViewBase { Array::new(handle, count, ()) } } + + fn component_by_guid(&self, guid: S) -> Option { + let name = guid.into_bytes_with_nul(); + let result = unsafe { + BNGetComponentByGuid( + self.as_ref().handle, + name.as_ref().as_ptr() as *const core::ffi::c_char, + ) + }; + core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) }) + } + + fn root_component(&self) -> Option { + let result = unsafe { BNGetRootComponent(self.as_ref().handle) }; + core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) }) + } + + fn component_builder(&self) -> ComponentBuilder { + ComponentBuilder::new_from_raw(self.as_ref().handle) + } + + fn component_by_path(&self, path: P) -> Option { + let path = path.into_bytes_with_nul(); + let result = unsafe { + BNGetComponentByPath( + self.as_ref().handle, + path.as_ref().as_ptr() as *const core::ffi::c_char, + ) + }; + core::ptr::NonNull::new(result).map(|h| unsafe { Component::from_raw(h) }) + } + + fn remove_component(&self, component: &Component) -> bool { + unsafe { BNRemoveComponent(self.as_ref().handle, component.as_raw()) } + } + + fn remove_component_by_guid(&self, guid: P) -> bool { + let path = guid.component_guid(); + unsafe { BNRemoveComponentByGuid(self.as_ref().handle, path.as_ptr()) } + } + + fn data_variable_parent_components( + &self, + data_variable: &DataVariable, + ) -> Array { + let mut count = 0; + let result = unsafe { + BNGetDataVariableParentComponents( + self.as_ref().handle, + data_variable.address(), + &mut count, + ) + }; + unsafe { Array::new(result, count, ()) } + } } impl BinaryViewExt for T {} diff --git a/rust/src/component.rs b/rust/src/component.rs new file mode 100644 index 000000000..e17efabfa --- /dev/null +++ b/rust/src/component.rs @@ -0,0 +1,276 @@ +use core::{ffi, mem, ptr}; + +use crate::binaryview::{BinaryView, BinaryViewBase, BinaryViewExt}; +use crate::function::Function; +use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref}; +use crate::string::{BnStrCompatible, BnString}; +use crate::types::{ComponentReferencedTypes, DataVariable}; + +use binaryninjacore_sys::*; + +pub struct ComponentBuilder { + bv: *mut BNBinaryView, + parent: Option, + name: Option, +} + +impl ComponentBuilder { + pub(crate) fn new_from_raw(bv: *mut BNBinaryView) -> Self { + Self { + bv, + parent: None, + name: None, + } + } + pub fn new(bv: &I) -> Self { + Self { + bv: bv.as_ref().handle, + parent: None, + name: None, + } + } + + pub fn parent(mut self, parent: G) -> Self { + self.parent = Some(parent.component_guid()); + self + } + + pub fn name(mut self, name: S) -> Self { + self.name = Some(BnString::new(name)); + self + } + + pub fn finalize(self) -> Component { + let result = match (&self.parent, &self.name) { + (None, None) => unsafe { BNCreateComponent(self.bv) }, + (None, Some(name)) => unsafe { BNCreateComponentWithName(self.bv, name.as_ptr()) }, + (Some(guid), None) => unsafe { BNCreateComponentWithParent(self.bv, guid.as_ptr()) }, + (Some(guid), Some(name)) => unsafe { + BNCreateComponentWithParentAndName(self.bv, guid.as_ptr(), name.as_ptr()) + }, + }; + unsafe { Component::from_raw(ptr::NonNull::new(result).unwrap()) } + } +} + +/// Components are objects that can contain Functions and other Components. +/// +/// They can be queried for information about the functions contained within them. +/// +/// Components have a Guid, which persistent across saves and loads of the database, and should be +/// used for retrieving components when such is required and a reference to the Component cannot be held. +#[repr(transparent)] +pub struct Component { + handle: ptr::NonNull, +} + +impl Component { + #[allow(clippy::mut_from_ref)] + pub(crate) unsafe fn as_raw(&self) -> &mut BNComponent { + &mut *self.handle.as_ptr() + } + + pub(crate) unsafe fn from_raw(handle: ptr::NonNull) -> Self { + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: &*mut BNComponent) -> &Self { + assert!(!handle.is_null()); + mem::transmute(handle) + } + + pub fn guid(&self) -> BnString { + let result = unsafe { BNComponentGetGuid(self.as_raw()) }; + assert!(!result.is_null()); + unsafe { BnString::from_raw(result) } + } + + /// Add function to this component. + pub fn add_function(&self, func: &Function) -> bool { + unsafe { BNComponentAddFunctionReference(self.as_raw(), func.handle) } + } + + /// Check whether this component contains a function. + pub fn contains_function(&self, func: &Function) -> bool { + unsafe { BNComponentContainsFunction(self.as_raw(), func.handle) } + } + + /// Remove function from this component. + pub fn remove_function(&self, func: &Function) -> bool { + unsafe { BNComponentRemoveFunctionReference(self.as_raw(), func.handle) } + } + + /// Move component to this component. This will remove it from the old parent. + pub fn add_component(&self, component: &Component) -> bool { + unsafe { BNComponentAddComponent(self.as_raw(), component.as_raw()) } + } + + /// Check whether this component contains a component. + pub fn contains_component(&self, component: &Component) -> bool { + unsafe { BNComponentContainsComponent(self.as_raw(), component.as_raw()) } + } + + /// Remove a component from the current component, moving it to the root. + /// + /// This function has no effect when used from the root component. + /// Use `BinaryView.remove_component` to Remove a component from the tree entirely. + pub fn remove_component(&self, component: &Component) -> bool { + self.view() + .unwrap() + .root_component() + .unwrap() + .add_component(component) + } + + pub fn add_data_variable(&self, data_variable: &DataVariable) -> bool { + unsafe { BNComponentAddDataVariable(self.as_raw(), data_variable.address()) } + } + + pub fn contains_data_variable(&self, data_variable: &DataVariable) -> bool { + unsafe { BNComponentContainsDataVariable(self.as_raw(), data_variable.address()) } + } + + pub fn remove_data_variable(&self, data_variable: &DataVariable) -> bool { + unsafe { BNComponentRemoveDataVariable(self.as_raw(), data_variable.address()) } + } + + /// Original Name of the component + pub fn display_name(&self) -> BnString { + let result = unsafe { BNComponentGetDisplayName(self.as_raw()) }; + assert!(!result.is_null()); + unsafe { BnString::from_raw(result) } + } + + /// Original name set for this component + + /// :note: The `.display_name` property should be used for `bv.get_component_by_path()` lookups. + + /// This can differ from the .display_name property if one of its sibling components has the same .original_name; In that + /// case, .name will be an automatically generated unique name (e.g. "MyComponentName (1)") while .original_name will + /// remain what was originally set (e.g. "MyComponentName") + + /// If this component has a duplicate name and is moved to a component where none of its siblings share its name, + /// the .name property will return the original "MyComponentName" + pub fn name(&self) -> BnString { + let result = unsafe { BNComponentGetOriginalName(self.as_raw()) }; + assert!(!result.is_null()); + unsafe { BnString::from_raw(result) } + } + + pub fn set_name(&self, name: S) { + let name = name.into_bytes_with_nul(); + unsafe { BNComponentSetName(self.as_raw(), name.as_ref().as_ptr() as *const ffi::c_char) } + } + + /// The component that contains this component, if it exists. + pub fn parent(&self) -> Option { + let result = unsafe { BNComponentGetParent(self.as_raw()) }; + ptr::NonNull::new(result).map(|h| unsafe { Self::from_raw(h) }) + } + + pub fn view(&self) -> Option> { + let result = unsafe { BNComponentGetView(self.as_raw()) }; + (!result.is_null()).then(|| unsafe { BinaryView::from_raw(result) }) + } + + /// Is an iterator for all Components contained within this Component + pub fn components(&self) -> Array { + let mut count = 0; + let result = unsafe { BNComponentGetContainedComponents(self.as_raw(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// List of all Functions contained within this Component + /// + ///
+ /// + /// functions Should be used instead of this in any performance sensitive context. + /// + ///
+ pub fn functions(&self) -> Array { + let mut count = 0; + let result = unsafe { BNComponentGetContainedFunctions(self.as_raw(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + pub fn data_variables(&self) -> Array { + let mut count = 0; + let result = unsafe { BNComponentGetContainedDataVariables(self.as_raw(), &mut count) }; + assert!(!result.is_null()); + unsafe { Array::new(result, count, ()) } + } + + /// Get data variables referenced by this component + /// + /// * `recursive` - Get all DataVariables referenced by this component and subcomponents. + pub fn get_referenced_data_variables(&self, recursive: bool) -> Array { + let mut count = 0; + let result = if recursive { + unsafe { BNComponentGetReferencedDataVariablesRecursive(self.as_raw(), &mut count) } + } else { + unsafe { BNComponentGetReferencedDataVariables(self.as_raw(), &mut count) } + }; + unsafe { Array::new(result, count, ()) } + } + + /// Get Types referenced by this component + /// + /// * `recursive` - Get all Types referenced by this component and subcomponents. + pub fn get_referenced_types(&self, recursive: bool) -> Array { + let mut count = 0; + let result = if recursive { + unsafe { BNComponentGetReferencedTypesRecursive(self.as_raw(), &mut count) } + } else { + unsafe { BNComponentGetReferencedTypes(self.as_raw(), &mut count) } + }; + unsafe { Array::new(result, count, ()) } + } +} + +impl Drop for Component { + fn drop(&mut self) { + unsafe { BNFreeComponent(self.as_raw()) } + } +} + +impl Clone for Component { + fn clone(&self) -> Self { + unsafe { + Self::from_raw(ptr::NonNull::new(BNNewComponentReference(self.as_raw())).unwrap()) + } + } +} + +impl CoreArrayProvider for Component { + type Raw = *mut BNComponent; + type Context = (); + type Wrapped<'a> = &'a Self; +} + +unsafe impl CoreArrayProviderInner for Component { + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNFreeComponents(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + Self::ref_from_raw(raw) + } +} + +pub trait IntoComponentGuid { + fn component_guid(self) -> BnString; +} + +impl IntoComponentGuid for &Component { + fn component_guid(self) -> BnString { + self.guid() + } +} + +impl IntoComponentGuid for S { + fn component_guid(self) -> BnString { + BnString::new(self) + } +} diff --git a/rust/src/function.rs b/rust/src/function.rs index 48f02205b..bfd8b587e 100644 --- a/rust/src/function.rs +++ b/rust/src/function.rs @@ -19,6 +19,7 @@ use crate::{ basicblock::{BasicBlock, BlockContext}, binaryview::{BinaryView, BinaryViewExt}, callingconvention::CallingConvention, + component::Component, disassembly::{DisassemblySettings, DisassemblyTextLine}, flowgraph::FlowGraph, hlil, llil, @@ -2138,6 +2139,13 @@ impl Function { let result = unsafe { BNCreateFunctionGraph(self.handle, graph_type, settings_raw) }; unsafe { Ref::new(FlowGraph::from_raw(result)) } } + + pub fn parent_components(&self) -> Array { + let mut count = 0; + let result = unsafe{ BNGetFunctionParentComponents(self.view().handle, self.handle, &mut count) }; + assert!(!result.is_null()); + unsafe{ Array::new(result, count, ()) } + } } impl fmt::Debug for Function { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index e24a3f784..1edf750c2 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -137,6 +137,7 @@ pub mod databuffer; pub mod debuginfo; pub mod demangle; pub mod disassembly; +pub mod component; pub mod downloadprovider; pub mod fileaccessor; pub mod filemetadata; diff --git a/rust/src/types.rs b/rust/src/types.rs index 9b2271d57..8fab75dc3 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -1339,6 +1339,24 @@ impl ToOwned for Type { } } +pub struct ComponentReferencedTypes; +impl CoreArrayProvider for ComponentReferencedTypes{ + type Raw= *mut BNType; + type Context= (); + type Wrapped<'a> = &'a Self; +} + +unsafe impl CoreArrayProviderInner for ComponentReferencedTypes{ + unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { + BNComponentFreeReferencedTypes(raw, count) + } + + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { + // SAFETY: BNType and Type are trasparent + core::mem::transmute(raw) + } +} + /////////////////////// // FunctionParameter From c0c48b2d64533f02ea1e7a76433118917ad3b0f0 Mon Sep 17 00:00:00 2001 From: Rubens Brandao Date: Fri, 14 Jun 2024 14:31:09 -0300 Subject: [PATCH 2/3] add Component missing functions --- rust/src/component.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/rust/src/component.rs b/rust/src/component.rs index e17efabfa..bee101be3 100644 --- a/rust/src/component.rs +++ b/rust/src/component.rs @@ -227,8 +227,32 @@ impl Component { }; unsafe { Array::new(result, count, ()) } } + + pub fn remove_itself(&self) -> bool { + unsafe { BNComponentRemoveComponent(self.as_raw()) } + } + + pub fn remove_all_functions(&self) { + unsafe { BNComponentRemoveAllFunctions(self.as_raw()) } + } + + pub fn add_all_members(&self, component: &Component) { + unsafe { BNComponentAddAllMembersFromComponent(self.as_raw(), component.as_raw()) } + } } +impl PartialEq for Component { + fn eq(&self, other: &Self) -> bool { + unsafe { BNComponentsEqual(self.as_raw(), other.as_raw()) } + } + + fn ne(&self, other: &Self) -> bool { + unsafe { BNComponentsNotEqual(self.as_raw(), other.as_raw()) } + } +} + +impl Eq for Component {} + impl Drop for Component { fn drop(&mut self) { unsafe { BNFreeComponent(self.as_raw()) } From d5c679d3ec7441eeb8cf6a55d6409edc38715f9e Mon Sep 17 00:00:00 2001 From: Rubens Brandao Date: Mon, 24 Jun 2024 10:35:49 -0300 Subject: [PATCH 3/3] fix return type for Array ComponentReferencedTypes --- rust/src/types.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/rust/src/types.rs b/rust/src/types.rs index 8fab75dc3..d5be0e864 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -1340,13 +1340,13 @@ impl ToOwned for Type { } pub struct ComponentReferencedTypes; -impl CoreArrayProvider for ComponentReferencedTypes{ - type Raw= *mut BNType; - type Context= (); - type Wrapped<'a> = &'a Self; +impl CoreArrayProvider for ComponentReferencedTypes { + type Raw = *mut BNType; + type Context = (); + type Wrapped<'a> = &'a Type; } -unsafe impl CoreArrayProviderInner for ComponentReferencedTypes{ +unsafe impl CoreArrayProviderInner for ComponentReferencedTypes { unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { BNComponentFreeReferencedTypes(raw, count) } @@ -1541,7 +1541,6 @@ pub struct NamedTypedVariable { } impl NamedTypedVariable { - pub fn new(var: Variable, name: String, ty: Conf>, auto_defined: bool) -> Self { Self { name, @@ -1556,7 +1555,7 @@ impl NamedTypedVariable { var: Variable::from_raw(var.var), auto_defined: var.autoDefined, name: CStr::from_ptr(var.name).to_str().unwrap().to_string(), - ty: Conf::new(Type::ref_from_raw(var.type_), var.typeConfidence) + ty: Conf::new(Type::ref_from_raw(var.type_), var.typeConfidence), } }