Skip to main content

malwaredb_server/
yara.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use malwaredb_api::YaraSearchRequest;
4
5use tracing::error;
6use uuid::Uuid;
7use yara_x::errors::CompileError;
8use yara_x::{Compiler, Rules};
9
10pub(crate) const MAX_YARA_PROCESSES: usize = 4;
11
12/// Yara task information to find matching files
13pub struct YaraTask {
14    /// Identifier of the Yara search task
15    pub id: Uuid,
16
17    /// Original Yara rules
18    pub yara_string: String,
19
20    /// Compiled Yara rules
21    pub yara_bytes: Vec<u8>,
22
23    /// Last file ID if on a further pagination search.
24    pub last_file_id: Option<u64>,
25
26    /// User ID associated with the Yara task
27    pub user_id: u32,
28}
29
30impl YaraTask {
31    pub(crate) fn process_yara_rules(&self, sample: &[u8]) -> anyhow::Result<Vec<String>> {
32        // TODO: Put this deserialization and `Scanner` creation somewhere else.
33        let rules = Rules::deserialize(&self.yara_bytes)?;
34        let mut scanner = yara_x::Scanner::new(&rules);
35        let mut results = Vec::new();
36        match scanner.scan(sample) {
37            Ok(matches) => {
38                for rule in matches.matching_rules() {
39                    results.push(String::from(rule.identifier()));
40                }
41            }
42            Err(e) => {
43                error!("Error scanning sample: {e}");
44            }
45        }
46
47        Ok(results)
48    }
49}
50
51pub(crate) fn compile_yara_rules(request: YaraSearchRequest) -> Result<Rules, CompileError> {
52    let mut compiler = Compiler::new();
53
54    for rule in request.rules {
55        compiler.add_source(&*rule)?;
56    }
57
58    Ok(compiler.build())
59}