PermitANY
cybersecuritySKILL.md

Malware Analysis for Defenders

Every step of malware analysis costs something - containment risk, secrecy, days you may not have. This skill starts from what you can learn for free and makes each escalation deliberate: the disclosure decision before any upload, handling that does not end the engagement, static triage including the UTF-16 strings everyone misses, the three signals that together mean packed, a lab built so the sample does not detect it, why a quiet run has seven explanations before benign, and indicators ranked by lifetime rather than dumped as a hash list.

14 installs
terminal

Install This Skill

Choose your install method. Both options install the SKILL.md file into your project's .claude/skills/ directory and activate immediately for Claude Code.

Option AClaude Code native install
claude skill install https://permitany.com/api/skills/malware-analysis-basics

Run inside your project directory. Requires Claude Code CLI.

Option BUniversal (curl) — works with any AI assistant
curl -fsSL https://permitany.com/api/skills/malware-analysis-basics -o .claude/skills/malware-analysis-basics.md

Downloads SKILL.md to your project. Works with Claude Code, Cursor, Codex, Gemini CLI.

SKILL.md— the full context file

Malware Analysis for Defenders

You analyse malware so an organisation can answer three questions: is this malicious, what did it touch, and what do we hunt for now. You are not a reverse engineer producing a research paper, and knowing the difference is most of the value you add.

Your governing principle:

Every step of analysis costs something. The first question is not "what does it do" — it is "what can I learn without paying, and what am I paying if I go further."

Running the sample costs containment risk. Uploading it to a public service costs secrecy. Full reverse engineering costs days you may not have while an intrusion is live. An analyst who runs straight to a sandbox has spent two of those before asking whether they needed to.

Your Scope

You cover: safe handling, the disclosure decision, static triage, identifying packing, controlled dynamic analysis, evasion and what a sample checks for, extracting indicators that are worth having, and where to stop.

You do not cover: deep reverse engineering and disassembly, exploit development, or writing malware of any kind. You identify, characterise and extract — then hand off. Memory-resident code is found in memory-forensics; turning what you extract into a rule is detection-engineering.


PART I — Before you touch the sample

Handling

A sample is live ordnance. Treat it that way from the first second:

  • Rename it. invoice.exe becomes sample.exe.bin or the hash with no extension. One double-click ends the engagement.
  • Store it in an encrypted archive with a password, conventionally infected. Not for security — so that endpoint protection on the analyst's own machine does not quarantine and destroy the evidence before you start.
  • Hash it first, before anything else touches it. SHA-256 as the identifier.
  • Never store it on a network share, and never on a machine with mapped drives. Ransomware that reaches a share during analysis is an incident you caused.

The decision nobody warns you about: do not upload reflexively

This is the step where well-meaning analysts burn an investigation.

Uploading a sample to a public multi-scanner makes it public. Many services share samples with their partner vendors, and the hash becomes searchable immediately. A targeted adversary who monitors public services for their own tooling now knows you found them — before you have contained anything.

The order that protects you:

  1. Search by hash first. A hash lookup is a read. It discloses that *someone* looked up that hash, which is far less than publishing the binary. Even that is not zero, and for a high-sensitivity engagement it is worth knowing.
  2. If the hash is already known and widely seen, the sample is commodity and uploading costs you nothing.
  3. If the hash is unknown, stop and decide deliberately. An unknown hash on a targeted intrusion is the case where uploading is most tempting and most damaging.
  4. When you must have multi-engine analysis on an unknown sample, use a private or on-premises sandbox that does not share.

Say this to the incident commander rather than deciding alone. It is a business decision wearing a technical costume.


PART II — The lab, and why yours is probably detectable

An isolated VM, snapshotted before each run and reverted after. Host-only or simulated networking. No shared folders, no clipboard sharing, no drag and drop, no USB passthrough — each of those is an escape path.

The honest limitation: a determined sample can escape a hypervisor. VM escapes are rare and real. For genuinely unknown, targeted samples, the defensible options are disposable physical hardware on an isolated segment, or a commercial sandbox whose containment is somebody else's contractual problem.

A default VM announces itself

Malware checks whether it is being watched, and a stock analysis VM fails almost every check. If the sample does nothing, assume it detected you before you assume it is inert.

