Cheat sheet — Malware Artifacts in IR¶
Companion to Module 12 — Malware Artifacts in IR · CC BY 4.0 — print it, pin it, share it.
Last reviewed: 2026-07
capa — static capability profiling (no execution)¶
capa suspicious.exe # map code → named capabilities + ATT&CK techniques
capa -v suspicious.exe # verbose: show the rule + code location for each match
capa -vv suspicious.exe # very verbose: every matched feature (for tuning rules)
capa -j suspicious.exe > caps.json # JSON output for tooling / AI review
capa -r ./capa-rules suspicious.exe # use a specific rules directory
- capa reads the binary and matches patterns against hundreds of rules. Output is "has the code to do X", not "is malware" — a benign installer can have "modify registry" too.
capa — what to check first in triage¶
Persistence "persist via ... Run key / scheduled task / service"
Communication "communicate over HTTP / DNS", "connect to URL"
Anti-analysis "check for debugger", "detect sandbox", "resolve API at runtime"
Execution "create process", "execute via rundll32"
Credential access "steal credentials", "read LSASS"
YARA — rule anatomy¶
rule Latrodectus_Loader_Example
{
meta:
author = "you"
description = "Characteristic of the Latrodectus loader"
reference = "<report/hash>"
date = "2026-07-11"
strings:
$s1 = "update-cdn82.net" ascii wide // exact C2 host
$s2 = { 6A 40 68 00 30 00 00 } // byte pattern (hex)
$s3 = /[a-z0-9]{8}\.exe/ nocase // regex
condition:
uint16(0) == 0x5A4D and // PE magic "MZ"
pe.imports("kernel32.dll","CreateRemoteThread") and
2 of ($s*)
}
YARA — scan and test¶
yara rule.yar suspicious.exe # match a single file
yara -r rule.yar /samples/ # -r recurse a directory
yara -s rule.yar suspicious.exe # -s print the matched strings + offsets
yara -c rule.yar /benign/ # -c count matches — run against BENIGN set to check FPs
yara -w rule.yar file # -w suppress warnings
String/condition building blocks¶
"text" ascii wide nocase text string; wide = UTF-16, nocase = case-insensitive
{ E8 ?? ?? ?? ?? } hex with wildcards (?? = any byte)
/regex/ regular expression
uint16(0) == 0x5A4D PE "MZ" header check
pe.imports("dll","Func") import-based anchor (needs: import "pe")
filesize < 500KB size bound
N of ($s*) / all of them / any of them
The IR workflow¶
capa (triage: what CAN it do?) → scope containment (block outbound, isolate, hunt persistence)
↓
YARA (turn the sample into a hunt/IOC) → threat-intel share + EDR retroactive search
↓
join with execution + network evidence → "can" becomes "did"
Gotchas worth remembering¶
- "Can" is not "did." capa reports capability, not exercise — a binary with network code may
have made zero connections. Report "can phone home" until you join it to a
conn.logsession and an execution record (prefetch, 4688); then it's "phoned home at 14:21." - YARA lives or dies on its conditions. Too specific (a string lifted verbatim) misses the next variant; too broad (one common string) fires on thousands of benign files. Anchor to imports or sections and tune to your FP tolerance.
- Always test against a benign set first (
yara -cover known-good files). A rule that fires on every UPX-packed installer or PDF viewer is a noise machine, not an IOC. - capa is static and safe — no sandbox, no execution, no infection risk. It's the right first pass before anyone thinks about detonating the sample.
- AI-drafted YARA is usually overfit or too broad. Review every condition, confirm it matches the target and clears the benign set, before you ship it.
Comments
Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).