Skip to content

Commit 1cf02d9

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 1cf02d9

File tree

4 files changed

+145
-38
lines changed

4 files changed

+145
-38
lines changed

python/binaryview.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4846,6 +4846,8 @@ def create_user_function(self, addr: int, plat: Optional['_platform.Platform'] =
48464846
if self.platform is None:
48474847
raise Exception("Attempting to call create_user_function with no specified platform")
48484848
plat = self.platform
4849+
if self.platform is None:
4850+
self.platform = plat
48494851
func = core.BNCreateUserFunction(self.handle, plat.handle, addr)
48504852
if func is None:
48514853
return None

rust/src/binary_view.rs

Lines changed: 78 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -924,29 +924,32 @@ 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>> {
952955
unsafe {
@@ -957,9 +960,9 @@ pub trait BinaryViewExt: BinaryViewBase {
957960

958961
let handle = BNAddFunctionForAnalysis(
959962
self.as_ref().handle,
960-
plat.handle,
961-
addr,
962-
auto_discovered,
963+
platform.handle,
964+
address,
965+
true,
963966
func_type,
964967
);
965968

@@ -971,28 +974,73 @@ pub trait BinaryViewExt: BinaryViewBase {
971974
}
972975
}
973976

974-
fn add_entry_point(&self, plat: &Platform, addr: u64) {
977+
/// Remove an auto function from the view.
978+
///
979+
/// Pass `true` for `update_refs` to update all references of the function.
980+
///
981+
/// NOTE: Unlike [`BinaryViewExt::remove_user_function`], this will NOT prohibit the function from
982+
/// being re-added in the future, use [`BinaryViewExt::remove_user_function`] to blacklist the
983+
/// function from being automatically created.
984+
fn remove_auto_function(&self, func: &Function, update_refs: bool) {
975985
unsafe {
976-
BNAddEntryPointForAnalysis(self.as_ref().handle, plat.handle, addr);
986+
BNRemoveAnalysisFunction(self.as_ref().handle, func.handle, update_refs);
977987
}
978988
}
979989

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);
990+
/// Add a user function at the given `address` with the views default platform.
991+
///
992+
/// NOTE: The default platform **must** be set for this view!
993+
fn add_user_function(&self, addr: u64) -> Option<Ref<Function>> {
994+
let platform = self.default_platform()?;
995+
self.add_user_function_with_platform(addr, &platform)
996+
}
983997

998+
/// Add an auto function at the given `address` with the `platform`.
999+
///
1000+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
1001+
fn add_user_function_with_platform(
1002+
&self,
1003+
addr: u64,
1004+
platform: &Platform,
1005+
) -> Option<Ref<Function>> {
1006+
unsafe {
1007+
let func = BNCreateUserFunction(self.as_ref().handle, platform.handle, addr);
9841008
if func.is_null() {
985-
return Err(());
1009+
return None;
9861010
}
987-
988-
Ok(Function::ref_from_raw(func))
1011+
Some(Function::ref_from_raw(func))
9891012
}
9901013
}
9911014

1015+
/// Removes the function from the view and blacklists it from being created automatically.
1016+
///
1017+
/// NOTE: If you call [`BinaryViewExt::add_user_function`], it will override the blacklist.
1018+
fn remove_user_function(&self, func: &Function) {
1019+
unsafe { BNRemoveUserFunction(self.as_ref().handle, func.handle) }
1020+
}
1021+
9921022
fn has_functions(&self) -> bool {
9931023
unsafe { BNHasFunctions(self.as_ref().handle) }
9941024
}
9951025

1026+
/// Add an entry point at the given `address` with the view's default platform.
1027+
///
1028+
/// NOTE: The default platform **must** be set for this view!
1029+
fn add_entry_point(&self, addr: u64) {
1030+
if let Some(platform) = self.default_platform() {
1031+
self.add_entry_point_with_platform(addr, &platform);
1032+
}
1033+
}
1034+
1035+
/// Add an entry point at the given `address` with the `platform`.
1036+
///
1037+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
1038+
fn add_entry_point_with_platform(&self, addr: u64, platform: &Platform) {
1039+
unsafe {
1040+
BNAddEntryPointForAnalysis(self.as_ref().handle, platform.handle, addr);
1041+
}
1042+
}
1043+
9961044
fn entry_point_function(&self) -> Option<Ref<Function>> {
9971045
unsafe {
9981046
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)