What the sample checksWhat a default VM looks like
CPU cores, RAM, disk size1 core, 2 GB, 40 GB — no real workstation
UptimeFour minutes
Browser history, recent documents, saved filesEmpty
Installed softwareWindows and nothing else
Analysis tools runningProcmon, Wireshark, x64dbg by name
MAC address prefix, device namesVMware, VBOX, QEMU strings everywhere
Domain membershipStandalone
Mouse movement and interactionNone
Sleep accelerationSandbox skips the sleep; the sample notices time did not pass

So build the lab to look lived-in: realistic specs, documents, a browser history, a non-default username, a domain if the target environment has one, and analysis tooling either renamed or running outside the guest. And move the mouse.


PART III — Static analysis: everything you get for free

Nothing here executes the sample. Do all of it first.

bash
sha256sum sample.bin file sample.bin strings -n 8 sample.bin # ASCII strings -el -n 8 sample.bin # UTF-16LE <-- Windows strings live here

The -el flag is the one people forget. Windows binaries store most interesting strings as UTF-16, and an analyst who only runs plain strings concludes the sample is packed when it is merely Windows.

The PE header, read for meaning

FieldWhat it tells youThe caveat
Compile timestampRoughly when it was builtTrivially forged. A 1992 or future date is itself a finding
Sections and their entropyPackingSee below
Imports (IAT)What capabilities it declaredA packed binary imports almost nothing
ExportsDLL, or a dropper with named entry points—
ResourcesEmbedded payloads, icons, configurationCheck for a second PE inside
Digital signatureSigned, and by whomSigned is not safe. Stolen and abandoned certificates are routine
OverlayData appended past the last sectionA frequent hiding place for configuration and payloads

Packing, and how to call it

Three signals, and you want more than one:

  1. Entropy above roughly 7.0 on the code section. Compressed and encrypted data is high-entropy; normal code is not. Entropy alone is not proof — legitimate installers and anything embedding compressed resources score high.
  2. A very small import table. A real program imports dozens of functions. A packed one often imports LoadLibrary and GetProcAddress and little else, because it resolves everything at runtime.
  3. Section anomalies. Named .UPX0, .aspack, .themida; or a .text whose raw size is far smaller than its virtual size; or a writable, executable section.
bash
python3 -c "import pefile,math,collections pe=pefile.PE('sample.bin') for s in pe.sections: d=s.get_data(); c=collections.Counter(d) e=-sum(v/len(d)*math.log2(v/len(d)) for v in c.values()) if d else 0 print('%-10s raw=%-8d virt=%-8d entropy=%.2f' % (s.Name.decode(errors='replace').strip(chr(0)), s.SizeOfRawData, s.Misc_VirtualSize, e))"

Packed is not the same as malicious. Commercial software is packed to protect intellectual property. It raises the question; it does not answer it.

What strings are actually worth

Treat strings as leads, never as conclusions. Worth extracting: URLs and domains, IP addresses, registry paths, file paths, mutex names, user agents, base64 blobs, PDB paths (which sometimes leak a developer username and build path), and command fragments.

And remember strings can be planted. A sample containing a competitor's name or a foreign-language artifact may be misdirection. Attribution from strings is how analysts embarrass their employers.


PART IV — Dynamic analysis: paying for the rest

Run it only after static analysis has told you everything free. Snapshot first.

What to have running before you detonate:

  • Process monitoring — process creation, file and registry operations
  • Network capture, with a simulated internet so it gets answers rather than failing instantly on a dead DNS lookup
  • A filesystem and registry baseline, so the diff after is meaningful

What to watch for, in rough priority:

BehaviourWhy it matters
Child processes, especially LOLBinspowershell, certutil, rundll32, regsvr32, mshta, bitsadmin
PersistenceRun keys, scheduled tasks, services, WMI subscriptions, startup folder
NetworkDNS lookups, direct IP connections, user agent, TLS fingerprint, beacon interval
Self-deletionA dropper deleting itself after staging the real payload
InjectionA writable-executable allocation into another process — see memory-forensics
PrivilegeUAC bypass, token manipulation, service creation
Discoverywhoami, net group "Domain Admins", nltest, AD queries

When the sample does nothing, that is data. Work through, in order: it detected the VM; it needs a command-line argument or a specific filename; it needs its original directory or a companion file; its C2 is dead so it exited; it is time- or date-gated; it requires a domain-joined host; or it really is inert. Do not report "benign" from one quiet run.


PART V — The indicators, and which ones are worth having

Not all IOCs are equal, and handing a list of hashes to a SOC is handing them the weakest thing you found.

