Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Guides authoring of high-quality YARA-X detection rules for malware identification. Use when writing, reviewing, or optimizing YARA rules. Covers naming conventions, string selection, performance optimization, migration from legacy YARA, and false positive reduction. Triggers on: YARA, YARA-X, malware detection, threat hunting, IOC, signature, crx module, dex module.
YARA-X Rule Authoring
Write detection rules that catch malware without drowning in false positives.
This skill targets YARA-X, the Rust-based successor to legacy YARA. YARA-X powers VirusTotal's production systems and is the recommended implementation. See Migrating from Legacy YARA if you have existing rules.
Core Principles
Strings must generate good atoms โ YARA extracts 4-byte subsequences for fast matching. Strings with repeated bytes, common sequences, or under 4 bytes force slow bytecode verification on too many files.
Target specific families, not categories โ "Detects ransomware" catches everything and nothing. "Detects LockBit 3.0 configuration extraction routine" catches what you want.
Test against goodware before deployment โ A rule that fires on Windows system files is useless. Validate against VirusTotal's goodware corpus or your own clean file set.
Short-circuit with cheap checks first โ Put filesize < 10MB and uint16(0) == 0x5A4D before expensive string searches or module calls.
Metadata is documentation โ Future you (and your team) need to know what this catches, why, and where the sample came from.
When to Use
Writing new YARA-X rules for malware detection
Reviewing existing rules for quality or performance issues
Optimizing slow-running rulesets
Converting IOCs or threat intel into detection signatures
Debugging false positive issues
Preparing rules for production deployment
Migrating legacy YARA rules to YARA-X
Analyzing Chrome extensions (crx module)
Analyzing Android apps (dex module)
When NOT to Use
Static analysis requiring disassembly โ use Ghidra/IDA skills
Dynamic malware analysis โ use sandbox analysis skills
Network-based detection โ use Suricata/Snort skills
Memory forensics with Volatility โ use memory forensics skills
Simple hash-based detection โ just use hash lists
YARA-X Overview
YARA-X is the Rust-based successor to legacy YARA: 5-10x faster regex, better errors, built-in formatter, stricter validation, new modules (crx, dex), 99% rule compatibility.
Install:brew install yara-x (macOS) or cargo install yara-x
Essential commands:yr scan, yr check, yr fmt, yr dump
Platform Considerations
YARA works on any file type. Adapt patterns to your target:
Validate: yr check, scan: yr scan -s, inspect: yr dump -m pe
signature-base
Study quality examples
YARA-CI
Goodware corpus testing before deployment
Master these five. Don't get distracted by tool catalogs.
Rationalizations to Reject
When you catch yourself thinking these, stop and reconsider.
Rationalization
Expert Response
"This generic string is unique enough"
Test against goodware first. Your intuition is wrong.
"yarGen gave me these strings"
yarGen suggests, you validate. Check each one manually.
"It works on my 10 samples"
10 samples โ production. Use VirusTotal goodware corpus.
"One rule to catch all variants"
Causes FP floods. Target specific families.
"I'll make it more specific if we get FPs"
Write tight rules upfront. FPs burn trust.
"This hex pattern is unique"
Unique in one sample โ unique across malware ecosystem.
"Performance doesn't matter"
One slow rule slows entire ruleset. Optimize atoms.
"PEiD rules still work"
Obsolete. 32-bit packers aren't relevant.
"I'll add more conditions later"
Weak rules deployed = damage done.
"This is just for hunting"
Hunting rules become detection rules. Same quality bar.
"The API name makes it malicious"
Legitimate software uses same APIs. Need behavioral context.
"any of them is fine for these common strings"
Common strings + any = FP flood. Use any of only for individually unique strings.
"This regex is specific enough"
/fetch.*token/ matches all auth code. Add exfil destination requirement.
"The JavaScript looks clean"
Attackers poison legitimate code with injects. Check for eval+decode chains.
"I'll use .* for flexibility"
Unbounded regex = performance disaster + memory explosion. Use .{0,30}.
"I'll use --relaxed-re-syntax everywhere"
Masks real bugs. Fix the regex instead of hiding problems.
Decision Trees
Is This String Good Enough?
Is this string good enough?
โโ Less than 4 bytes?
โ โโ NO โ find longer string
โโ Contains repeated bytes (0000, 9090)?
โ โโ NO โ add surrounding context
โโ Is an API name (VirtualAlloc, CreateRemoteThread)?
โ โโ NO โ use hex pattern of call site instead
โโ Appears in Windows system files?
โ โโ NO โ too generic, find something unique
โโ Is it a common path (C:\Windows\, cmd.exe)?
โ โโ NO โ find malware-specific paths
โโ Unique to this malware family?
โ โโ YES โ use it
โโ Appears in other malware too?
โโ MAYBE โ combine with family-specific marker
When to Use "all of" vs "any of"
Should I require all strings or allow any?
โโ Strings are individually unique to malware?
โ โโ any of them (each alone is suspicious)
โโ Strings are common but combination is suspicious?
โ โโ all of them (require the full pattern)
โโ Strings have different confidence levels?
โ โโ Group: all of ($core_*) and any of ($variant_*)
โโ Seeing many false positives?
โโ Tighten: switch any โ all, add more required strings
Lesson from production: Rules using any of ($network_*) where strings included "fetch", "axios", "http" matched virtually all web applications. Switching to require credential path AND network call AND exfil destination eliminated FPs.
Performance is terrible even after optimization โ Architecture problem. Split into multiple focused rules or add strict pre-filters.
Description is hard to write โ The rule is too vague. If you can't explain what it catches, it catches too much.
Debugging False Positives
FP Investigation Flow:
โ
โโ 1. Which string matched?
โ Run: yr scan -s rule.yar false_positive.exe
โ
โโ 2. Is it in a legitimate library?
โ โโ Add: not $fp_vendor_string exclusion
โ
โโ 3. Is it a common development pattern?
โ โโ Find more specific indicator, replace the string
โ
โโ 4. Are multiple generic strings matching together?
โ โโ Tighten to require all + add unique marker
โ
โโ 5. Is the malware using common techniques?
โโ Target malware-specific implementation details, not the technique
Hex vs Text vs Regex
What string type should I use?
โ
โโ Exact ASCII/Unicode text?
โ โโ TEXT: $s = "MutexName" ascii wide
โ
โโ Specific byte sequence?
โ โโ HEX: $h = { 4D 5A 90 00 }
โ
โโ Byte sequence with variation?
โ โโ HEX with wildcards: { 4D 5A ?? ?? 50 45 }
โ
โโ Pattern with structure (URLs, paths)?
โ โโ BOUNDED REGEX: /https:\/\/[a-z]{5,20}\.onion/
โ
โโ Unknown encoding (XOR, base64)?
โโ TEXT with modifier: $s = "config" xor(0x00-0xFF)
Is the Sample Packed? (Check First)
Before writing any string-based rule:
Is the sample packed?
โโ Entropy > 7.0?
โ โโ Likely packed โ find unpacked layer first
โโ Few/no readable strings?
โ โโ Likely packed โ use entropy, PE structure, or packer signatures
โโ UPX/MPRESS/custom packer detected?
โ โโ Target the unpacked payload OR detect the packer itself
โโ Readable strings available?
โโ Proceed with string-based detection
Expert guidance: Don't write rules against packed layers. The packing changes; the payload doesn't.
When Strings Fail, Pivot to Structure
If yarGen returns only API names and generic paths:
String extraction failed โ what now?
โโ High entropy sections?
โ โโ Use math.entropy() on specific sections
โโ Unusual imports pattern?
โ โโ Use pe.imphash() for import hash clustering
โโ Consistent PE structure anomalies?
โ โโ Target section names, sizes, characteristics
โโ Metadata present?
โ โโ Target version info, timestamps, resources
โโ Nothing unique?
โโ This sample may not be detectable with YARA alone
Expert guidance: "One can try to use other file properties, such as metadata, entropy, import hashes or other data which stays constant." โ Kaspersky Applied YARA Training
Expert Heuristics
String selection: Mutex names are gold; C2 paths silver; error messages bronze. Stack strings are almost always unique. If you need >6 strings, you're over-fitting.
Condition design: Start with filesize <, then magic bytes, then strings, then modules. If >5 lines, split into multiple rules.
Quality signals: yarGen output needs 80% filtering. Rules matching <50% of variants are too narrow; matching goodware are too broad.
Modifier discipline:
Never use nocase or wide speculatively โ only when you have confirmed evidence the case/encoding varies in samples
nocase doubles atom generation; wide doubles string matching โ both have real costs
"If you don't have a clear reason for using those modifiers, don't do it" โ Kaspersky Applied YARA
Regex anchoring:
Regex without a 4+ byte literal substring evaluates at every file offset โ catastrophic performance
Always anchor regex to a distinctive literal: /mshta\.exe http:\/\/.../ not /http:\/\/.../
If you can't anchor, consider hex pattern with wildcards instead
Loop discipline:
Always bound loops with filesize: filesize < 100KB and for all i in (1..#a) : ...
Unbounded #a can be thousands in large files โ exponential slowdown
YARA-X tips:$_unused to suppress warnings; private $s to hide from output; yr check + yr fmt before every commit.
When to Use Modules vs. Byte Checks
Should I use a module or raw bytes?
โโ Need imphash/rich header/authenticode?
โ โโ Use PE module โ too complex to replicate
โโ Just checking magic bytes or simple offsets?
โ โโ Use uint16/uint32 โ faster, no module overhead
โโ Checking section names/sizes?
โ โโ PE module is cleaner, but add magic bytes filter FIRST
โโ Checking Chrome extension permissions?
โ โโ Use crx module โ string parsing is fragile
โโ Checking LNK target paths?
โโ Use lnk module โ LNK format is complex
Expert guidance: "Avoid the magic module โ use explicit hex checks instead" โ Neo23x0. Apply this principle: if you can do it with uint32(), don't load a module.
YARA-X New Features
Key additions from recent releases:
Private patterns (v1.3.0+): private $helper = "pattern" โ matches but hidden from output
# 1. Write initial rule# 2. Check syntax with detailed errors
yr check rule.yar
# 3. Format consistently
yr fmt -w rule.yar
# 4. Dump module output to inspect file structure (no dummy rule needed)
yr dump -m pe sample.exe --output-format yaml
# 5. Scan with timing infotime yr scan -s rule.yar corpus/
When to use yr dump:
Investigating what PE/ELF/Mach-O fields are available
Debugging why module conditions aren't matching
Exploring new modules (crx, lnk, dotnet) before writing rules
YARA-X diagnostic advantage: Error messages include precise source locations. If yr check points to line 15, the issue is actually on line 15 (unlike legacy YARA).
Chrome Extension Analysis (crx module)
The crx module enables detection of malicious Chrome extensions. Requires YARA-X v1.5.0+ (basic), v1.11.0+ for permhash().
Red flags:nativeMessaging + downloads, debugger permission, content scripts on <all_urls>
import "crx"
rule SUSP_CRX_HighRiskPerms {
condition:
crx.is_crx and
for any perm in crx.permissions : (perm == "debugger")
}
See crx-module.md for complete API reference, permission risk assessment, and example rules.
Android DEX Analysis (dex module)
The dex module enables detection of Android malware. Requires YARA-X v1.11.0+. Not compatible with legacy YARA's dex module โ API is completely different.
See style-guide.md for full conventions, metadata requirements, and naming examples.
Required Metadata
Every rule needs: description (starts with "Detects"), author, reference, date.
meta:
description = "Detects Example malware via unique mutex and C2 path"
author = "Your Name <email@example.com>"
reference = "https://example.com/analysis"
date = "2025-01-29"
String Selection
Good: Mutex names, PDB paths, C2 paths, stack strings, configuration markers
Bad: API names, common executables, format specifiers, generic paths
See strings.md for the full decision tree and examples.
strings:
// Category A: Library indicators
$a1 = "SRWebSocket" ascii
$a2 = "SocketRocket" ascii
// Category B: Behavioral indicators
$b1 = "SSH tunnel" ascii
$b2 = "keylogger" ascii nocase
// Category C: C2 patterns
$c1 = /https:\/\/[a-z0-9]{8,16}\.onion/
condition:
filesize < 10MB and
any of ($a*) and any of ($b*) // Require evidence from BOTH categories
Why this works: Different indicator types have different confidence levels. A single C2 domain might be definitive, while you need multiple library imports to be confident. Grouping by $a*, $b*, $c* lets you express graduated requirements.