Skip to content

Commit 607ca37

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 255d616 commit 607ca37

File tree

2 files changed

+147
-36
lines changed

2 files changed

+147
-36
lines changed

rust/src/binary_view.rs

Lines changed: 84 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -947,29 +947,36 @@ pub trait BinaryViewExt: BinaryViewBase {
947947
MemoryMap::new(self.as_ref().to_owned())
948948
}
949949

950-
fn add_auto_function(&self, plat: &Platform, addr: u64) -> Option<Ref<Function>> {
951-
unsafe {
952-
let handle = BNAddFunctionForAnalysis(
953-
self.as_ref().handle,
954-
plat.handle,
955-
addr,
956-
false,
957-
std::ptr::null_mut(),
958-
);
959-
960-
if handle.is_null() {
961-
return None;
962-
}
950+
/// Add an auto function at the given `address` with the views default platform.
951+
///
952+
/// Use [`BinaryViewExt::add_auto_function_with_platform`] if you wish to specify a platform.
953+
///
954+
/// NOTE: The default platform **must** be set for this view!
955+
fn add_auto_function(&self, address: u64) -> Option<Ref<Function>> {
956+
let platform = self.default_platform()?;
957+
self.add_auto_function_with_platform(address, &platform)
958+
}
963959

964-
Some(Function::ref_from_raw(handle))
965-
}
960+
/// Add an auto function at the given `address` with the `platform`.
961+
///
962+
/// Use [`BinaryViewExt::add_auto_function_ext`] if you wish to specify a function type.
963+
///
964+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
965+
fn add_auto_function_with_platform(
966+
&self,
967+
address: u64,
968+
platform: &Platform,
969+
) -> Option<Ref<Function>> {
970+
self.add_auto_function_ext(address, platform, None)
966971
}
967972

968-
fn add_function_with_type(
973+
/// Add an auto function at the given `address` with the `platform` and function type.
974+
///
975+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
976+
fn add_auto_function_ext(
969977
&self,
970-
plat: &Platform,
971-
addr: u64,
972-
auto_discovered: bool,
978+
address: u64,
979+
platform: &Platform,
973980
func_type: Option<&Type>,
974981
) -> Option<Ref<Function>> {
975982
unsafe {
@@ -980,9 +987,9 @@ pub trait BinaryViewExt: BinaryViewBase {
980987

981988
let handle = BNAddFunctionForAnalysis(
982989
self.as_ref().handle,
983-
plat.handle,
984-
addr,
985-
auto_discovered,
990+
platform.handle,
991+
address,
992+
true,
986993
func_type,
987994
);
988995

@@ -994,28 +1001,75 @@ pub trait BinaryViewExt: BinaryViewBase {
9941001
}
9951002
}
9961003

997-
fn add_entry_point(&self, plat: &Platform, addr: u64) {
1004+
/// Remove an auto function from the view.
1005+
///
1006+
/// Pass `true` for `update_refs` to update all references of the function.
1007+
///
1008+
/// NOTE: Unlike [`BinaryViewExt::remove_user_function`], this will NOT prohibit the function from
1009+
/// being re-added in the future, use [`BinaryViewExt::remove_user_function`] to blacklist the
1010+
/// function from being automatically created.
1011+
fn remove_auto_function(&self, func: &Function, update_refs: bool) {
9981012
unsafe {
999-
BNAddEntryPointForAnalysis(self.as_ref().handle, plat.handle, addr);
1013+
BNRemoveAnalysisFunction(self.as_ref().handle, func.handle, update_refs);
10001014
}
10011015
}
10021016

1003-
fn create_user_function(&self, plat: &Platform, addr: u64) -> Result<Ref<Function>> {
1004-
unsafe {
1005-
let func = BNCreateUserFunction(self.as_ref().handle, plat.handle, addr);
1017+
/// Add a user function at the given `address` with the views default platform.
1018+
///
1019+
/// Use [`BinaryViewExt::add_user_function_with_platform`] if you wish to specify a platform.
1020+
///
1021+
/// NOTE: The default platform **must** be set for this view!
1022+
fn add_user_function(&self, addr: u64) -> Option<Ref<Function>> {
1023+
let platform = self.default_platform()?;
1024+
self.add_user_function_with_platform(addr, &platform)
1025+
}
10061026

1027+
/// Add an auto function at the given `address` with the `platform`.
1028+
///
1029+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
1030+
fn add_user_function_with_platform(
1031+
&self,
1032+
addr: u64,
1033+
platform: &Platform,
1034+
) -> Option<Ref<Function>> {
1035+
unsafe {
1036+
let func = BNCreateUserFunction(self.as_ref().handle, platform.handle, addr);
10071037
if func.is_null() {
1008-
return Err(());
1038+
return None;
10091039
}
1010-
1011-
Ok(Function::ref_from_raw(func))
1040+
Some(Function::ref_from_raw(func))
10121041
}
10131042
}
10141043

1044+
/// Removes the function from the view and blacklists it from being created automatically.
1045+
///
1046+
/// NOTE: If you call [`BinaryViewExt::add_user_function`], it will override the blacklist.
1047+
fn remove_user_function(&self, func: &Function) {
1048+
unsafe { BNRemoveUserFunction(self.as_ref().handle, func.handle) }
1049+
}
1050+
10151051
fn has_functions(&self) -> bool {
10161052
unsafe { BNHasFunctions(self.as_ref().handle) }
10171053
}
10181054

1055+
/// Add an entry point at the given `address` with the view's default platform.
1056+
///
1057+
/// NOTE: The default platform **must** be set for this view!
1058+
fn add_entry_point(&self, addr: u64) {
1059+
if let Some(platform) = self.default_platform() {
1060+
self.add_entry_point_with_platform(addr, &platform);
1061+
}
1062+
}
1063+
1064+
/// Add an entry point at the given `address` with the `platform`.
1065+
///
1066+
/// NOTE: If the view's default platform is not set, this will set it to `platform`.
1067+
fn add_entry_point_with_platform(&self, addr: u64, platform: &Platform) {
1068+
unsafe {
1069+
BNAddEntryPointForAnalysis(self.as_ref().handle, platform.handle, addr);
1070+
}
1071+
}
1072+
10191073
fn entry_point_function(&self) -> Option<Ref<Function>> {
10201074
unsafe {
10211075
let raw_func_ptr = BNGetAnalysisEntryPoint(self.as_ref().handle);

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)