YARA Rule Writing Guide
SkillFiles & storageUse when the user asks for a YARA rule, "write YARA for this sample/family", or `/hash-investigation` / `/malware-analysis` surfaces a sample worth a static-content rule. Pattern-matching rules for identifying malicious files.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the YARA Rule Writing Guide skill
What this skill tells your AI
The instructions your AI receives, as published by liberty91ltd/cti-skills in skills/yara-writing/SKILL.md and read by ahel’s review.
YARA rules identify and classify malware by matching byte patterns, strings, and conditions in files.
Rule Structure
rule RuleName : tag1 tag2 {
meta:
author = "CTI Platform"
date = "YYYY-MM-DD"
description = "Description of what this rule detects"
reference = "https://source-reference.com"
tlp = "GREEN"
mitre_attack = "T1566"
hash = "sha256_of_sample"
confidence = "high"
strings:
$text1 = "suspicious string" ascii wide
$hex1 = { 4D 5A 90 00 03 00 00 00 }
$regex1 = /https?:\/\/[a-z0-9\-\.]+\.onion/
condition:
uint16(0) == 0x5A4D and
filesize < 5MB and
(2 of ($text*) or $hex1) and
$regex1
}
String Types
Text strings
$s1 = "CreateRemoteThread" # Exact ASCII match
$s2 = "kernel32.dll" ascii wide # Match both ASCII and UTF-16
$s3 = "password" nocase # Case-insensitive
$s4 = "cmd /c" ascii wide nocase # Combined modifiers
$s5 = "C:\\Windows\\Temp\\" # Escaped backslashes
Hex strings
$h1 = { 4D 5A 90 00 } # Exact bytes (PE header)
$h2 = { 4D 5A ?? ?? 03 00 } # Wildcards (?? = any byte)
$h3 = { 4D 5A [2-4] 03 00 } # Jump (2-4 bytes between)
$h4 = { 4D 5A ( 90 00 | 00 00 ) } # Alternation (OR)
Regular expressions
$r1 = /https?:\/\/[\w\-\.]+/ # URL pattern
$r2 = /[A-Za-z0-9+\/]{50,}={0,2}/ # Base64 encoded content
$r3 = /(\d{1,3}\.){3}\d{1,3}/ # IP address pattern
Conditions
File properties
uint16(0) == 0x5A4D # PE file (MZ header)
uint32(0) == 0x464C457F # ELF file
uint32(0) == 0xBEBAFECA # Mach-O fat binary
filesize < 10MB # File size limit
String matching
all of them # All strings must match
any of them # At least one string
2 of ($text*) # At least 2 of $text group
3 of ($s1, $s2, $s3, $s4) # 3 of these 4 strings
$s1 at 0 # $s1 at offset 0
$s1 in (0..1024) # $s1 in first 1KB
#s1 > 3 # $s1 occurs more than 3 times
PE module (Windows executables)
import "pe"
pe.number_of_sections > 5
pe.imports("kernel32.dll", "VirtualAlloc")
pe.exports("DllRegisterServer")
pe.is_dll()
pe.timestamp > 1704067200 # Compiled after 2024-01-01
Best Practices
Do
- Start with a PE/ELF/file type check to limit scope
- Add a filesize constraint to avoid scanning large files
- Use unique strings — prefer byte sequences or specific API combinations over generic strings
- Combine multiple indicators (string + structure + behavior)
- Include metadata with reference to source intelligence
- Test against both malicious samples AND clean files (false positive testing)
Don't
- Match on single, common strings (e.g., just "http://" or "cmd.exe")
- Create rules without file type constraints (performance killer)
- Use overly broad regex patterns
- Forget to escape special characters in hex patterns
- Write rules that match on packer/crypter artifacts only (will match unrelated packed software)
Common Malware Patterns
Encoded PowerShell
rule Encoded_PowerShell_Execution {
meta:
description = "Detects base64 encoded PowerShell commands"
mitre_attack = "T1059.001"
strings:
$enc1 = "-EncodedCommand" ascii nocase
$enc2 = "-enc " ascii nocase
$enc3 = "FromBase64String" ascii nocase
$b64 = /[A-Za-z0-9+\/]{100,}={0,2}/ ascii
condition:
any of ($enc*) and $b64
}
Suspicious PE imports
import "pe"
rule Suspicious_Injection_Imports {
meta:
description = "PE with process injection API imports"
mitre_attack = "T1055"
condition:
pe.imports("kernel32.dll", "VirtualAllocEx") and
pe.imports("kernel32.dll", "WriteProcessMemory") and
pe.imports("kernel32.dll", "CreateRemoteThread")
}
Naming Convention
APT_<GroupName>_<MalwareName>.yar— For attributed malwareMAL_<MalwareName>_<Variant>.yar— For named malware familiesSUSP_<Behavior>_<Context>.yar— For suspicious behavior patternsHUNT_<Target>_<Technique>.yar— For threat hunting queries
Output Location
Write YARA rules to: data/detection-rules/yara/<malware-name>.yar
Validation against a real corpus
Before deploying a rule beyond your test set, validate it against a broader sample collection. When ReversingLabs Spectra Analyze is available:
/lookup-reversinglabs yara-matches <ruleset_name>— for a rule you have already deployed to RL, list the samples it has matched in the continuous-scanning corpus. Useful to confirm the rule isn't firing on goodware and to discover new variants caught by the same logic./lookup-reversinglabs search 'threatname:<family> classification:malicious' --max-results 100— before writing a family rule, retrieve a candidate sample set to test against. Then pull each sample's hashes for inclusion in your test suite./lookup-reversinglabs containers <hash>andextracted <hash>— find parents/children of a known sample to ensure the rule fires across the dropper-payload chain, not just on one layer.
Without RL access, fall back to retro-hunting via /lookup-virustotal (premium) and /lookup-otx pulse traversal.
Related skills
/hash-investigation,/malware-analysis— produce the structural and behavioural intel that informs the rule/lookup-reversinglabs— corpus validation, family pivots, parent/child relationships/lookup-virustotal,/lookup-otx— community detection signals and pulse-driven sample collection/sigma-writing— behavioural-detection counterpart for log telemetry
Signals
- GitHub stars
- 22
- Forks
- 9
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
yara-writing- Source
- github.com/liberty91ltd/cti-skills