# Reverser Malware Triage

> Fast malware triage workflow — static (PE/Mach-O/ELF format, strings, imports, signatures, entropy/packed indicators), dynamic (sandbox with INetSim, Wireshark, Process Monitor, Procmon, time-shift), unpack (Scylla/PE-sieve), then full RE with Ghidra/IDA. Designed for ≤15 min initial verdict.

- Skill: `purpleailab/reverser-malware-triage` (Agent Skill)
- Install (CLI): `npx skillmds@latest add purpleailab/reverser-malware-triage`
- Raw SKILL.md: https://api.skillmd.com/api/skills/purpleailab/reverser-malware-triage/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: purpleailab (https://skillmd.com/u/purpleailab)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/purpleailab/reverser-malware-triage

---


# Malware Triage — 15 minute first verdict

You have a suspicious binary. Goal: in 15 minutes, decide CLEAN / SUSPICIOUS / MALICIOUS / NEEDS-DEEPER.

## Phase 1: Static (5 min)

```bash
# 1. File format
file sample.bin
exiftool sample.bin                 # author / compile timestamp / version

# 2. Hash + reputation
sha256sum sample.bin
# Submit to: VirusTotal, MalwareBazaar, IntelX, Joe Sandbox, ANY.RUN
# Often the verdict already exists — saves you 14 minutes.

# 3. Strings — fast triage signal
strings -n 8 sample.bin | sort -u | head -100
strings -e l -n 8 sample.bin | sort -u | head -50   # wide (UTF-16) strings on Windows

# Suspicious strings to grep for:
strings sample.bin | grep -iE 'http|https|wmic|powershell|cmd.exe|temp|appdata|amsi|defender|reflectiveloader'

# 4. Format-specific: PE
peresearcher sample.exe   # OR python pefile
python3 -c '
import pefile
p = pefile.PE("sample.exe")
print("Compile time:", p.FILE_HEADER.TimeDateStamp)
print("Sections:", [(s.Name.decode().rstrip("\x00"), s.SizeOfRawData, s.get_entropy()) for s in p.sections])
print("Imports:", [(e.dll.decode(), [i.name.decode() if i.name else hex(i.ordinal) for i in e.imports]) for e in p.DIRECTORY_ENTRY_IMPORT])
'

# 5. Entropy → packed?
python3 -c '
import math
data = open("sample.bin","rb").read()
counts = [data.count(bytes([b])) for b in range(256)]
total = len(data)
ent = -sum((c/total)*math.log2(c/total) for c in counts if c)
print(f"Entropy: {ent:.3f} / 8 — {'packed' if ent > 7.5 else 'normal'}")
'

# 6. YARA against canonical rulesets
yara -r /opt/yara-rules/ sample.bin
yara -r /opt/Neo23x0-signature-base/ sample.bin
```

## Phase 2: Dynamic (5 min — in an isolated VM)

```bash
# Pre-flight (do this once, save snapshot)
# - Disconnected network OR use INetSim/FakeNet-NG to fake services
# - Procmon recording (Process / File / Network / Registry filters)
# - Wireshark capturing on the snapshot's network adapter
# - Fakedns / inetsim listening for DNS / HTTP / SMTP / FTP

# Detonate
cp sample.bin C:\tmp\sample.exe
# Right-click → Run as admin OR sample.exe in cmd

# Observe for 60-180 seconds, then take snapshot
# Then revert VM for next run
```

### Things to look for

| Signal | Verdict |
|---|---|
| Writes to `\AppData\Local\Temp` then executes | Likely dropper |
| Creates Run/RunOnce registry key | Persistence |
| Schedules a task | Persistence |
| Modifies firewall via netsh | Defense evasion |
| Spawns powershell + LongStringEncoded | Stage 2 |
| Network: HTTPS to a no-SNI IP | C2 callback |
| DNS to a DGA-looking domain | C2 callback |
| Reads process memory of lsass.exe / winlogon.exe | Credential theft |
| Writes to userinit / shells / image-file-exec-options | Persistence |
| Touches `\Microsoft\Cryptography\Defaults\Provider` | Cert injection |

## Phase 3: Unpack (if entropy was high, optional 5 min)

```bash
# In dynamic VM, after detonation, dump memory:
# Scylla (UI) → attach to process, dump PE image
# OR PE-sieve (command-line):
pe-sieve.exe /pid 1234 /dir dumped
# OR DnSpy + DotNetReactorUnpacker for .NET
# OR de4dot for obfuscated .NET

# Then static-re the unpacked binary (Phase 1 strings/imports against the dump)
```

## Phase 4: Verdict + handoff

| Verdict | Indicators | Next step |
|---|---|---|
| **CLEAN** | Known-good hash, signed, expected strings/imports, no suspicious behavior | Mark + move on |
| **SUSPICIOUS** | Unsigned, low rep, mildly unusual imports/strings, no clear malicious behavior | Sandbox 30 min longer, YARA against custom rules |
| **MALICIOUS** | C2 callback, drops files, persistence, credential theft, packed + evades VMs | IOC extraction, then deep RE (load `reverser/ghidra/SKILL.md`) |
| **NEEDS-DEEPER** | High entropy, anti-analysis, custom-packed, no obvious signal | Unpack first (Phase 3), then re-triage |

## IOC extraction template

If MALICIOUS:
- Hashes (md5, sha1, sha256)
- C2 domains / IPs (from PCAP)
- Mutex names (Procmon: CreateMutex events)
- File paths created
- Registry keys modified
- YARA signature (generate from unique strings/code)

## Tooling cheatsheet

| Stage | Tool | Use |
|---|---|---|
| Static (PE) | pefile, capa, exiftool, Detect It Easy (DIE) | Format + capability scan |
| Static (ELF) | readelf, objdump, radare2 | Format + symbols |
| Static (Mach-O) | jtool2, otool, MachOView | Format + symbols |
| Dynamic | Cuckoo, CAPE, ANY.RUN, Joe Sandbox, Hatching Triage | Automated sandbox |
| Network | Wireshark, mitmproxy, FakeNet-NG, INetSim | Traffic capture + fake services |
| Memory | Volatility 3, PE-sieve, Scylla | Memory forensics + unpacking |
| Disassembly | Ghidra, IDA, Binary Ninja | Full RE — see `reverser/ghidra/SKILL.md` |
| YARA | yara, capa rules | Signature matching |

## References

- "Practical Malware Analysis" — Sikorski & Honig (still the canonical book)
- MITRE ATT&CK — for behavior → technique mapping
- Lenny Zeltser's "REMnux" — pre-built malware analysis distro
- DEFCON "Malware Forensics" track recordings

