Anatomy of a rule
YARA-X is a Rust reimplementation of YARA — the pattern-matching tool widely used to identify and classify malware. YARA-X keeps the YARA rule language largely intact while aiming to be faster, safer, and more user-friendly than its predecessor. Its command-line tool is called yr.
A rule is the basic unit of work. Every rule describes a set of patterns and a boolean condition that decides whether a piece of data — a file, a process, or a buffer — matches. This page walks through the shape of a rule from top to bottom.
This page documents the rule structure. The full catalog of pattern modifiers, condition operators, and modules lives in the rest of this knowledge base; links to the upstream reference are in Sources.
The skeleton
At minimum a rule needs a name and a condition. Everything else is optional.
rule example {
condition:
false
}
That rule is valid: it has the rule keyword, an identifier (example), and a condition section. It simply never matches.
A more typical rule fills in two more sections — meta and strings — giving the canonical four-part shape:
rule <name> [: <tags>] {
meta:
// identifier = value pairs (optional)
strings:
// pattern declarations (optional)
condition:
// boolean expression (required)
}
| Part | Keyword | Required? | Purpose |
|---|---|---|---|
| Name | rule + identifier | Yes | Unique identifier for the rule |
| Tags | : Foo Bar | No | Labels for filtering and grouping |
| Metadata | meta: | No | Descriptive key/value pairs (not used in matching) |
| Patterns | strings: | No | Text, hex, and regex patterns to search for |
| Condition | condition: | Yes | Boolean expression that decides a match |
Rule name and tags
A rule starts with the rule keyword followed by an identifier. Identifiers may contain alphanumeric characters and underscores, are case-sensitive, and cannot start with a digit.
You can attach any number of tags after the identifier, introduced by a colon and separated from one another by whitespace. Tags follow the same naming rules as identifiers (alphanumeric and underscores, case-sensitive, no leading digit). They are used to filter which rules apply or to label matches — they do not affect whether a rule matches.
rule TagsExample1 : Foo Bar Baz {
condition:
true
}
rule TagsExample2 : Bar {
condition:
true
}
Tags are handy when you maintain large rule sets. For example, you can tag rules by malware family or platform and then ask yr to report only the tags you care about at scan time.
The meta section
The meta section holds identifier/value pairs that document the rule. Each metadata identifier is followed by an equals sign and a value. Values can be strings, integers, or the booleans true / false.
rule meta_example {
meta:
author = "Jane Doe"
description = "Detects the silent_banker dropper"
threat_level = 3
in_the_wild = true
condition:
true
}
Metadata is purely informational — it is never evaluated as part of the condition. It travels with the rule and shows up in scan output, which makes it useful for attribution, references, and triage notes.
The strings section
The strings section declares the patterns YARA-X searches for. Each pattern has an identifier that starts with $. YARA-X supports three kinds of patterns:
| Pattern type | Example | Notes |
|---|---|---|
| Text | $text = "text here" | A literal sequence of characters |
| Hex | $hex = { E2 34 A1 C8 23 FB } | Raw bytes, written in hexadecimal |
| Regular expression | $regex = /some regular expression: \w+/ | A regex, delimited by / |
rule ExampleRule {
strings:
$text = "text here"
$hex = { E2 34 A1 C8 23 FB }
$regex = /some regular expression: \w+/
condition:
$text or $hex or $regex
}
Text patterns accept modifiers that change how matching works. A few common ones:
| Modifier | Effect |
|---|---|
nocase | Case-insensitive matching |
wide | Match strings encoded with two bytes per character |
ascii | Match the plain ASCII form (often paired with wide) |
fullword | Match only when delimited by non-alphanumeric characters |
xor | Match the pattern XOR-ed with single bytes, e.g. xor(0x01-0xff) |
base64 | Match base64-encoded forms of the pattern |
private | Hide the pattern from scan output |
Modifiers are appended after the pattern, for example $a = "Borland" wide ascii. Note that some combinations are rejected by the compiler — base64 and base64wide cannot be combined with xor, fullword, or nocase.
The condition section
The condition section is the only required body section. It contains a boolean expression that, when true, marks the data as a match. Conditions typically reference the pattern identifiers from the strings section and combine them with operators such as and, or, and not.
rule condition_example {
strings:
$a = "malicious"
$b = "payload"
condition:
$a and $b
}
Conditions can express much more than simple presence — counts, offsets, file size, and module-provided data — but the building block is always a boolean expression. See the upstream reference linked below for the complete operator set.
A complete annotated example
The example below is the rule shipped in the YARA-X README. It demonstrates every section working together.
rule silent_banker : banker {
meta:
description = "This is just an example"
threat_level = 3
in_the_wild = true
strings:
$a = {6A 40 68 00 30 00 00 6A 14 8D 91}
$b = {8D 4D B0 2B C1 83 C0 27 99 6A 4E 59 F7 F9}
$c = "UVODFRYSIHLNWPEJXQZAKCBGMT"
condition:
$a or $b or $c
}
Reading it top to bottom:
rule silent_banker : banker— the rule is namedsilent_bankerand carries the tagbanker.meta:— three informational pairs: adescriptionstring, athreat_levelinteger, and anin_the_wildboolean. None of these affect matching.strings:— two hex patterns ($a,$b) describing byte sequences, plus one text pattern ($c).condition:— the file matches if any one of the three patterns is found.
Scanning with a rule
Once a rule is saved to a file (conventionally .yar or .yara), scan a target with the yr CLI:
yr scan my_rules.yar /path/to/target_file
The general form of the scan command is:
yr scan [OPTIONS] <[NAMESPACE:]RULES_PATH>... <TARGET_PATH>
RULES_PATH can be a single rule file or a directory; when it is a directory, YARA-X recursively collects every *.yar and *.yara file it finds.
The silent_banker rule above and the small snippets in this page are illustrative — the hex byte sequences are taken from the upstream documentation and are not tied to any specific real-world sample. Use them to learn the structure, not as production detection logic.