secskills
secskills / defense / analyzing-malware

analyzing-malware

defense verified 2026-07-27

Analyze suspected malware safely — containment, static triage, sandboxed detonation, unpacking, capability and C2 extraction, IOC production, and YARA rule authoring. Use when handed a suspicious file, hash, or sample, when triaging an alert artifact, or when producing detection content from a specimen.

$ /plugin install secskills-defense $ /plugin install secskills-core

The analysis is the easy part. The part that goes wrong is containment: a sample detonated on a machine that can reach production, or an IOC published that burns an active investigation. Get the environment right first.

When to Use

When NOT to Use

this skill regardless of framing

sample) — use hunting-web-backdoors

finished intel product** — use producing-threat-intelligence

Containment: Do This Before Anything Else

ControlRequirement
HostDisposable VM or dedicated bare-metal, snapshot taken before execution
NetworkIsolated segment; simulated services (INetSim/FakeNet-NG) by default
SharesNo host folder sharing, no clipboard sharing, no mounted host drives
CredentialsNo real accounts, no domain join, no password manager
HandlingSample stored in a password-protected archive, extension neutered (.bin, .mal)
EgressReal internet only with an explicit decision and a plan for attribution leakage

Live C2 contact tells the operator you are looking. On an active incident, do not resolve the C2 domain, submit the hash publicly, or upload the sample to a multi-scanner service until the incident lead approves it — public submission is a disclosure.

Static Triage — No Execution

# Identity, always first
sha256sum sample && file sample && du -h sample
# Fuzzy and import hashes for clustering against known families
ssdeep sample; tlsh sample   # Debian tlsh-tools ships /usr/bin/tlsh;
                             # built from upstream it is tlsh_unittest
python3 -c "import pefile;print(pefile.PE('sample').get_imphash())"

# Structure
pecheck sample                  # or: rabin2 -I / readelf -h
capa -v sample                  # capability detection mapped to ATT&CK — start here
floss sample                    # deobfuscated + stack strings, better than `strings`

# Packing and embedded content
binwalk -E sample               # entropy
binwalk -Me sample              # extract embedded objects

capa is the highest-value single command in this workflow: it turns a binary into a list of behaviours mapped to MITRE ATT&CK and MBC, which tells you whether deeper analysis is warranted at all.

Document-borne and script-borne samples:

oleid doc.xls && olevba --deobf doc.xls        # OLE macros
oledump.py doc.doc                              # stream-level inspection
msodde doc.docx                                 # DDE payloads
rtfobj doc.rtf                                  # embedded objects in RTF
pdfid file.pdf && pdf-parser -a file.pdf        # /JS /OpenAction /Launch

# Obfuscated scripts: normalize before reading
box-js payload.js
# PowerShell: decode -EncodedCommand, then unwrap the layers
echo '<base64>' | base64 -d | iconv -f UTF-16LE -t UTF-8

Most script malware is three layers of encoding around ten lines of logic. Deobfuscate mechanically rather than reading the obfuscated form.

Dynamic Analysis

Snapshot, detonate, observe, revert. Never analyze twice from a dirty state.

Baseline snapshot
  → start Procmon / Sysmon / inotify + tcpdump + INetSim
  → detonate with the right launcher (rundll32, wscript, mshta, Office)
  → observe 3-5 minutes, then interact (click, wait past sleep timers)
  → collect artifacts and memory
  → revert

What to collect and what each answers:

ArtifactToolAnswers
Process treeSysmon E1, Procmon, execsnoopInjection, LOLBin abuse, child spawns
File and registry writesProcmon, inotifywaitDrops, persistence, config
Networktcpdump, Wireshark, INetSim logs, mitmproxyC2 endpoints, beacon interval, protocol
MemoryDumpIt / procdump, then VolatilityUnpacked payload, injected code, keys
PersistenceAutoruns, systemctl list-units, cron, LaunchAgentsSurvival mechanism

Recover the unpacked payload from memory rather than fighting the packer:

# After the sample unpacks itself, dump and carve
vol -f mem.raw windows.malfind          # injected/RWX regions
vol -f mem.raw windows.dumpfiles --pid <pid>

Watch for sleep and evasion gates: many samples idle for minutes, check for a domain-joined host, count CPU cores, or look for analysis processes. If nothing happens, patch the check or hook Sleep/NtDelayExecution with Frida before concluding the sample is inert.

Capability Model

Structure findings against ATT&CK rather than as a narrative:

For each, record the concrete evidence (address, API call, artifact) that supports the claim. A capability asserted without evidence is a guess, and guesses in a malware report drive bad response decisions.

Configuration and C2 Extraction

The config is the most valuable output — it feeds blocking, hunting, and attribution.

# Known families: use the community extractors first
python3 -m maco.extract sample          # MACO / CAPE / RATDecoders ecosystems
# Unknown: find the decode routine, then emulate it over the encrypted blob

Typical config contents: C2 URLs and fallbacks, campaign or botnet ID, RC4/AES key, mutex, sleep interval and jitter, install path, kill date. Extract all of them — campaign IDs and mutexes are often better hunting pivots than the C2, which rotates.

IOC and Detection Output

Rank indicators by how long they survive and how specific they are:

Hash            → precise, dies immediately (recompile)
C2 IP/domain    → useful now, rotates in days
Mutex / config  → survives rotation, family-specific
Behaviour/TTP   → survives redevelopment; write these

Write YARA against structure and code, not incidental strings:

rule Family_Loader_ConfigDecode
{
    meta:
        author      = "analyst"
        date        = "2026-07-26"
        description = "Loader config RC4 decode stub"
        hash        = "<sha256>"
        reference   = "<internal case id>"
    strings:
        // The decode loop's constants, not a filename it happens to drop
        $decode = { 8A 04 0? 32 0? 88 0? 4? 3B ?? 72 }
        $mutex  = "Global\\<family-specific>" ascii
    condition:
        uint16(0) == 0x5A4D and filesize < 2MB and all of them
}

Validate every rule before it ships:

yara -w rule.yar ./samples/family/      # must hit all known-true samples
yara -w rule.yar ./corpus/goodware/     # must produce zero hits — this step is not optional

Hand behavioural detections to engineering-detections for Sigma/EDR conversion and tuning.

Rationalizations to Reject

verdict with a suspicious file is a reason to analyze harder, not to close.

disclosure to the adversary and possibly to your customer's competitors. Decide deliberately.

Confirm with code or config similarity before you inherit that family's attribution and playbook.

on a date, and dead-drop resolvers before concluding.

Deliverable

ATT&CK Coverage

Generated from secskills-core/ttp-index.json — edit that file, then run python3 scripts/sync_attack.py --write. Re-verify IDs against the current ATT&CK release before citing them in a report.

Resource Development (TA0042)

Initial Access (TA0001)

Execution (TA0002)

Privilege Escalation (TA0004)

Defense Evasion (TA0005)

Collection (TA0009)

Command and Control (TA0011)

Impact (TA0040)

Detection content for any of these: engineering-detections. Proactive search: hunting-threats. Post-compromise: responding-to-incidents.

References