summaryrefslogtreecommitdiff
path: root/plugins/warp/src/plugin/create.rs
blob: 966c69caf746991306207e7d7f9642fd123c46c2 (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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use crate::cache::cached_function;
use crate::convert::from_bn_type;
use crate::matcher::invalidate_function_matcher_cache;
use binaryninja::binaryview::{BinaryView, BinaryViewExt};
use binaryninja::command::Command;
use rayon::prelude::*;
use std::io::Write;
use std::thread;
use std::time::Instant;
use warp::r#type::ComputedType;

pub struct CreateSignatureFile;

// TODO: Prompt the user to add the newly created signature file to the signature blacklist (so that it doesn't keep getting applied)

impl Command for CreateSignatureFile {
    fn action(&self, view: &BinaryView) {
        let mut signature_dir = binaryninja::user_directory().unwrap().join("signatures/");
        if let Some(default_plat) = view.default_platform() {
            // If there is a default platform, put the signature in there.
            signature_dir.push(default_plat.name().to_string());
        }
        let view = view.to_owned();
        thread::spawn(move || {
            let background_task = binaryninja::backgroundtask::BackgroundTask::new(
                format!("Generating {} signatures... ", view.functions().len()),
                true,
            )
            .unwrap();

            let start = Instant::now();

            let mut data = warp::signature::Data::default();
            data.functions
                .par_extend(view.functions().par_iter().filter_map(|func| {
                    let llil = func.low_level_il().ok()?;
                    Some(cached_function(&func, &llil))
                }));
            data.types.extend(view.types().iter().map(|ty| {
                let ref_ty = ty.type_object().to_owned();
                ComputedType::new(from_bn_type(&view, ref_ty, u8::MAX))
            }));

            // And type generation :3
            log::info!("Signature generation took {:?}", start.elapsed());

            if let Some(sig_file_name) = binaryninja::interaction::get_text_line_input(
                "Signature File",
                "Create Signature File",
            ) {
                let save_file = signature_dir.join(sig_file_name + ".sbin");
                log::info!("Saving to signatures to {:?}...", &save_file);
                // TODO: Should we overwrite? Prompt user.
                if let Ok(mut file) = std::fs::File::create(&save_file) {
                    match file.write_all(&data.to_bytes()) {
                        Ok(_) => {
                            log::info!("Signature file saved successfully.");
                            // Force rebuild platform matcher.
                            invalidate_function_matcher_cache();
                        }
                        Err(e) => log::error!("Failed to write data to signature file: {:?}", e),
                    }
                } else {
                    log::error!("Could not create signature file: {:?}", save_file);
                }
            }

            background_task.finish();
        });
    }

    fn valid(&self, _view: &BinaryView) -> bool {
        true
    }
}