summaryrefslogtreecommitdiff
path: root/plugins/warp/src/plugin/project.rs
blob: ea5a56008519d657d631a6f386fe10ffe3507fd7 (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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use binaryninja::background_task::BackgroundTask;
use binaryninja::command::ProjectCommand;
use binaryninja::interaction::{Form, FormInputField};
use binaryninja::project::Project;
use binaryninja::rc::Ref;
use regex::Regex;
use std::thread;
use std::time::Instant;

use crate::processor::{
    new_processing_state_background_thread, FileDataKindField, FileFilterField, WarpFileProcessor,
};
use crate::report::{ReportGenerator, ReportKindField};

pub struct CreateSignaturesForm {
    form: Form,
}

impl CreateSignaturesForm {
    pub fn new(_project: &Project) -> CreateSignaturesForm {
        let mut form = Form::new("Create Signature File");
        form.add_field(Self::file_data_field());
        form.add_field(Self::file_filter_field());
        form.add_field(Self::generated_report_field());
        // TODO: Threads (we run the analysis in the background)
        Self { form }
    }

    pub fn file_data_field() -> FormInputField {
        FileDataKindField::default().to_field()
    }

    pub fn file_data_kind(&self) -> FileDataKindField {
        FileDataKindField::from_form(&self.form).unwrap_or_default()
    }

    pub fn file_filter_field() -> FormInputField {
        FileFilterField::to_field()
    }

    pub fn file_filter(&self) -> Option<Regex> {
        FileFilterField::from_form(&self.form)
    }

    pub fn generated_report_field() -> FormInputField {
        ReportKindField::default().to_field()
    }

    pub fn generated_report_kind(&self) -> ReportKindField {
        ReportKindField::from_form(&self.form).unwrap_or_default()
    }

    pub fn prompt(&mut self) -> bool {
        self.form.prompt()
    }
}

pub struct CreateSignatures;

impl CreateSignatures {
    pub fn execute(project: Ref<Project>) {
        let mut form = CreateSignaturesForm::new(&project);
        if !form.prompt() {
            return;
        }
        let file_data_kind = form.file_data_kind();
        let report_kind = form.generated_report_kind();

        let mut processor = WarpFileProcessor::new().with_file_data(file_data_kind);

        // This thread will show the state in a background task.
        let background_task = BackgroundTask::new("Processing started...", true);
        new_processing_state_background_thread(background_task.clone(), processor.state());

        if let Some(filter) = form.file_filter() {
            processor = processor.with_file_filter(filter);
        }

        let start = Instant::now();
        match processor.process_project(&project) {
            Ok(warp_file) => {
                // Print the processor string into the description of the file, so we know how it was generated.
                let processor_str = format!("{:#?}", &processor);

                // TODO: File name needs to be configurable.
                if project
                    .create_file(
                        &warp_file.to_bytes(),
                        None,
                        "generated.warp",
                        &processor_str,
                    )
                    .is_err()
                {
                    log::error!("Failed to create project file!");
                }

                let report = ReportGenerator::new();
                if let Some(generated) = report.report(&report_kind, &warp_file) {
                    let ext = report.report_extension(&report_kind).unwrap_or_default();
                    let file_name = format!("report.{}", ext);
                    if project
                        .create_file(&generated.into_bytes(), None, &file_name, "Warp file")
                        .is_err()
                    {
                        log::error!("Failed to create project file!");
                    }
                }
            }
            Err(e) => {
                log::error!("Failed to process project: {}", e);
            }
        }
        log::info!("Processing project files took: {:?}", start.elapsed());

        // Tells the processing state thread to finish.
        background_task.finish();
    }
}

impl ProjectCommand for CreateSignatures {
    fn action(&self, project: &Project) {
        let project = project.to_owned();
        thread::spawn(move || {
            CreateSignatures::execute(project);
        });
    }

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