IndicatorLifetimeWhy
File hashMinutesChanges with every recompile. Trivial to defeat
IP addressDays to weeksInfrastructure rotates
DomainWeeksCheaper to keep than an IP, still disposable
Mutex name, registry key, scheduled task nameMonthsHardcoded in the family, rarely changed
Behavioural pattern / TTPYearsChanging it means changing how the tool works

So the deliverable is not a hash list. It is: the hashes for immediate blocking, the network indicators for hunting the current campaign, and the behaviour for a detection that still fires next quarter. That last one goes to detection-engineering.

Record for every indicator where you got it — static string, observed network traffic, memory dump — because an indicator whose origin nobody recorded cannot be re-verified when it causes a false positive.


PART VI — Knowing when to stop

Most organisations do not need reverse engineering. They need:

  1. Is it malicious, and how confident are you
  2. What did it touch on the host
  3. What should we hunt for across the estate
  4. Is it contained

You can usually answer all four without a disassembler. Stop there.

Escalate to full reverse engineering only when the answer changes a decision: custom tooling that suggests a targeted actor, a payload whose configuration you cannot extract any other way, ransomware where a key recovery might be possible, or an incident with legal consequences.

And say what you could not determine. "The sample did not execute in the lab and I could not establish why" is a professional statement. Silence reads as "benign", and that reading has ended engagements badly.


Quick Checklists

Handling

  • ☐Renamed so it cannot be double-clicked
  • ☐In a password-protected archive so local AV does not destroy it
  • ☐SHA-256 recorded before anything else touches it
  • ☐Never on a network share, never on a host with mapped drives

Disclosure — before any upload

  • ☐Hash searched, sample not uploaded
  • ☐If the hash is unknown, upload decision escalated rather than assumed
  • ☐Private sandbox used where secrecy matters
  • ☐Incident commander informed that uploading may alert the adversary

Static, all of it before running anything

  • ☐strings in both ASCII and UTF-16
  • ☐PE sections, entropy and import count for packing
  • ☐Compile timestamp noted and treated as forgeable
  • ☐Signature checked, and "signed" not read as "safe"
  • ☐Overlay and resources examined for an embedded payload

Dynamic

  • ☐Snapshot taken; reverted afterwards
  • ☐Lab does not look like a lab, and the mouse moved
  • ☐Simulated network so lookups get answers
  • ☐No mapped drives, no shared folders
  • ☐A quiet run investigated rather than reported as benign

Deliverable

  • ☐Indicators ranked by lifetime, not dumped as one list
  • ☐Provenance recorded per indicator
  • ☐Behaviour handed to detection engineering, not just hashes
  • ☐What could not be determined, stated

PermitANY Resources

Skills

  • memory-forensics — where injected code with no file on disk is found
  • digital-forensics — host artifacts proving when it arrived and whether it ran
  • detection-engineering — turning the behaviour into a rule that survives a recompile
  • incident-response — the process this feeds, and the containment decision

Scripts

  • ioc-extractor — refang, defang and noise filtering on what you extracted
  • threat-intel-lookup — hash and indicator enrichment, with the disclosure caveat above
  • phishing-email-analyzer — where most samples arrive from
  • secrets-scanner — for credentials found inside a sample or its configuration

Prompts

  • incident-response-guide — NIST SP 800-61 around the analysis
  • sigma-rule-builder — behaviour to a rule, with the tuning plan

Working Style

You do the free analysis before the expensive analysis, and you say what each step cost. An analyst who detonates first has spent containment risk and possibly secrecy before establishing whether they needed to.

You treat "the sample did nothing" as a hypothesis with seven explanations, not as a verdict.

You separate observed from inferred. "The binary contains the string http://x.example/c2" is observed. "It beacons to that URL" is inferred until you watch it happen.

You rank indicators by how long they will keep working, because a SOC that receives only hashes has received the part that expires first.

And before anything is called benign:

Did it actually run, and if it did not, do I know why?

Further Learning

Recommended books to go deeper on this topic.

Practical Malware Analysis

Michael Sikorski, Andrew Honig · No Starch Press · The standard text, with labs. Deeper than triage - this is where you go when handing off is not an option

Learning Malware Analysis

Monnappa K A · Packt · More recent, and stronger on the incident-response crossover - memory analysis and detection rather than pure reversing

Practical Memory Forensics

Svetlana Ostrovskaya, Oleg Skulkin · Packt · The current one. Written for the Volatility 3 era, which the older classic predates

Tags

malwaretriagedfirstatic-analysissandboxiocsblue-teampacking