Writing YARA Rules: Malware Detection and IOC Matching
Write YARA rules from scratch for malware and IOCs: string match, condition logic, evasion, and tuning. Scan and verify samples with the yara CLI on Linux.
Scope
YARA rules are the industry standard for malware and attack-trace detection. Applies when: threat intel extracts features from confirmed samples and hunts variants at scale; blue-team ops scan server dirs, mail attachments, and user uploads; IR matches IOCs on a compromised host to confirm a known family. Audience: Linux-fluent analysts. Goal: write working YARA rules from zero.
Prerequisites
- Linux server (CentOS 7+ / Ubuntu 20.04+), root
- yara CLI installed; yara-python if you need Python integration
- Malware samples (isolated analysis VM) or public sample sets
- Regex and hex-byte basics
Install YARA:
# Ubuntu / Debian
apt install yara
# CentOS / RHEL (EPEL repo)
yum install epel-release
yum install yara
# Build from source (latest version)
wget https://github.com/VirusTotal/yara/archive/refs/tags/v4.5.2.tar.gz
tar zxf v4.5.2.tar.gz && cd yara-4.5.2
./bootstrap.sh && ./configure --enable-cuckoo --enable-magic
make -j$(nproc) && make install
# Verify install
yara --version
How It Works
A YARA rule is a condition expression: if file content matches declared strings, byte sequences, and logic, it hits. Three parts — meta, strings, condition. Engine extracts the string table and byte sequences, evaluates conditions, then emits the rule name and matched features. Quality is not string count; it is precise condition combinatorics that balance detection vs false positives.
Procedure
Step 1: First rule
Create first.yar:
rule First_Rule
{
meta:
author = "ops"
description = "Example rule: detect test marker"
date = "2026-08-18"
strings:
$a = "malware_marker"
$b = { 6D 61 6C 77 61 72 65 }
condition:
$a or $b
}
Create a test file and scan:
echo "this is a malware_marker test" > /tmp/sample.txt
yara /tmp/first.yar /tmp/sample.txt
# Output: First_Rule /tmp/sample.txt
Step 2: Wide strings and hex bytes
Windows malware often stores UTF-16LE strings; ASCII-only rules miss. Use wide for wide strings; hex blocks for variable bytes:
rule Wide_String_Detect
{
strings:
$a = "cmd.exe" wide ascii
$b = { 68 00 74 00 74 00 70 00 3A 00 2F 00 2F 00 } // h t t p : / /
condition:
$a or $b
}
Hex blocks support wildcards ? and jumps [-N]. Example: { 6A ?? 74 } — second byte any.
Step 3: File-attribute conditions
Combine filesize, entropy, and similar to cut FPs:
rule PE_Malware_Size_Hint
{
condition:
uint16(0) == 0x5A4D // MZ header
and filesize < 2MB
and pe.imphash() == "3b2c3c4a5d6e7f80"
}
Note: pe module needs compile-time support (--enable-cuckoo or default PE support).
Step 4: Directory scan and recursion
# Scan a single directory (non-recursive)
yara /tmp/rules/ /tmp/samples/
# Recursive scan and show matched strings
yara -r -s /tmp/rules/ /tmp/samples/
# Count hits only
yara -c /tmp/rules/ /tmp/samples/
Step 5: Multi-rule files and tags
// tags.yar
rule Tagged_Rule : webshell php
{
strings:
$a = "eval("
condition:
$a
}
Filter by tag with -t:
yara -t webshell /tmp/rules/ /tmp/samples/
Validation
Standard rule-validation flow:
# 1. syntax check (syntax errors fail immediately)
yara /tmp/rules/all.yar /tmp/empty.txt
# 2. True-positive verify with known malware samples (must hit)
yara /tmp/rules/all.yar /tmp/malware_sample.bin
# 3. False-positive verify with benign files (should not hit)
yara /tmp/rules/all.yar /usr/bin/ls /etc/passwd
# 4. Measure rule coverage
yara -c -r /tmp/rules/ /tmp/samples/
# Output hit file count; compare with total sample count
Integrate yara regression in CI: after each new rule, run known-bad and known-good sets. Detection rate vs FP rate is then obvious.
FAQ
FAQ 1: High false-positive rate?
Tighten conditions; do not delete strings first. Add filesize bounds, uint16(0) == 0x5A4D type checks, and across multiple strings, and count conditions like #a > 3. Use -s to see which strings actually hit, then tighten those.
FAQ 2: Wide-string rule misses the sample?
Confirm the sample string is actually UTF-16LE. Use wide ascii together. Check the condition still references the string. Packed/compressed samples need unpacking first or the feature never appears.
Summary
YARA authorship is core SOC skill: rule = feature strings + logic. Balance detection vs FPs. Loop: write → true-positive verify → white-sample verify → check in → iterate. Use pe.imphash(), filesize, entropy to harden rules. Wire YARA to analysis sandboxes and EDR alerts for a sample-to-detect closed loop.