1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
use crate::matcher::{Matcher, PlatformID, PLAT_MATCHER_CACHE};
use binaryninja::binary_view::{BinaryView, BinaryViewExt};
use binaryninja::command::Command;
pub struct LoadSignatureFile;
impl Command for LoadSignatureFile {
fn action(&self, view: &BinaryView) {
let Some(platform) = view.default_platform() else {
log::error!("Default platform must be set to load signature!");
return;
};
// NOTE: Because we only can consume signatures from a specific directory, we don't need to use the interaction API.
// If we did need to load signature files from a project than this would need to change.
let Some(file) = rfd::FileDialog::new()
.add_filter("Signature Files", &["sbin"])
.set_file_name(format!("{}.sbin", view.file().filename()))
.pick_file()
else {
return;
};
let Ok(data) = std::fs::read(&file) else {
log::error!("Could not read signature file: {:?}", file);
return;
};
let Some(data) = warp::signature::Data::from_bytes(&data) else {
log::error!("Could not get data from signature file: {:?}", file);
return;
};
let new_matcher = Matcher::from_data(data);
log::info!(
"Loading signature file with {} functions and {} types...",
new_matcher.functions.len(),
new_matcher.types.len()
);
let platform_id = PlatformID::from(platform.as_ref());
let matcher_cache = PLAT_MATCHER_CACHE.get_or_init(Default::default);
match matcher_cache.get_mut(&platform_id) {
Some(mut matcher) => matcher.extend_with_matcher(new_matcher),
None => {
// We still must uphold `from_platform` in case we are running this before the matcher workflow
// is kicked off. Other-wise we only will have the `new_matcher` data.
let mut matcher = Matcher::from_platform(platform);
matcher.extend_with_matcher(new_matcher);
matcher_cache.insert(platform_id, matcher);
}
}
}
fn valid(&self, _view: &BinaryView) -> bool {
true
}
}
|