YARA strings: text, hex and regex patterns
How to write YARA strings: text strings and escapes, modifiers like nocase, wide, xor and base64, hex strings with wildcards and jumps, and regular expressions.
Patterns — YARA calls them strings, even when they are bytes or regular expressions — are what YARA searches for before it evaluates the condition. Choosing them well decides both how precise a rule is and how fast it runs. This guide covers the three pattern types and their modifiers.
Text strings
A text string is written in double quotes and matched byte for byte:
rule Text_Strings
{
strings:
$a = "Global\\MyMutex_2024"
$b = "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0)"
$c = "tab\there and a quote \" inside"
$d = "\x4D\x5A with raw bytes"
condition:
any of them
}
Supported escapes are \", \\, \t, \n, \r and \xNN for an arbitrary byte. YARA-X rejects unknown escape sequences instead of silently ignoring them — a common source of errors when porting old rules (see YARA-X vs YARA).
String modifiers
Modifiers follow the value and change how it is searched.
| Modifier | Effect | Notes |
|---|---|---|
ascii | Match the bytes as written | Default when no encoding modifier is given |
wide | Match UTF-16LE (each char followed by 00) | Combine with ascii to search both |
nocase | Case-insensitive | Multiplies internal variants; avoid on short strings |
fullword | Must be delimited by non-alphanumeric characters | "evil" then won't match "devil" |
xor | Also match the string XORed with every single-byte key 1–255 | xor(1-255) or xor(0x20) narrows the range |
base64 / base64wide | Match the string inside base64-encoded data | Custom alphabet as argument; not combinable with nocase, xor or fullword |
private | Match, but hide the string from match output | Useful for helper patterns |
rule Modifier_Examples
{
strings:
$cfg = "ConfigBlock" wide ascii
$cmd = "invoke-expression" nocase
$key = "SuperSecretKey!" xor(1-255)
$b64 = "powershell -nop" base64
$word = "backdoor" fullword
condition:
2 of them
}
Keep xor, base64 and nocase for strings of at least six to eight characters: each modifier expands one pattern into many, and short expansions match random data.
Hexadecimal strings
Hex strings describe raw bytes between braces. They are the tool of choice for code sequences, file headers and binary configuration blobs.
rule Hex_Syntax
{
strings:
$fixed = { 4D 5A 90 00 03 00 00 00 }
$wild = { E8 ?? ?? ?? ?? 83 C4 04 }
$nibble = { 6A 4? 68 00 30 00 00 }
$jump = { 55 8B EC [2-6] 83 EC 20 }
$alt = { 68 ( 00 10 | 00 20 ) 00 00 }
condition:
any of them
}
| Syntax | Meaning |
|---|---|
?? | Any byte |
4? / ?A | Nibble wildcard: high or low half fixed |
[4], [2-6], [8-] | Jump of exactly 4, between 2 and 6, or 8 or more arbitrary bytes |
( AA | BB CC ) | Alternatives, which may differ in length |
~00 | Any byte except 00 (YARA 4.3+ and YARA-X) |
Opcodes with relative addresses (call, jmp, lea rip) should have their operand bytes wildcarded, otherwise the rule only matches one build. Keep at least four consecutive fixed bytes somewhere in the pattern so YARA can extract a good atom.
Regular expressions
Regexes are written between slashes and follow a Perl-like syntax: character classes, quantifiers, alternation, groups and anchors. Two flags may follow the closing slash: i (case-insensitive) and s (dot matches newlines). The same string modifiers as for text strings (ascii, wide, nocase, fullword, private) apply.
rule Regex_Examples
{
strings:
$url = /https?:\/\/[a-z0-9\-.]{3,64}\.(top|xyz|click)\/[a-z0-9]{8}/ nocase
$ip_port = /\b(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}:[0-9]{2,5}\b/
$mutex = /Global\\[A-F0-9]{8}-[A-F0-9]{4}/
condition:
any of them
}
Regex pitfalls:
- Missing literal part. A regex like
/[a-z]{10}\.exe/has only.exeas a fixed anchor; one like/[a-z]{5,}/has none and must be attempted almost everywhere. - Leading
.*. Patterns are already unanchored; a leading.*only adds work. - Unbounded repetition. Prefer
{1,64}over+or*when you know the maximum length. - Escapes. The forward slash must be escaped as
\/. YARA-X is stricter than YARA 4 about invalid escapes.
Choosing the right type
| You want to match… | Use |
|---|---|
| A unique readable string (mutex, user agent, PDB path) | Text string, with wide if it may be UTF-16 |
| Code bytes, headers, binary structures | Hex string with wildcards for addresses |
| A small set of variants of a byte sequence | Hex alternatives ( … | … ) |
| Something with a variable-length or structured part (URLs, GUIDs) | Regex with a literal anchor |
| An obfuscated string | xor or base64 on a long enough string |
Performance in one paragraph
YARA extracts a short fixed sequence (an atom) from every pattern and searches for all atoms at once; only where an atom hits does it verify the full pattern. Strings shorter than four bytes, hex patterns made of wildcards, common bytes such as 00 00 00 00, and regexes without literals all produce poor atoms and slow down the whole rule set. The performance guide explains the mechanism, and the linter flags these cases automatically.
Next: combine your patterns in YARA conditions.
FAQ
- What does the wide modifier do in YARA?
- wide searches for the string encoded as UTF-16LE, i.e. each ASCII character followed by a zero byte. Add ascii as well if the string may appear in both encodings.
- How do I match any byte in a YARA hex string?
- Use ?? for a full wildcard byte, a single ? for one nibble (for example 4? or ?A), and [n-m] for a jump of n to m arbitrary bytes.
- When should I use a regex instead of a text string?
- Only when the variable part cannot be expressed with a text or hex string. Regexes are slower, and they must contain a literal part of at least a few bytes to be efficient.