Skip to main content

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.

note

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)
}
PartKeywordRequired?Purpose
Namerule + identifierYesUnique identifier for the rule
Tags: Foo BarNoLabels for filtering and grouping
Metadatameta:NoDescriptive key/value pairs (not used in matching)
Patternsstrings:NoText, hex, and regex patterns to search for
Conditioncondition:YesBoolean 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
}
tip

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
}
info

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 typeExampleNotes
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:

ModifierEffect
nocaseCase-insensitive matching
wideMatch strings encoded with two bytes per character
asciiMatch the plain ASCII form (often paired with wide)
fullwordMatch only when delimited by non-alphanumeric characters
xorMatch the pattern XOR-ed with single bytes, e.g. xor(0x01-0xff)
base64Match base64-encoded forms of the pattern
privateHide 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 named silent_banker and carries the tag banker.
  • meta: — three informational pairs: a description string, a threat_level integer, and an in_the_wild boolean. 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.

Illustrative example

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.

Sources