Systematic malware triage and initial assessment workflow for professional malware analysis...
First phase for every sample. You run static tools on the host, interpret the output, classify the sample, and decide the next phase. Target: 5-15 minutes per sample.
R="${CLAUDE_PLUGIN_ROOT:-<dir containing this SKILL.md>}" once (when installed as a plugin $CLAUDE_PLUGIN_ROOT is set; otherwise it is this skill folder). Your working directory is the user's analysis workspace, so prefix every script path below with $R, e.g. python3 "$R"/scripts/ioc_extract.py.file, strings, pe_info.py, upx -d, 7z l, hashing. No chmod +x, no wine, no ./sample.malware-triage/scripts/pe_info.py, malware-triage/scripts/hash_calculator.py, scripts/ioc_extract.py. Resolve them from wherever this SKILL.md lives.command -v file strings upx 7z yara; python3 -c "import pefile" 2>&1 | tail -1
# pefile missing -> pip install pefile (needed by pe_info.py)
cat a strings dump. Save to a file, wc -l, then grep/head.S=/path/to/sample
file "$S"; ls -l "$S"
python3 malware-triage/scripts/hash_calculator.py "$S"
Record MD5/SHA1/SHA256, size, file output. Then route on the file output:
file says |
Action |
|---|---|
Mono/.Net assembly |
Record hashes, hand back to orchestrator โ specialized-file-analyzer (check this before PE) |
Microsoft Office, PDF document, ELF, MS Windows shortcut, Zip/RAR/7-zip, ISO 9660, Microsoft Disk Image, HTML document, script/text |
Record hashes, hand back to orchestrator โ specialized-file-analyzer |
PE32 / PE32+ (not .NET) |
Continue below |
data / unrecognized |
Continue at Unknown Files |
python3 malware-triage/scripts/pe_info.py "$S" # add --json for structured output
Read every section of the output. What matters:
| Output | Interpretation |
|---|---|
.NET: YES |
Stop, route to specialized-file-analyzer |
| Compile timestamp in the future / before 2000 | Forged; ignore for dating. Rich header linker info is harder to fake |
Overall entropy > 7.0, or executable section > 6.8, or ! markers |
Packed/encrypted โ see Packed Samples |
Entry point outside .text/CODE, or in last section |
Packer stub or appended code |
Import count < 10, or only LoadLibrary/GetProcAddress/VirtualAlloc |
Runtime API resolution โ packed or deliberately hiding imports |
| Suspicious import categories (injection, keylogging, network, anti-debug, crypto, persistence) | Map each to a capability; cross-check with references/indicators.md |
| Overlay present | Appended data: config, second-stage payload, or installer archive. Carve it: python3 -c "..." using the reported offset, then file the result |
| Signature present | Verify claimed signer; revoked/self-signed/mismatched = red flag. Unsigned is neutral |
| PDB path | Project/user names, build environment โ high-value attribution string |
| Resources with high entropy or large size | Embedded payload. Note type/size; extract in deep analysis |
| TLS callbacks | Code runs before entry point โ anti-debug or early unpacking |
| Version info mimicking Microsoft/Adobe/etc. while unsigned | Masquerading |
W=triage_$(basename "$S") # work dir
mkdir -p "$W"
strings -a -n 6 "$S" > "$W/strings_ascii.txt"
strings -a -n 6 -e l "$S" > "$W/strings_wide.txt" # UTF-16LE, essential for Windows binaries
wc -l "$W"/strings_*.txt
python3 scripts/ioc_extract.py "$W"/strings_*.txt # defanged IPs, domains, URLs, emails, hashes, reg keys, paths
Then targeted greps (adjust after reading the ioc_extract output):
grep -ihE 'HKEY_|HKLM|HKCU|CurrentVersion\\Run|schtasks|sc create|netsh|vssadmin|bcdedit|wmic' "$W"/strings_*.txt | sort -u | head -40
grep -ihE 'user-agent|mozilla/|POST |GET |Content-Type|\.php|\.onion|/gate|/panel' "$W"/strings_*.txt | sort -u | head -40
grep -ihE 'mutex|Global\\|Local\\|\\pipe\\' "$W"/strings_*.txt | sort -u | head -20
grep -ihE 'IsDebuggerPresent|VMware|VBox|vbox|QEMU|Xen|sandbox|SbieDll|wireshark|procmon|ollydbg|x64dbg' "$W"/strings_*.txt | sort -u
grep -ihE 'bitcoin|monero|\.onion|decrypt|ransom|your files|README' "$W"/strings_*.txt | sort -u | head -20
grep -ihE '\.exe|\.dll|\.bat|\.ps1|\.vbs|\.tmp' "$W"/strings_*.txt | grep -viE 'kernel32|ntdll|user32|advapi32|msvcr|api-ms-win' | sort -u | head -40
Note what is absent too: a binary with network imports but no URL/IP strings is decrypting its config at runtime.
Suspicious-API and string categories: references/indicators.md.
Triggered by Step 3 entropy/import findings.
| Packer | Indicators | Unpack on host? |
|---|---|---|
| UPX | UPX0/UPX1 sections, UPX! in overlay |
Yes: upx -d "$S" -o "$W/unpacked.exe" |
| Themida / WinLicense | .themida, .winlicense sections, huge protected section |
No โ dynamic analysis |
| VMProtect | .vmp0/.vmp1 |
No โ dynamic analysis |
| ASPack / MPRESS / Petite / Enigma / Upack | named sections (.aspack, .MPRESS1, .petite, .enigma1, .Upack) |
Rarely โ dynamic analysis |
| Custom / unknown | high entropy, few imports, no known section names | No โ dynamic analysis |
If UPX unpacking succeeds: hash the unpacked file, re-run Steps 3-4 on it, record both hashes (packed = delivery artifact, unpacked = what matches families). If upx -d fails, the UPX header was tampered; treat as custom.
Set sophistication: known packer โ at least Moderate; commercial protector โ Advanced; custom packer โ Advanced/APT. Add "requires dynamic analysis to reveal imports/strings" to next steps.
Combine imports, strings, reputation, and context. Consult references/indicators.md for the patterns.
| Type | Typical evidence |
|---|---|
| Trojan / RAT / Backdoor | socket or WinHTTP + command dispatch strings, screen/keyboard APIs, persistence |
| Ransomware | Crypt* APIs, file enumeration, vssadmin delete shadows, ransom-note strings, wallet addresses |
| Infostealer | browser profile paths (Login Data, cookies.sqlite), wallet dirs, CryptUnprotectData, exfil URL |
| Dropper / Loader | small binary, high-entropy resource or overlay, URLDownloadToFile, WriteFile + CreateProcess, few other capabilities |
| Cryptominer | pool URLs (stratum+tcp://), xmrig, high CPU-related config strings |
| Worm | SMB/RPC APIs, network share enumeration, removable-drive checks |
Threat level: Critical (destructive, ransomware, APT) / High (data theft, full compromise) / Medium (limited capability, targeted) / Low (adware, PUP, commodity). Sophistication: Simple / Moderate / Advanced / APT-level, driven by protection, evasion, and custom code. Verdict: Malicious / Suspicious / Benign. Benign requires positive evidence (valid signature from a plausible vendor, expected imports for its stated purpose, reputation clean over time), not just absence of red flags.
Turn static evidence into a watch list for the dynamic phase. Each prediction names the evidence:
CreateRemoteThread + OpenProcess โ injection; CreateProcess + cmd/powershell strings โ LOLBin chain)?GetTempPath/SHGetFolderPath imported.socket/connect โ raw TCP; DnsQuery only โ DNS tunnelling/DGA), hard-coded C2 vs runtime-decrypted, likely beacon.malware-dynamic-analysis/references/anti_analysis_bypass.md).These predictions become the Procmon/Sysmon filters and the observation plan for malware-dynamic-analysis.
| Priority | When |
|---|---|
| Immediate | Unknown/undetected, incident-related, destructive capability, APT indicators, matches current threat intel |
| Standard | Known family variant, commodity malware with existing coverage |
| Low | Well-documented sample, adware/PUP, old, likely false positive |
Next phase: malware-dynamic-analysis for PE files that are packed, have runtime-resolved config, or need behavioral confirmation; detection-engineer + malware-report-writer directly when the sample is a known variant and static IOCs suffice; Benign closes the sample.
file returned data or something unhelpful:
xxd "$S" | head -20 # magic bytes, structure
strings -a -n 8 "$S" | head -50
python3 - "$S" <<'EOF' # single-byte XOR brute force for a hidden PE
import sys; b=open(sys.argv[1],'rb').read()
for k in range(1,256):
d=bytes(x^k for x in b[:4096])
if d[:2]==b'MZ' or b'This program cannot' in d: print(f"XOR key 0x{k:02x} reveals PE header")
EOF
Also check: base64 blob ([A-Za-z0-9+/]{100,}), gzip/zlib magic (1f 8b, 78 9c), reversed PE (ZM at end), shellcode (starts with fc e8 / e8 00 00 00 00 / 55 8b ec). Decode what you find, file the result, and re-route.
For N samples, do a quick pass on all before deep-diving any:
for f in samples/*; do
echo "== $f"; file "$f"; sha256sum "$f"
python3 malware-triage/scripts/pe_info.py "$f" 2>/dev/null | grep -E '^\.NET:|packed|imported functions'
done
Produce a ranking table (sample, type, packed, detections, priority, one-line reason), then run the full workflow on Immediate samples first.
analysis_state.md in the user's working directory using the orchestrator's structure: hashes, type, priority, classification, threat level, triage findings, IOCs (defanged), next-phase recommendation.## Triage Report โ [filename]
**Hashes:** MD5 โฆ / SHA1 โฆ / SHA256 โฆ **Size:** โฆ bytes **Type:** โฆ **Packed:** No | Yes (packer)
**Reputation:** VT x/y, family label(s), first seen โฆ | not checked
### Static Findings
- Compile time / linker / signature / PDB
- Sections + entropy (flag anomalies)
- Suspicious imports by category โ capability
- Notable strings: URLs, IPs, paths, registry, mutex, UA, commands
- Resources / overlay / TLS callbacks
### Classification
**Verdict:** Malicious | Suspicious | Benign **Type:** โฆ **Threat:** Critical | High | Medium | Low **Sophistication:** โฆ
**Capabilities:** โฆ
### Predicted Behavior
Process / Files / Registry / Network / Persistence / Evasion โ each with the evidence behind it
### Initial IOCs (defanged)
File: hashes, imphash, dropped names ยท Network: โฆ ยท Host: registry, paths, mutex
### Recommendation
**Priority:** โฆ **Next phase:** โฆ **Why:** โฆ
Before handing back: all three hashes; file type; packing status with evidence; imports categorized; strings run in both ASCII and UTF-16; IOCs extracted and defanged; classification with reasoning; predictions tied to evidence; state file updated.
references/indicators.md โ suspicious API imports, string patterns, behavioral indicators, packer signatures, classification patternsreferences/triage_checklist.md โ full checklist, decision tree, dynamic go/no-go criteria, tool referencescripts/pe_info.py โ PE header/section/import/resource/overlay/signature summary (needs pefile)scripts/hash_calculator.py โ MD5/SHA1/SHA256../scripts/ioc_extract.py โ IOC extraction and defanging from any text