summaryrefslogtreecommitdiff
path: root/plugins/warp/src/plugin/load.rs
blob: c86a16cb7e9c378ec0a214a9e26cae090c587e1e (plain)
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
    }
}