A dense reference for writing rules. Every complete rule below compiles with YARA-X; test your own in the editor.
Rule skeleton
import "pe"
rule PREFIX_Family_Detail : tag1 tag2
{
meta:
description = "What this rule detects"
author = "you"
date = "2026-09-29"
reference = "https://example.org/report"
strings:
$x1 = "very specific string" ascii wide
$s1 = { 8B 45 ?? 33 C9 [2-4] E8 }
$s2 = /config_[a-f0-9]{8}/
condition:
uint16(0) == 0x5A4D and filesize < 5MB and
(1 of ($x*) or all of ($s*)) and
pe.number_of_sections > 2
}
Only condition is mandatory. Order: meta, strings, condition. Modifiers: private rule (not reported, usable by other rules), global rule (must be true for any rule in the namespace to match).
Strings
| Type | Syntax | Example |
|---|
| Text | "…" | $a = "cmd.exe /c" |
| Hex | { … } | $h = { 4D 5A ?? 00 } |
| Regex | /…/is | $r = /evil[0-9]{2}\.exe/ |
Text escapes: \" \\ \t \n \r \xNN.
Modifiers
| Modifier | Text | Hex | Regex | Meaning |
|---|
ascii | yes | – | yes | Plain bytes (default) |
wide | yes | – | yes | UTF-16LE |
nocase | yes | – | yes | Case-insensitive |
fullword | yes | – | yes | Delimited by non-alphanumerics |
xor / xor(a-b) | yes | – | – | Single-byte XOR keys |
base64 / base64wide | yes | – | – | Inside base64 data |
private | yes | yes | yes | Not shown in output |
Hex syntax
| Syntax | Meaning |
|---|
?? | Any byte |
A? / ?A | Nibble wildcard |
[4] / [2-6] / [8-] | Jumps |
( 01 02 | 03 ) | Alternatives |
~00 | Any byte except 00 |
Condition operators
| Category | Operators |
|---|
| Boolean | and or not |
| Comparison | == != < <= > >= |
| Arithmetic | + - * \ (integer division) % |
| Bitwise | & | ^ ~ << >> |
| Strings (module values) | contains icontains startswith istartswith endswith iendswith iequals matches |
| Patterns | $a #a @a[i] !a[i] $a at N $a in (A..B) |
| File | filesize uint8/16/32(off) int8/16/32(off) + be variants |
| Defined | defined expr |
Quantifiers and loops
| Expression | Meaning |
|---|
any of them / all of them / none of them | Over all patterns |
2 of ($s*) / 50% of them | Count or percentage |
any of ($a, $b) | Explicit set |
for any i in (1..#a) : ( @a[i] < 100 ) | Loop over matches |
for all of ($x*) : ( # > 2 ) | Loop over patterns ($, #, @ = current) |
for any s in pe.sections : ( s.name == ".text" ) | Loop over module arrays |
with x = uint32(0x3C) : ( … ) | Local variable (YARA-X only) |
Magic bytes
| Format | Check |
|---|
| PE (MZ) | uint16(0) == 0x5A4D |
| ELF | uint32(0) == 0x464C457F |
| Mach-O 64 | uint32(0) == 0xFEEDFACF |
PDF %PDF | uint32(0) == 0x46445025 |
ZIP / OOXML PK\x03\x04 | uint32(0) == 0x04034B50 |
OLE D0 CF 11 E0 | uint32(0) == 0xE011CFD0 |
| Gzip | uint16(0) == 0x8B1F |
Shebang #! | uint16(0) == 0x2123 |
Module snippets
import "pe"
import "math"
import "hash"
rule Module_Snippets
{
condition:
pe.is_pe and (
pe.imports("kernel32.dll", "VirtualAlloc") or
pe.exports("DllRegisterServer") or
pe.imphash() == "00000000000000000000000000000000" or
math.entropy(0, 4096) > 7.0 or
hash.md5(0, 64) == "00000000000000000000000000000000"
)
}
YARA-X command line
| Command | Purpose |
|---|
yr scan rules.yar target | Scan a file or directory |
yr scan -s rules.yar target | Also print matched patterns |
yr check rules.yar | Compile and report errors/warnings |
yr fmt rules.yar | Format rules |
yr compile rules.yar -o rules.yarc | Save compiled rules |
yr dump -m pe file.exe | Show what a module extracts |
| Do | Don't |
|---|
| 4+ consecutive fixed bytes per pattern | Strings shorter than 4 bytes |
Magic bytes and filesize first | Module calls before cheap guards |
| Wildcard only varying operands | Hex made of ?? and 00 |
| Literal anchors in regexes | Leading .*, unbounded + |
Loop over 1..#a | Loop over 0..filesize |
nocase/xor on long strings | xor/base64 on short strings |
For explanations, read the guides on syntax, strings, conditions, modules and performance; check a rule with the linter.