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