Skip to content

Commit ce22ddc

Browse files
committed
Require a default platform to create functions for a given Binary View
This affects mainly users creating an empty raw view headlessly and adding a function.
1 parent 6143812 commit ce22ddc

File tree

4 files changed

+167
-38
lines changed

4 files changed

+167
-38
lines changed

python/binaryview.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4761,6 +4761,8 @@ def add_function(self, addr: int, plat: Optional['_platform.Platform'] = None, a
47614761
raise Exception("Default platform not set in BinaryView")
47624762
if plat is None:
47634763
plat = self.platform
4764+
if self.platform is None:
4765+
self.platform = plat
47644766
if not isinstance(plat, _platform.Platform):
47654767
raise ValueError("Provided platform is not of type `Platform`")
47664768

@@ -4789,6 +4791,8 @@ def add_entry_point(self, addr: int, plat: Optional['_platform.Platform'] = None
47894791
raise Exception("Default platform not set in BinaryView")
47904792
if plat is None:
47914793
plat = self.platform
4794+
if self.platform is None:
4795+
self.platform = plat
47924796
if not isinstance(plat, _platform.Platform):
47934797
raise ValueError("Provided platform is not of type `Platform`")
47944798
core.BNAddEntryPointForAnalysis(self.handle, plat.handle, addr)
@@ -4846,6 +4850,8 @@ def create_user_function(self, addr: int, plat: Optional['_platform.Platform'] =
48464850
if self.platform is None:
48474851
raise Exception("Attempting to call create_user_function with no specified platform")
48484852
plat = self.platform
4853+
if self.platform is None:
4854+
self.platform = plat
48494855
func = core.BNCreateUserFunction(self.handle, plat.handle, addr)
48504856
if func is None:
48514857
return None

rust/src/binary_view.rs

Lines changed: 96 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -924,31 +924,40 @@ pub trait BinaryViewExt: BinaryViewBase {
924924
MemoryMap::new(self.as_ref().to_owned())
925925
}
926926

927-
fn add_auto_function(&self, plat: &Platform, addr: u64) -> Option<Ref<Function>> {
928-
unsafe {
929-
let handle = BNAddFunctionForAnalysis(
930-
self.as_ref().handle,
931-
plat.handle,
932-
addr,
933-
false,
934-
std::ptr::null_mut(),
935-
);
936-
937-
if handle.is_null() {
938-
return None;
939-
}
927+
/// Add an auto function at the given `address` with the views default platform.
928+
///
929+
/// NOTE: The default platform **must** be set for this view!
930+
fn add_auto_function(&self, address: u64) -> Option<Ref<Function>> {
931+
let platform = self.default_platform()?;
932+
self.add_auto_function_with_platform(address, &platform)
933+
}
940934

941-
Some(Function::ref_from_raw(handle))
942-
}
935+
/// Add an auto function at the given `address` with the `platform`.
936+
///
937+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
938+
fn add_auto_function_with_platform(
939+
&self,
940+
address: u64,
941+
platform: &Platform,
942+
) -> Option<Ref<Function>> {
943+
self.add_auto_function_ext(address, platform, None)
943944
}
944945

945-
fn add_function_with_type(
946+
/// Add an auto function at the given `address` with the `platform` and function type.
947+
///
948+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
949+
fn add_auto_function_ext(
946950
&self,
947-
plat: &Platform,
948-
addr: u64,
949-
auto_discovered: bool,
951+
address: u64,
952+
platform: &Platform,
950953
func_type: Option<&Type>,
951954
) -> Option<Ref<Function>> {
955+
// If the view does not have a default platform, we must set it.
956+
// The core expects there to be one before it can create a function.
957+
if self.default_platform().is_none() {
958+
self.set_default_platform(platform);
959+
}
960+
952961
unsafe {
953962
let func_type = match func_type {
954963
Some(func_type) => func_type.handle,
@@ -957,9 +966,9 @@ pub trait BinaryViewExt: BinaryViewBase {
957966

958967
let handle = BNAddFunctionForAnalysis(
959968
self.as_ref().handle,
960-
plat.handle,
961-
addr,
962-
auto_discovered,
969+
platform.handle,
970+
address,
971+
true,
963972
func_type,
964973
);
965974

@@ -971,28 +980,85 @@ pub trait BinaryViewExt: BinaryViewBase {
971980
}
972981
}
973982

974-
fn add_entry_point(&self, plat: &Platform, addr: u64) {
983+
/// Remove an auto function from the view.
984+
///
985+
/// Pass `true` for `update_refs` to update all references of the function.
986+
///
987+
/// NOTE: Unlike [`BinaryViewExt::remove_user_function`], this will NOT prohibit the function from
988+
/// being re-added in the future, use [`BinaryViewExt::remove_user_function`] to blacklist the
989+
/// function from being automatically created.
990+
fn remove_auto_function(&self, func: &Function, update_refs: bool) {
975991
unsafe {
976-
BNAddEntryPointForAnalysis(self.as_ref().handle, plat.handle, addr);
992+
BNRemoveAnalysisFunction(self.as_ref().handle, func.handle, update_refs);
977993
}
978994
}
979995

980-
fn create_user_function(&self, plat: &Platform, addr: u64) -> Result<Ref<Function>> {
981-
unsafe {
982-
let func = BNCreateUserFunction(self.as_ref().handle, plat.handle, addr);
996+
/// Add a user function at the given `address` with the views default platform.
997+
///
998+
/// NOTE: The default platform **must** be set for this view!
999+
fn add_user_function(&self, addr: u64) -> Option<Ref<Function>> {
1000+
let platform = self.default_platform()?;
1001+
self.add_user_function_with_platform(addr, &platform)
1002+
}
9831003

1004+
/// Add an auto function at the given `address` with the `platform`.
1005+
///
1006+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
1007+
fn add_user_function_with_platform(
1008+
&self,
1009+
addr: u64,
1010+
platform: &Platform,
1011+
) -> Option<Ref<Function>> {
1012+
// If the view does not have a default platform, we must set it.
1013+
// The core expects there to be one before it can create a function.
1014+
if self.default_platform().is_none() {
1015+
self.set_default_platform(platform);
1016+
}
1017+
1018+
unsafe {
1019+
let func = BNCreateUserFunction(self.as_ref().handle, platform.handle, addr);
9841020
if func.is_null() {
985-
return Err(());
1021+
return None;
9861022
}
987-
988-
Ok(Function::ref_from_raw(func))
1023+
Some(Function::ref_from_raw(func))
9891024
}
9901025
}
9911026

1027+
/// Removes the function from the view and blacklists it from being created automatically.
1028+
///
1029+
/// NOTE: If you call [`BinaryViewExt::add_user_function`], it will override the blacklist.
1030+
fn remove_user_function(&self, func: &Function) {
1031+
unsafe { BNRemoveUserFunction(self.as_ref().handle, func.handle) }
1032+
}
1033+
9921034
fn has_functions(&self) -> bool {
9931035
unsafe { BNHasFunctions(self.as_ref().handle) }
9941036
}
9951037

1038+
/// Add an entry point at the given `address` with the view's default platform.
1039+
///
1040+
/// NOTE: The default platform **must** be set for this view!
1041+
fn add_entry_point(&self, addr: u64) {
1042+
if let Some(platform) = self.default_platform() {
1043+
self.add_entry_point_with_platform(addr, &platform);
1044+
}
1045+
}
1046+
1047+
/// Add an entry point at the given `address` with the `platform`.
1048+
///
1049+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
1050+
fn add_entry_point_with_platform(&self, addr: u64, platform: &Platform) {
1051+
// If the view does not have a default platform, we must set it.
1052+
// The core expects there to be one before it can create a function.
1053+
if self.default_platform().is_none() {
1054+
self.set_default_platform(platform);
1055+
}
1056+
1057+
unsafe {
1058+
BNAddEntryPointForAnalysis(self.as_ref().handle, platform.handle, addr);
1059+
}
1060+
}
1061+
9961062
fn entry_point_function(&self) -> Option<Ref<Function>> {
9971063
unsafe {
9981064
let raw_func_ptr = BNGetAnalysisEntryPoint(self.as_ref().handle);

rust/src/file_metadata.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,9 @@ impl FileMetadata {
222222
}
223223

224224
/// Get the [`BinaryView`] for the view type.
225-
///
225+
///
226226
/// # Example
227-
///
227+
///
228228
/// ```no_run
229229
/// use binaryninja::file_metadata::FileMetadata;
230230
/// # let file: FileMetadata = unimplemented!();

rust/tests/function.rs

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use binaryninja::binary_view::BinaryViewExt;
1+
use binaryninja::binary_view::{BinaryView, BinaryViewExt};
2+
use binaryninja::file_metadata::FileMetadata;
23
use binaryninja::headless::Session;
3-
use binaryninja::metadata::Metadata;
4-
use binaryninja::rc::Ref;
4+
use binaryninja::platform::Platform;
55
use std::path::PathBuf;
66

77
#[test]
@@ -15,7 +15,7 @@ fn store_and_query_function_metadata() {
1515

1616
// Store key/value pairs to user and auto metadata
1717
func.store_metadata("one", "one", false);
18-
func.store_metadata("two", 2 as u64, true);
18+
func.store_metadata("two", 2u64, true);
1919
func.store_metadata("three", "three", true);
2020
func.remove_metadata("three");
2121

@@ -35,8 +35,9 @@ fn store_and_query_function_metadata() {
3535
.unwrap(),
3636
2
3737
);
38-
assert!(
39-
func.query_metadata("three") == None,
38+
assert_eq!(
39+
func.query_metadata("three"),
40+
None,
4041
"Query for key \"three\" returned a value"
4142
);
4243

@@ -67,3 +68,59 @@ fn store_and_query_function_metadata() {
6768
);
6869
assert_eq!(auto_metadata.get("one"), Ok(None));
6970
}
71+
72+
#[test]
73+
fn add_function() {
74+
let _session = Session::new().expect("Failed to initialize session");
75+
let out_dir = env!("OUT_DIR").parse::<PathBuf>().unwrap();
76+
let view = binaryninja::load(out_dir.join("atox.obj")).expect("Failed to create view");
77+
let mut func = view
78+
.entry_point_function()
79+
.expect("Failed to get entry point function");
80+
81+
// Remove the function then as an auto function then add as auto function.
82+
// This tests to make sure that the function is not blacklisted from being added back.
83+
view.remove_auto_function(&func, false);
84+
85+
assert_eq!(
86+
view.functions_at(func.start()).len(),
87+
0,
88+
"Function was not removed"
89+
);
90+
func = view
91+
.add_auto_function(func.start())
92+
.expect("Failed to add function");
93+
assert_eq!(
94+
view.functions_at(func.start()).len(),
95+
1,
96+
"Function was not added back"
97+
);
98+
99+
// Use the user version of remove to blacklist the function, auto function should be prohibited.
100+
view.remove_user_function(&func);
101+
assert_eq!(
102+
view.add_auto_function(func.start()),
103+
None,
104+
"Function was not blacklisted"
105+
);
106+
107+
// Adding back as a user should override the blacklist.
108+
func = view
109+
.add_user_function(func.start())
110+
.expect("Failed to add function as user");
111+
assert_eq!(
112+
view.functions_at(func.start()).len(),
113+
1,
114+
"Function was not added back"
115+
);
116+
117+
// Make sure you cannot add a function without a default platform.
118+
let code = &[0xa1, 0xfa, 0xf8, 0xf0, 0x99, 0x83, 0xc0, 0x37, 0xc3];
119+
let view = BinaryView::from_data(&FileMetadata::new(), code).expect("Failed to create view");
120+
assert!(view.add_user_function(0).is_none());
121+
assert!(view.add_auto_function(0).is_none());
122+
123+
// Now set it to verify we can add it.
124+
let platform = Platform::by_name("x86").expect("Failed to get platform");
125+
assert!(view.add_user_function_with_platform(0, &platform).is_some());
126+
}

0 commit comments

Comments
 (0)