CtrlK
BlogDocsLog inGet started
Tessl Logo

reverser-yara-hunting

YARA rule authoring + hunting — `condition:` syntax, hex patterns with wildcards, `for`/`any of them`, PE module, ELF module, hash module, math module. Build per-family signatures, hunt at scale via VT/MalwareBazaar/Hybrid Analysis. Avoid common pitfalls (collisions, slow rules, regex traps).

67

Quality

81%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

YARA Rule Authoring + Hunting

Anatomy of a good rule

import "pe"
import "hash"

rule MalFamily_DropperVariant_Q4_2024 {
    meta:
        author = "you"
        date = "2024-11-20"
        description = "MalFamily dropper, observed Q4 2024 campaign"
        hash = "deadbeefdeadbeefdeadbeefdeadbeef"
        tlp = "amber"
        confidence = "high"
        false_positives = "low (test against AV vendor samples)"
        mitre = "T1055"

    strings:
        $magic = { 4D 5A 90 00 03 }            // MZ + DOS header
        $config_marker = { 7A 89 ?? ?? 4F 8C } // 6-byte signature, 2 wildcards
        $string1 = "loader_stage_2" wide
        $string2 = "cmd.exe /c " ascii
        $api1   = "VirtualAllocEx"
        $api2   = "WriteProcessMemory"
        $api3   = "CreateRemoteThread"
        // Avoid generic strings — they cause FPs.

    condition:
        uint16(0) == 0x5A4D and                    // PE header
        filesize < 5MB and                          // bounded — avoids huge-file scans
        $config_marker and                          // unique marker
        2 of ($api1, $api2, $api3) and             // at least 2 of the 3 process-inject APIs
        any of ($string*) and
        pe.imports("ws2_32.dll", "WSAStartup") and  // network capability
        not pe.is_signed                            // unsigned
}

The condition tools you need

// Filesize / offset reads (no module)
filesize > 100KB and filesize < 5MB
uint32(0x3c) > 0 and uint32(uint32(0x3c)) == 0x4550  // valid PE

// "for" loops over offsets / sections
for any i in (0..pe.number_of_sections - 1):
    (pe.sections[i].name == ".text" and pe.sections[i].entropy > 7.0)

// "of"
1 of them                              // any one string
all of ($a*)                           // all $a*-prefix strings
3 of ($s1, $s2, $s3, $s4, $s5)         // at least 3 of 5

// Hash module
hash.sha256(0, filesize) == "..."      // exact-match rule
hash.imphash() == "..."                // PE import hash (fragile but high-signal)

High-leverage patterns

Family-stable byte patterns

Look for unique byte sequences that survive obfuscation:

  • Crypto constants (SHA-256 IVs, AES sbox, RC4 init pattern)
  • Hard-coded SID strings
  • C2 packet headers (magic bytes, fixed offsets)
  • Reflective loader entry stub bytes (Donut, Cobalt Strike's PE loader)

Capability rules

Don't fingerprint a sample — fingerprint a TECHNIQUE:

rule Suspicious_ProcessInjection {
    meta: description = "VirtualAlloc + WriteProcessMemory + CreateRemoteThread = injection"
    condition:
        pe.imports("kernel32.dll", "VirtualAllocEx") and
        pe.imports("kernel32.dll", "WriteProcessMemory") and
        pe.imports("kernel32.dll", "CreateRemoteThread")
}

This catches every injector regardless of family. False-positive: legitimate tools (Procmon, IDA, debuggers). Reduce via additional conditions (unsigned, in temp dir, etc.).

Anti-analysis fingerprinting

rule AntiVm_VMware_Strings {
    strings:
        $s1 = "VMware" ascii nocase
        $s2 = "VBoxService" ascii nocase
        $s3 = "qemu" ascii nocase
        $s4 = { 56 4D 58 68 } // "VMXh" — VMware backdoor port magic
    condition: 2 of them
}

Hunting at scale

VirusTotal Retrohunt (paid)

// Upload rule to VT — runs against the past 90 days of submissions
// Outputs new hashes matching the signature

MalwareBazaar (free)

# yarafs.io / abuse.ch — runs YARA against MB corpus
curl https://mb-api.abuse.ch/api/v1/ -X POST -d 'query=get_yara&yara_rule=YourRule'

Local corpus scan

# Recursive scan
yara -r rules/ /samples/
# JSON output for downstream processing
yara -r rules/ /samples/ -m -p 4    # -m: metadata, -p: parallel threads

# Fast pre-filter with capa first
capa /samples/sample.exe   # extracts capabilities; rule-driven, JSON-output

Common pitfalls

PitfallFix
Too-short strings (4 bytes) → false positivesUse 8+ byte strings; require multiple matches
Regex /pattern/ with [, ?, * → slowPrefer literal strings; if regex needed, anchor with ^/\b
No filesize bound → scans 5GB filesAlways include filesize < N
Multiple wildcards in one hex ?? → exponential matcher costLimit to 2-3 wildcards per byte string
condition: any of them with one common string → constant FPsUse 2 of them minimum
Rule name with versionUse a separate meta.version so rule survives bumps

Mass-hunt workflow

  1. Triage a sample (see reverser/malware-triage skill)
  2. Extract unique byte patterns, strings, capabilities
  3. Write a YARA rule with meta for context + bounded condition
  4. Test against:
    • The known sample (must match)
    • A clean corpus (must NOT match — false positive rate)
    • A different malware family corpus (must NOT match)
  5. Submit to VT Retrohunt + MalwareBazaar
  6. Track results, iterate

Tooling

  • yara / yara-python (writing + running)
  • yarGen (auto-generate rules from a sample set)
  • valhalla.nextron-systems.com (commercial YARA feed by Florian Roth)
  • Neo23x0/signature-base (open-source canonical rule set)
  • capa (Mandiant — capability-level rules)

References

  • VirusTotal YARA guide
  • "YARA, the pattern matching swiss knife for malware researchers"
  • Florian Roth's blog (the canonical YARA author of our era)
  • "Practical YARA Rules" — Andre Tavares
Repository
PurpleAILAB/Decepticon
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.