YARA and YARA-X: Pattern Matching for Malware Analysis
- YARA and YARA-X: Pattern Matching for Malware Analysis
Overview
YARA is a rule-based pattern matching engine designed for identifying and classifying malware samples. A YARA rule describes a file (or memory region) by combining string patterns, byte sequences, and Boolean logic. When a file matches all conditions in a rule, YARA reports the match — along with whichever matched strings you choose to print.
YARA is used at every stage of malware analysis:
- Triage: rapidly classify a sample by family before deeper analysis
- Hunting: sweep across a file corpus, memory dump, or live process list for known indicators
- Integration: CAPE sandbox uses YARA rules as breakpoints during execution; Velociraptor runs YARA hunts across an entire fleet; Suricata can scan extracted files with YARA via a Lua output module
YARA-X is a complete Rust rewrite of YARA, released as stable (v1.0.0) in June 2025. It is now the primary development target; YARA 4.x is in maintenance mode (security fixes only). VirusTotal migrated its Livehunt and Retrohunt infrastructure to YARA-X in December 2024, and saw scan timeouts drop from ~2% of files to under 0.2%.
This page covers both engines side-by-side where they differ.
Installation
YARA (Classic)
Current stable: v4.5.5 (October 2024).
# Kali / Debian
sudo apt update && sudo apt install yara
# Python bindings
pip install yara-python
# Build from source (for --with-crypto and --enable-magic modules)
sudo apt install automake libtool make gcc pkg-config \
libssl-dev libjansson-dev libmagic-dev
wget https://github.com/VirusTotal/yara/releases/download/v4.5.5/yara-4.5.5.tar.gz
tar xzf yara-4.5.5.tar.gz && cd yara-4.5.5
./bootstrap.sh
./configure --with-crypto --enable-magic
make && sudo make install
YARA-X
Current stable: v1.0.0+ (June 2025, with ongoing releases).
# Option 1: Pre-built binary (Linux/macOS/Windows — no Rust needed)
# Download from https://github.com/VirusTotal/yara-x/releases
# Extract and place 'yr' in PATH
# Option 2: Build from source (requires Rust)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
git clone https://github.com/VirusTotal/yara-x
cd yara-x
cargo install --path cli
# Option 3: macOS (Homebrew)
brew install yara-x
# Python bindings
pip install yara-x
No apt package for Kali/Debian as of mid-2026. Use the pre-built release binary.
Rule Structure
A YARA rule has three optional sections and one required section:
rule RuleName : tag1 tag2 {
meta:
author = "Analyst Name"
description = "Detects Foo malware dropper"
date = "2025-06-01"
reference = "https://blog.example.com/analysis"
hash = "abc123def456..."
severity = "high"
mitre_attack = "T1059.001"
strings:
$magic = { 4D 5A }
$url = /https?:\/\/[a-z0-9]{8,}\.(ru|cn|top)/i
$cmd = "cmd.exe /c" nocase
condition:
$magic at 0 and
filesize < 2MB and
any of ($url, $cmd)
}
| Section | Required | Purpose |
|---|---|---|
meta: |
No | Key=value descriptors. String, int, or bool values. Not usable in conditions. |
strings: |
No | Named patterns ($identifier). Three types: hex, text, regex. |
condition: |
Yes | Boolean expression that determines a match. |
Rule names are alphanumeric + underscore, max 128 characters.
Tags follow the colon after the name; space-separated. Use -t <tag> on the command line to filter by tag.
Naming Convention
A commonly used convention for threat intelligence sharing:
THREATACTOR_MALWARE_ROLE_PLATFORM
Examples: APT28_XAgent_Loader_Windows, Lazarus_Dropper_Linux_x64, Generic_Ransomware_Encryptor.
String Types
Hex Strings
Raw byte sequences in curly braces. Support wildcards, ranges, negation, and alternatives.
strings:
$exact = { E2 34 A1 C8 23 FB }
$wild = { E2 34 ?? C8 } // ?? = any single byte
$nibble = { E2 3? ?? C8 } // ? = any nibble
$not_00 = { F4 23 ~00 62 B4 } // ~ = NOT this byte
$jump = { F4 23 [4-6] 62 B4 } // [n-m] = n to m arbitrary bytes
$unbnd = { AA BB [10-] CC DD } // unbounded upper limit
$any_len = { AA BB [-] CC DD } // 0 or more bytes
$alt = { F4 ( 62 B4 | 56 ) 45 } // alternatives in parentheses
Text Strings
Double-quoted strings with C-style escapes (\n, \t, \xNN, \\, \").
strings:
$t1 = "This program cannot be run in DOS mode"
$t2 = "NtCreateThread\x00"
$t3 = "HKEY_CURRENT_USER\\Software\\Run"
Regular Expressions
Perl-like syntax between forward slashes. Modifiers /i (case-insensitive) and /s (dot matches newline).
strings:
$r1 = /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ // IPv4
$r2 = /https?:\/\/[a-z0-9\-]{3,}\.(ru|cn|top|xyz)/i
$r3 = /HKEY_[A-Z_]+/i
$r4 = /-----BEGIN [A-Z ]+ KEY-----/s
String Modifiers
Modifiers follow the string definition, separated by spaces.
| Modifier | Types | Effect |
|---|---|---|
nocase |
text, regex | Case-insensitive match |
wide |
text, regex | Match UTF-16 LE encoding (every char followed by \x00) |
ascii |
text, regex | Match ASCII; combine with wide to catch both encodings |
fullword |
text, regex | Only match when bounded by non-alphanumeric characters |
xor |
text | Try all XOR keys 0x00–0xFF; use xor(0x01-0xff) to skip plaintext |
base64 |
text | Match Base64-encoded variants (3 alignment permutations); min 4 chars |
base64wide |
text | Like base64 but the base64 output is then UTF-16 LE encoded |
private |
text, hex, regex | Participates in matching but never printed in output |
Incompatibilities: nocase cannot be combined with xor, base64, or base64wide. fullword cannot be combined with base64 or base64wide.
strings:
$a = "Borland" wide ascii nocase // catch both encodings, any case
$b = "cmd.exe" xor(0x01-0xff) // common single-byte XOR obfuscation
$c = "MZ" base64 // base64-encoded PE header
$d = /\.dll$/i fullword // extension, word-bounded
$e = { DE AD BE EF } private // matches counted, never printed
Conditions
String Presence and Counting
condition:
$a // true if $a matches anywhere
$a and $b // both must match
not $c // $c must not match
#a >= 3 // $a appears at least 3 times
#b == 0 // $b does not appear
Offsets and Lengths
$a at 0 // $a must start at offset 0
$b at 0x100 // exact offset
$c in (0x0..0x200) // anywhere in range
@a // offset of first $a match
@a[2] // offset of second match
!a // length of first $a match
!a[2] // length of second match
@a - @b < 10 // within 10 bytes of each other
File Size
filesize < 200KB
filesize > 1MB
filesize == 4096
Units: KB, MB. No suffix = bytes.
Raw Data Reads
Read specific bytes from the file without defining a string.
uint16(0) == 0x5A4D // "MZ" — PE file magic
uint32(0) == 0x464C457F // ELF magic (little-endian)
uint32be(0) == 0x7F454C46 // ELF magic (big-endian)
uint8(0) == 0x7F and
uint8(1) == 0x45 // 'E'
Functions: int8, int16, int32, uint8, uint16, uint32; append be for big-endian.
Set Operators (of)
any of them // any string defined in the rule
all of them // every string must match
none of ($b*) // none of the $b* group
2 of ($a, $b, $c) // at least 2 of these 3
any of ($prefix*) // any string whose name starts with $prefix
1 of (Rule1, Rule2) // at least 1 of these rules matches (rule references)
for..of — Per-occurrence conditions
for all of them : ( # > 2 ) // every pattern appears 2+ times
for any of ($a*) : ( @ > 0x100 ) // any $a* match is past offset 0x100
for 2 of ($a, $b, $c) : ( @ < 512 ) // at least 2 of those match before byte 512
for..in — Index iteration
for all i in (1..#a) : ( @a[i] < 100 ) // every $a match is within first 100 bytes
for any i in (1..#a) : ( @a[i] + 10 == @b[i] ) // some $a match is 10 bytes before a $b match
String operators (v4.2.0+)
pe.version_info["CompanyName"] contains "Microsoft"
pe.description startswith "Windows"
pe.version_info["CompanyName"] icontains "microsoft" // case-insensitive
pe.description matches /[Mm]icrosoft/
Worked Example: Weighted Scoring
Rather than requiring all indicators, use math.to_number to weight evidence:
import "math"
rule Suspicious_PowerShell_Downloader {
meta:
description = "Scores indicators; fires at >= 70 points"
strings:
$iex = "IEX(" nocase
$wget = "New-Object Net.WebClient" nocase
$enc = "FromBase64String" nocase
$bypass = "-ExecutionPolicy Bypass" nocase
condition:
math.to_number($iex) * 30 +
math.to_number($wget) * 30 +
math.to_number($enc) * 25 +
math.to_number($bypass) * 15 >= 70
}
Modules
Import a module at the top of the file:
import "pe"
import "math"
PE Module
The most commonly used module for Windows malware analysis.
import "pe"
rule Packed_PE {
condition:
uint16(0) == 0x5A4D and
pe.number_of_sections < 4 and
math.entropy(pe.sections[0].raw_data_offset,
pe.sections[0].raw_data_size) > 7.0
}
Key attributes:
pe.machine == pe.MACHINE_AMD64 // or MACHINE_I386, MACHINE_ARM64
pe.number_of_sections
pe.timestamp // Unix epoch; 0 in many stripped files
pe.entry_point
pe.is_dll()
pe.is_32bit() / pe.is_64bit()
pe.imphash() // normalized import hash (lowercase string)
// Sections (0-indexed array)
pe.sections[0].name // e.g. ".text"
pe.sections[0].virtual_address
pe.sections[0].raw_data_offset
pe.sections[0].raw_data_size
pe.sections[0].characteristics
// Imports
pe.imports("kernel32.dll", "WriteProcessMemory") // bool
pe.imports("ntdll.dll") // count of ntdll imports
// Exports
pe.exports("GetProcAddress") // bool
pe.exports(72) // by ordinal
// Version info
pe.version_info["CompanyName"] contains "Microsoft"
pe.version_info["FileDescription"] startswith "Windows"
// Characteristics
pe.characteristics & pe.DLL
ELF Module
import "elf"
elf.machine == elf.EM_X86_64
elf.machine == elf.EM_ARM
elf.machine == elf.EM_AARCH64
elf.entry_point
elf.sections[0].name
elf.sections[0].size
elf.segments[0].flags & elf.PF_X // executable segment
elf.symtab[0].name
elf.symtab[0].type == elf.STT_FUNC
elf.telfhash() // TLSH of symbols
Math Module
import "math"
// Entropy: 0.0 (uniform) to 8.0 (random/encrypted)
math.entropy(0, filesize) >= 7.0
// Per-section entropy
math.entropy(
pe.sections[0].raw_data_offset,
pe.sections[0].raw_data_size) > 7.0
math.mean(0, filesize) < 72.0
math.mode(0, filesize) == 0xFF // most frequent byte value (v4.2.0+)
math.count(0x00, 0, filesize) > 1000 // count zero bytes (v4.2.0+)
math.percentage(0xFF, 0, 1024) >= 0.9 // 90%+ of first 1KB is 0xFF (v4.2.0+)
math.abs(@a - @b) == 1
High entropy (≥ 7.0) in a PE section is a common packing or encryption indicator. However, high-entropy sections are also normal in legitimately compressed executables, so combine with other indicators.
Hash Module
import "hash"
hash.md5(0, filesize) == "feba6c919e3797e7778e8f2e85fa033d"
hash.sha256(0, filesize) == "abc123..."
hash.md5(0, 512) // hash of first 512 bytes
hash.crc32(0, filesize)
All returned hash strings are lowercase.
Time Module
import "time"
// Flag PE files with compile timestamps in the future
pe.timestamp > time.now()
// Flag suspiciously old compile timestamp (before 1990)
pe.timestamp < 631152000
Command-Line Usage
YARA (Classic)
yara [OPTIONS] <rules_file> <target>
<target> can be a file, directory, or PID (for process memory scanning).
| Flag | Description |
|---|---|
-r |
Recurse into directories |
-s |
Print matching strings |
-m |
Print metadata |
-e |
Print rule namespace |
-g |
Print tags |
-c |
Print count of matches only |
-n |
Negate: print rules that did NOT match |
-t <tag> |
Filter output to rules with this tag |
-f |
Fast scan: stop at first match per rule |
-d <var>=<val> |
Define external variable (repeatable) |
-p <N> |
Use N threads for directory scanning |
-a <secs> |
Timeout in seconds |
-z <bytes> |
Skip files larger than N bytes |
-C |
Treat rules file as compiled .yarc |
--scan-list |
Read target paths from a file (one per line) |
-D |
Print module data (debug module output) |
# Scan a directory, print strings and metadata
yara -r -s -m rules.yar /path/to/samples/
# Scan a running process
yara rules.yar 4321
# Filter by tag, with external variable
yara -t ransomware -d owner="finance" rules.yar /samples/
# Compile rules and use compiled file
yarac rules.yar compiled.yarc
yara -C compiled.yarc target.bin
# Scan files listed in a file
yara --scan-list rules.yar filelist.txt
YARA-X (yr)
YARA-X uses subcommands.
yr scan
yr scan [OPTIONS] <RULES_PATH>... <TARGET_PATH>
Key flags:
| Flag | Description |
|---|---|
--define <VAR=VALUE> |
External variable (repeatable) |
-m, --print-meta |
Print metadata |
-g, --print-tags |
Print tags |
--print-strings[=N] |
Print matched patterns (optional char limit) |
-r, --recursive[=DEPTH] |
Recurse with optional max depth |
--scan-list |
Targets from file |
--output-format <fmt> |
text, ndjson, or json |
--profiling |
Identify slowest rules by performance |
-C, --compiled-rules |
RULES_PATH is a .yarc file |
--threads N |
Number of scanning threads |
--timeout <SECS> |
Abort scan after N seconds |
--relaxed-re-syntax |
Relax regex strictness (porting from YARA) |
# Scan and print JSON output
yr scan --output-format json rules.yar sample.exe | jq '.matches[].rule'
# Recursive scan with profiling
yr scan --profiling -r rules/ /samples/
# Profile slowest rules to identify performance bottlenecks
yr scan --profiling rules.yar /large/corpus/
Other yr subcommands
# Compile rules to binary (faster repeated scanning)
yr compile rules.yar -o compiled.yarc
# Inspect module data without writing a rule
yr dump --module pe suspicious.exe
yr dump --output-format yaml --module lnk shortcut.lnk
yr dump --module elf malware.elf
# Auto-format rules (like gofmt for YARA)
yr fmt rules.yar
yr fmt --check rules.yar # exit non-zero if formatting needed (CI use)
# Show dependencies and module usage
yr deps rules.yar
# Auto-fix fixable warnings
yr fix warnings rules.yar
External Variables
Define variables in rules that callers provide at scan time. Useful for context-aware rules (e.g., “is this on a production host?”).
rule CheckContext {
condition:
ext_hostname contains "prod" and
ext_file_owner == "root" and
ext_is_quarantined == false
}
Pass values on the command line:
# YARA
yara -d ext_hostname="prod-web-01" -d ext_file_owner="root" \
-d ext_is_quarantined=false rules.yar target.bin
# YARA-X
yr scan --define ext_hostname="prod-web-01" \
--define ext_file_owner="root" \
--define ext_is_quarantined=false \
rules.yar target.bin
In Python (yara-python):
rules = yara.compile('rules.yar',
externals={'ext_hostname': 'default', 'ext_file_owner': 'unknown', 'ext_is_quarantined': False})
matches = rules.match('target.bin',
externals={'ext_hostname': 'prod-web-01', 'ext_file_owner': 'root'})
Python API
yara-python (Classic YARA)
import yara
# Compile
rules = yara.compile('rules.yar')
rules = yara.compile(source='rule test { condition: true }')
# Match a file
matches = rules.match('/path/to/sample.exe')
# Match a process
matches = rules.match(pid=1234)
# Match raw bytes
matches = rules.match(data=b'\x4D\x5A\x00\x00...')
for match in matches:
print(match.rule, match.tags, match.meta)
for s in match.strings:
print(f" {s.identifier} at offset {s.instances[0].offset}")
yara-x Python API
The YARA-X Python API is not compatible with yara-python; code must be rewritten.
import yara_x
# Compile
rules = yara_x.compile('rule test { condition: true }')
# Or use a Compiler for multi-namespace workflows
compiler = yara_x.Compiler()
compiler.new_namespace("apt_rules")
compiler.add_source(open("apt.yar").read())
rules = compiler.build()
# Scanner
scanner = yara_x.Scanner(rules)
scanner.set_timeout(30)
result = scanner.scan_file("sample.exe")
result = scanner.scan(b"\x4D\x5A...")
# Results
for rule in result.matching_rules:
print(rule.identifier, rule.namespace, rule.metadata)
for pattern in rule.patterns:
for match in pattern.matches:
print(f" {pattern.identifier} at offset={match.offset} len={match.length}")
Note: YARA-X does not yet support scanning process memory from Python. Use classic YARA (
yara-python) for process scanning.
YARA-X: Key Differences from YARA
Breaking Changes
Most YARA 4.x rules work unchanged in YARA-X. These are the cases that require edits:
| Issue | YARA behavior | YARA-X behavior |
|---|---|---|
Regex: unescaped { |
Accepted silently | Error — must escape as \{ |
Regex: invalid escape (e.g. \g) |
Accepted silently | Error |
base64 on strings < 3 chars |
Allowed (false positives) | Error — minimum 3 chars |
Wildcard rule names (1 of (rule*)) |
Supported | Not supported |
Negative array index (@a[-1]) |
Allowed | Error |
xor + fullword |
Surrounding bytes checked without XOR | Surrounding bytes also XOR’d |
Use yr scan --relaxed-re-syntax as a transitional flag when porting rules with regex issues.
New Features in YARA-X
with statement — local variables in conditions:
import "pe"
rule ReusedStrings {
condition:
with first = pe.version_info["CompanyName"],
last = pe.exports("GetProcAddress") : (
first contains "Microsoft" and last
)
}
.len() method on strings, arrays, and dicts:
condition:
pe.version_info["CompanyName"].len() > 0 and
pe.sections.len() > 5
yr dump — inspect module output without writing a rule:
yr dump --module pe malware.exe
yr dump --module lnk phishing_invoice.lnk
yr fmt — canonical rule formatter (like gofmt for YARA).
--profiling — built-in per-rule timing; identify which rules are slow.
--output-format ndjson — newline-delimited JSON for pipeline processing.
New Modules in YARA-X
| Module | Purpose |
|---|---|
lnk |
Windows Shortcut (.lnk) files — detects phishing delivery vectors |
macho |
macOS Mach-O binary format |
dotnet |
.NET assembly analysis |
dex |
Android DEX files |
crx |
Chrome extensions (includes permhash for permission fingerprinting) |
console |
Logging/debugging output from within rules |
string |
String manipulation utilities |
Practical Rule Writing
Anti-FP Checklist
- Use unique strings. Avoid strings that appear in common runtimes (OpenSSL, zlib, MSVC CRT).
- Minimum 6–8 chars for text patterns; shorter strings match too broadly.
- Combine conditions.
all of ($a, $b, $c)is far more precise thanany of them. - Guard with file type checks.
uint16(0) == 0x5A4Doruint32(0) == 0x464C457Fbefore string scans. - Test against clean corpora. Run against
/usr/bin/*, WindowsSystem32, common software before deploying. - Use
2 of ($a, $b, $c, $d)when some indicators may be absent — require evidence, not perfection.
Performance Checklist
- Cheap conditions first.
uint16(0) == 0x5A4D and filesize < 5MB and ...— header checks short-circuit before expensive string scans. - Use
-f/--fast-scanwhen presence is all you need (stops at first match). - Prefer hex over regex for fixed byte sequences — YARA’s Aho-Corasick handles fixed strings fastest.
- Bound your jumps.
[4-16]instead of[0-]. - Avoid
nocaseon wide regex — it is substantially slower. - Anchor regex patterns.
/^MZ/has a better atom than/MZ/; long fixed prefixes are extracted for pre-screening. - Use
yr scan --profilingto find slow rules in your ruleset. - Precompile with
yarac/yr compilefor repeated scanning.
Testing Rules
Craft minimal test files:
# Test a text pattern rule
printf 'cmd.exe /c powershell -ExecutionPolicy Bypass' > /tmp/test.bin
yara -s rules.yar /tmp/test.bin
# Test a PE header rule (fake MZ header)
python3 -c "import sys; sys.stdout.buffer.write(b'MZ' + b'\x00'*100)" > /tmp/fake.exe
yara -s rules.yar /tmp/fake.exe
Verify a rule does NOT match clean files:
yara -r rules.yar /usr/bin/ 2>/dev/null | grep -c "RuleName" # should be 0
JSON output for scripted testing (YARA-X):
yr scan --output-format json rules.yar sample.bin | jq '.matches | length'
YARA-CI (GitHub App) runs automated tests on push and flags false positives against a whitelist corpus. Add it to any GitHub repo containing YARA rules.
Full Worked Example: PE Malware Classifier
import "pe"
import "math"
rule Potential_Packed_Downloader : suspicious {
meta:
author = "CS493 Example"
description = "PE with high entropy, no version info, and download indicators"
severity = "medium"
strings:
$url1 = /https?:\/\/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ nocase
$url2 = /https?:\/\/[a-z0-9]{8,}\.(ru|cn|top|xyz)/i
$dl1 = "URLDownloadToFile" nocase
$dl2 = "WinHttpOpen" nocase
$dl3 = "InternetOpenUrl" nocase
$enc1 = "FromBase64String" nocase
$enc2 = "cmd.exe /c" xor(0x01-0xff)
condition:
uint16(0) == 0x5A4D and // is a PE file
filesize < 5MB and
pe.number_of_sections >= 2 and
not pe.is_dll() and // not a library
math.entropy(0, filesize) >= 6.5 and // somewhat packed
(pe.version_info["CompanyName"] == "" or
not pe.imports("kernel32.dll")) and // stripped metadata
(1 of ($url*) or 1 of ($dl*)) and // has download indicator
(any of ($enc*)) // plus encoding
}
Integration
Suricata
Suricata does not run YARA rules natively — integration uses Suricata’s Lua output module to scan extracted files from network traffic.
# suricata.yaml — add to outputs
outputs:
- lua:
enabled: yes
scripts:
- yara.lua
Configure yara.lua (from the yara-suricata project) with your rules path and Suricata file-store location:
suricata_filestore = "/var/log/suricata/files"
yara_path = "/usr/bin/yara"
yara_rules_path = "/usr/share/yara/rules.yar"
Suricata writes extracted files to the file-store; the Lua script calls YARA on each file and logs hits to Suricata’s JSON log. Files with no hits are deleted automatically.
CAPE Sandbox
CAPE integrates YARA at multiple points:
- Static pre-detonation — classifies the sample by family before execution
- Dynamic in-detonation — YARA rules on unpacked memory act as debugger breakpoints, firing mid-execution
- Payload classification — identifies malware family after unpacking
- Config extraction — YARA-matched signatures drive automated config extraction
- Anti-evasion — YARA + debugger actions detect and counter sandbox evasion in real time
Place custom .yar files in CAPE’s data/yara/ directory.
Velociraptor
Velociraptor runs YARA hunts across an entire endpoint fleet via VQL (Velociraptor Query Language):
-- Define the YARA rule
LET YaraRule = '''
rule Suspicious_LNK {
meta:
description = "LNK with long command line"
strings:
$cmd = "powershell" nocase
$enc = "-EncodedCommand" nocase
condition:
any of them
}
'''
-- Hunt for matches across the fleet
SELECT FileName, String.Offset AS Offset,
str(str=String.Data) AS Hit
FROM foreach(
row={SELECT FullPath FROM glob(globs='''C:\Users\*\Downloads\*.lnk''')},
query={SELECT * FROM yara(files=FullPath, rules=YaraRule)}
)
Key VQL functions:
| Function | Description |
|---|---|
yara(files=PATH, rules=RULE) |
Scan file(s); memory-mapped without accessor for full-file analysis |
proc_yara(pid=N, rules=RULE) |
Scan process memory |
yara(files=PATH, rules=RULE, accessor="ntfs") |
Scan via raw NTFS accessor (bypasses file locks) |
Note: When an
accessoris used, Velociraptor reads in chunks — rules usingfilesizemay not behave as expected.
References
- YARA Documentation (v4.5.0)
- YARA GitHub Releases
- Kali Linux — YARA package
- YARA-X Official Documentation
- YARA-X GitHub
- YARA-X vs YARA — feature comparison
- YARA-X differences with YARA (breaking changes)
- YARA-X 1.0.0 Stable Release blog post
- VirusTotal migrates Livehunt/Retrohunt to YARA-X
- YARA-X CLI commands reference
- YARA-X Python API
- YARA PE module reference
- YARA math module reference
- yara-suricata Lua integration
- CAPEv2 Sandbox (YARA integration)
- Velociraptor YARA scanning docs
- Intezer — Minimizing YARA false positives
- YARA performance optimization
- YARA-CI — automated rule testing (GitHub App)