← News
/PLAYBOOK · 2026-08-18

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

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.