Skip to content

YARA rules

ClamAV loads .yar/.yara rules by default, and so does exav: rule files load alongside ClamAV signatures and match in the same scan.

Put rule files in your signature directory; they load recursively with everything else:

Terminal window
exav -d ./sigs /data # sigs/ contains .cvd, .ndb, and .yar files

A YARA detection is reported like any other:

Terminal window
sample.bin: YARA.SomeRuleName FOUND

Under --clamav-compat, YARA detections carry the .UNOFFICIAL suffix (YARA.SomeRuleName.UNOFFICIAL), as clamscan names them: the official .cvd files ship no YARA rules.

YARA support is behind the default-on yara feature. A build without it still loads rule files but warns that they will never match. --no-default-features drops every other default feature too; see Feature flags.

exav uses YARA-X’s parser crate (yara-x-parser) and replaces its WASM back end with a native tree-walking evaluator:

  • No wasmtime, no Cranelift, no rsa, and no code generation at scan time. Depending on yara-x as a library pulls in a large WebAssembly runtime for its back end; the native engine links none of it.
  • YARA-X is BSD-3-Clause, compatible with exav’s MIT license, and exav reuses and adapts its source and test vectors under it, with attribution. (exav derives nothing from ClamAV’s code, which is GPL.)

Supported: text, hex and regexp strings with all modifiers (nocase, ascii, wide, fullword, xor, base64, base64wide, private); full condition logic (boolean, of, counts, offsets, lengths, anchors, arithmetic, bitwise, float, comparisons, string operators, matches); for … in, for … of, with; integer reads (uint/int 8/16/32 and _be); filesize; entrypoint; rule references; global and private rules; and the pe, math, hash, string, time, elf and dotnet modules.

External variables: filepath, filename and extension (lowercased, with its leading dot) are set from the scanned file’s path, and undefined when there is none. filetype and owner are declared, so rules using them compile, but are never set, so those conditions never match.

Not supported, and rejected as explicit compile errors rather than evaluated wrongly: the macho, dex, cuckoo, androguard and other modules; include; floatN() reads; a bare regular expression used as a condition; and a few fields of the implemented modules (pe.rich_signature, pe.version_info, resources, pe.signatures, dotnet.classes).

A file larger than --max-object-bytes is scanned through a block cache, and rules that use the pe, elf or dotnet modules cannot run on it: the file is reported LIMITS-EXCEEDED unless something is found. The same verdict comes from a pattern with more than a million matches and from a rule set that runs out of evaluation steps. See Limits and tuning.

Matching is cross-checked against the real yara-x over varied inputs, comparing the set of matching rules (see Differential testing). The harness runs yara-x as a program (yr) rather than linking it, which would bring its WebAssembly runtime into exav’s build. Install it with cargo install yara-x-cli and run make test-yara-diff; without it the harness skips, so read its output rather than only its exit code.

The engine is exav_core::yara, usable as a standalone YARA library:

use exav_core::yara::{Compiler, Scanner as YaraScanner};
fn demo() -> exav_core::yara::Result<bool> {
let mut c = Compiler::new();
c.add_source(r#"rule demo { strings: $a = "evil" condition: $a }"#)?;
let rules = c.build();
let mut scanner = YaraScanner::new(&rules);
let hit = scanner.scan(b"...evil...")?.matching_rules().next().is_some();
Ok(hit)
}

add_source fails on the first unsupported rule. add_source_lenient compiles each rule on its own and returns the rejected ones, as a scan’s database load does. See exav-core for the rest of the library’s API.