| name | malware-analysis |
| description | Analyze suspicious files, executables, and samples for malicious behavior using the Practical Malware Analysis methodology (Sikorski & Honig), orchestrated through the REMnux MCP server. Use whenever the user asks to triage, reverse-engineer, analyze, investigate, unpack, or figure out what a binary does — PE (.exe/.dll/.sys), ELF, Mach-O, script, Office doc, PDF, archive, or raw shellcode. Covers the full four-layer methodology — basic static (hashes, strings, PE/ELF headers, imports, packing), basic dynamic (sandbox/Procmon/FakeNet), advanced static (Ghidra/IDA disassembly), and advanced dynamic (x64dbg debugging, unpacking, anti-analysis bypass). Produces IOC extraction, MITRE ATT&CK TTP mapping, host- and network-based detections, and analyst reports with STIX 2.1 output for OpenCTI ingestion. Trigger even for low-signal phrasings like 'what is this file', 'is this malicious', 'I got this dropper', or 'pulled this off a workstation'. |
Malware Analysis
A structured workflow for analyzing suspicious files using the methodology from Practical Malware Analysis (Sikorski & Honig, No Starch 2012), adapted for modern blue-team operations and the REMnux MCP server.
Core philosophy
Malware analysis exists to answer three operational questions, in priority order:
- What host-based indicators does this leave? — files created, registry keys written, mutexes, services, scheduled tasks. Used by EDR/SIEM detection.
- What network-based indicators does it produce? — domains, IPs, URIs, user-agents, protocol quirks, C2 patterns. Used by NDR/firewall/proxy detection.
- What is its purpose and capability? — what it can do, what it's designed for, who likely operates it. Used by IR scoping, threat intel, and exec reporting.
Everything else is a means to those ends. Don't get lost in disassembly when a string dump answers the question. Don't run dynamic analysis when a sandbox report already covers it.
Rules of engagement (from Chapter 0)
- Don't get stuck in the weeds. Malware is big and messy. Focus on key features; skim the rest.
- Use multiple tools. If one tool doesn't reveal something, another will. Overlap is fine.
- Hypothesize, then confirm. Guess what the sample does based on early signals (strings, imports, filename, delivery context), then verify. This is dramatically faster than blind analysis.
- It's cat-and-mouse. Samples that detect VMs, debuggers, and analysts evolve constantly. Expect resistance and plan to bypass it.
Safety first
Always assume the sample is live and hostile. Before anything:
- Run analysis inside an isolated VM or REMnux container. Never on a host with credentials, corporate network access, or anything you'd hate to lose.
- Snapshot before detonation. Revert after each dynamic run.
- Disconnect or fake the network. Use INetSim, FakeNet-NG, or a sinkholed host-only network. Do not let unknown samples reach real C2 unless that's an explicit goal coordinated with the SOC.
- Never double-click. Launch through
rundll32, explicit CLI, or the sandbox harness.
- Handle DLLs deliberately. DLLs don't run standalone — use
rundll32.exe sample.dll,ExportName or modify the PE header to strip the IMAGE_FILE_DLL flag.
If the caller hasn't confirmed an isolated environment, ask before proceeding to any dynamic step.
The four-layer methodology
Analysis escalates through four layers. Do not skip layers, and do not escalate without reason. Stop at the layer that answers the operational question.
| Layer | What it tells you | Cost | Limitations |
|---|
| 1. Basic static | Is it malicious? What family? What APIs? Packed? | Minutes | Defeated by packing/obfuscation |
| 2. Basic dynamic | What does it actually do on a system? | ~15–30 min | Misses code paths not taken, anti-sandbox |
| 3. Advanced static | Exact logic of specific functions | Hours | Requires RE skill, defeated by obfuscation |
| 4. Advanced dynamic | Internal state during execution, bypass anti-analysis | Hours | Requires debugging skill and anti-anti-analysis |
Workflow
Before the first tool call
Establish:
- Where is the sample? Path on disk, hash, or URL to fetch. If not local, use
remnux:download_from_url or remnux:upload_from_host.
- What's the operational goal? Triage a single incident? Build detections? Attribute to an actor? This sets depth.
- What's already known? Has it been in a public sandbox? Hash matches on VT? Delivery vector (phishing, drive-by, lateral)?
- What's the environment? REMnux only (Linux + static tools, limited Windows PE detonation), or REMnux + a Windows sandbox VM for dynamic?
Then proceed layer by layer.
Layer 1 — Basic static triage
The cheapest, fastest information. Always do this first. Use scripts/triage.py to orchestrate most of it in one shot.
Step 1 — Identify. Use remnux:get_file_info to get SHA256/MD5/SHA1 hashes and file type. File type drives every subsequent decision — a PE32 is handled differently from an ELF or a VBA-laden Office doc.
Step 2 — Multi-AV lookup. Search the hash on VirusTotal (out-of-band) or internal TI platforms. A detection name like Trojan.Win32.Emotet or Backdoor.Cobalt immediately focuses all subsequent analysis. If the hash is unknown and the sample may be targeted, don't upload the binary — just check the hash.
Step 3 — Strings. Use remnux:run_tool with strings (both ASCII and wide/Unicode — strings -e l for 16-bit little-endian). Also try floss (FireEye Labs Obfuscated String Solver) which deobfuscates stack and stack-allocated strings that plain strings misses.
Read the strings with intent. Hunt for:
- URLs, domains, IP addresses
- File paths (
C:\Windows\..., %APPDATA%\..., /tmp/...)
- Registry keys (esp.
Run, RunOnce, Services, Winlogon\Notify, Image File Execution Options)
- Error messages (often unintentional — reveals feature intent, e.g., "Mail system DLL is invalid")
- User-Agent strings, HTTP verbs, protocol fragments
- Mutex names (common malware-family signal)
- Function names suggesting intent (
KeyLogger, Install, Beacon)
See references/static-indicators.md for red-flag patterns.
Step 4 — Packing check. Run remnux:run_tool with peid, die (Detect It Easy), or pescan. Very short string output + tiny imports = almost certainly packed. If packed, note the packer (UPX, ASPack, Themida, VMProtect, etc.) and proceed differently — simple UPX can be unpacked in-place with upx -d; advanced packers require Layer 4.
Step 5 — PE headers and imports (for Windows PE). Run remnux:run_tool with pefile, peframe, or pestudio (if available). Extract:
- Compile timestamp — sanity-check against delivery date (authors sometimes back-date, but forward-dated timestamps are suspicious)
- Section names and entropy —
.UPX0, .aspack, randomly-named sections, sections with entropy > 7.0 = packed/encrypted
- Imports by DLL — which Windows DLLs are loaded and which functions are called
- Exports — named exports like
ServiceMain, DllRegisterServer, Wlx* (GINA replacement) reveal intent
- Resources — embedded binaries, icons, manifests; check
.rsrc entropy
The import table is the single richest static signal. See references/windows-apis.md for how to interpret specific function imports. A handful of imports reveal common malware behavior at a glance:
URLDownloadToFile + WinExec / ShellExecute → downloader
CreateRemoteThread + VirtualAllocEx + WriteProcessMemory → process injection
SetWindowsHookEx + GetAsyncKeyState / GetKeyState → keylogger
CreateService / StartServiceCtrlDispatcher → persistence as service
RegSetValueEx targeting Run / RunOnce → registry-based persistence
InternetOpen + InternetReadFile or WSAStartup + connect → network C2
CryptAcquireContext + CryptEncrypt → encryption (ransomware or C2 crypto)
SamIConnect + SamIGetPrivateData → credential dumping
LoadLibrary + GetProcAddress with very few other imports → runtime linking / likely packed
- Exports starting with
Wlx* → GINA replacement / credential theft
Step 6 — Non-PE samples. For ELF use readelf, nm, ltrace/strace. For Office docs use oleid, olevba, oledump. For PDFs use peepdf, pdf-parser, pdfid. For scripts (JS/VBS/PS1) use deobfuscators (box-js, JSDetox, PowerShell AMSI trace). REMnux has all of these — use remnux:suggest_tools with the file type to see what's available.
Step 7 — Form a hypothesis. Based on Layers 1.1–1.6, write a one-sentence hypothesis: "This sample appears to be a downloader that fetches a secondary payload from a hardcoded URL and establishes registry-based persistence." Everything downstream confirms, refines, or refutes that hypothesis. If the hypothesis fully answers the operational question, stop here.
Layer 2 — Basic dynamic observation
Used when static analysis hits a wall (packing, runtime-resolved imports) or when you need to see actual behavior (what does it do, not what it can do).
Important caveat: REMnux runs Linux. For Windows PE dynamic analysis you need either:
- A connected Windows sandbox VM (Cuckoo, CAPE, FLARE-VM, or a snapshotted manual VM), OR
- A cloud sandbox (Joe Sandbox, ANY.RUN, Triage, VirusTotal, CrowdStrike Falcon Sandbox) — these produce rich reports that often suffice.
REMnux is appropriate for Linux ELF samples, scripts, and documents detonated in controlled interpreters.
Step 1 — Sandbox submission (preferred when available). Submit to CrowdStrike Falcon Sandbox or equivalent; read the report for process tree, file writes, registry changes, network destinations, and dropped files. A good sandbox report is Layer 2 done. Note the limitations: sleep-skipping is imperfect, detect-and-bail is common, command-line args aren't always provided.
Step 2 — Manual detonation harness (when needed). On the Windows analysis VM:
- Procmon (Sysinternals) with filters:
Process Name is <sample>, Operation includes RegSetValue, CreateFile, WriteFile, TCP Connect. Run for bounded time — Procmon can consume all RAM if left alone.
- Process Explorer running — watch for child processes and injected processes. A mismatch between on-disk strings and in-memory strings (compared via Process Explorer's Strings tab) indicates process replacement/hollowing.
- Regshot snapshot before and after detonation
- Wireshark capturing on all isolated interfaces
- INetSim or FakeNet-NG on a Linux VM on the same isolated network — fakes DNS, HTTP, HTTPS, SMTP, FTP, and more
Run for 3–10 minutes, longer if the sample sleeps or waits. Kill, revert, repeat with tweaks as needed (different user privileges, different OS version, with/without admin, with/without faked Internet).
See references/dynamic-indicators.md for what to look for in each tool's output.
Step 3 — IOC extraction. From dynamic output, extract:
- Files created/modified/deleted (absolute paths, hashes)
- Registry keys and values (persistence mechanisms especially)
- Mutexes created (high-value host indicators — often globally unique strings)
- Services installed
- Scheduled tasks
- DNS queries, IPs contacted, full HTTP requests (URL, headers, body)
- Process tree (parent → child relationships, injected processes)
Use scripts/ioc_formatter.py to convert these into STIX 2.1 SDOs for OpenCTI ingestion.
Layer 3 — Advanced static (disassembly / RE)
Used when: dynamic analysis can't reveal a specific code path, the sample is packed and needs unpacking logic understood, or you need to precisely document what a function does for detection/attribution.
Tools: Ghidra (free, scriptable — preferred default), IDA Pro (commercial, industry standard), Binary Ninja, radare2/rizin/Cutter.
Workflow:
- Load the binary. If packed, unpack first (Layer 4 technique or
upx -d for UPX).
- Start at the entry point. Trace calls to identify the main function.
- Rename functions as you identify them (
sub_401000 → decrypt_config, etc.). Keep the IDB/GPR alive across sessions.
- Focus on the imports you flagged in Layer 1. Cross-reference every call site — that's where the interesting logic sits.
- Decode strings, keys, and config blocks. Malware commonly XOR-encodes strings with a single byte or short repeating key.
- Map out the C2 protocol: how is beacon data structured? How is the response parsed? What commands does it support?
See references/advanced-static.md for disassembler workflow, finding main, recognizing C constructs in assembly (if/else, loops, switches, structs), and decoding common obfuscation. See references/windows-apis.md for API behavior and parameter meaning.
Use Ghidra's script engine or IDA Python to automate repetitive deobfuscation (XOR loops, string decoders, import resolution).
Layer 4 — Advanced dynamic (debugging)
Used when: the sample is packed and won't unpack cleanly, anti-analysis is defeating static or basic dynamic, you need to step through a specific code path (e.g., a C2 decrypt routine with a live packet), or you need to dump the unpacked binary from memory.
Tools: x64dbg/x32dbg (free, modern, Windows), OllyDbg 2.x (legacy but still useful, Windows), WinDbg (kernel + user, Windows), gdb + gef/pwndbg (Linux ELF).
Common tasks:
- Generic unpacking. Set a breakpoint at common tail-jump patterns or memory-write-then-exec transitions (
VirtualAlloc + WriteProcessMemory + new EIP). When execution reaches the original entry point (OEP), dump the process with Scylla/Process Dump and rebuild imports.
- Bypass anti-debug. Patch
IsDebuggerPresent / CheckRemoteDebuggerPresent / NtQueryInformationProcess return values. Use plugins like ScyllaHide or TitanHide that handle common PEB flags and timing checks automatically.
- Bypass anti-VM. Modify VMware registry artifacts, MAC address, process names, disk identifiers. See
references/anti-analysis.md.
- Stepping through C2. Set breakpoints on
send / recv / InternetReadFile to capture plaintext before encryption or after decryption.
For kernel-mode malware (rootkits, bootkits), use WinDbg kernel debugging with two VMs (debugger VM + target VM) connected over a named pipe.
See references/advanced-dynamic.md for the full debugging workflow: pre-flight anti-debug scrubbing, canonical API breakpoints by goal (finding C2 URL, crypto keys, injection targets), generic manual unpacking procedure, process dumping with Scylla, Frida instrumentation, and kernel debugging setup.
Recognizing malware behavior
Once you've observed behavior (static or dynamic), map it to a malware category and to MITRE ATT&CK techniques. See references/behavior-patterns.md for category fingerprints and references/windows-apis.md for API-to-ATT&CK mapping.
Common categories: backdoor, RAT, downloader, launcher/loader, credential stealer, keylogger, rootkit, ransomware, wiper, banker, infostealer, cryptominer, worm. Samples often combine categories — don't force a single label if the evidence points to multiple.
Handling anti-analysis
If the sample actively resists analysis — tiny imports, high entropy, crashes on launch in a VM, sleeps for hours, checks for debugger — consult references/anti-analysis.md. It covers anti-disassembly tricks (jump-into-instruction, opaque predicates, ret-chains), anti-debug (PEB flags, timing checks via GetTickCount/rdtsc, OutputDebugString, FindWindow for OllyDbg), anti-VM (VMware artifacts, CPU instructions like SIDT/SLDT, MAC address prefixes), and packer strategies.
Producing the report
After analysis, always produce a structured report. Downstream ecosystems (OpenCTI, detection engineering, exec briefings) depend on it, so do not skip this step.
Use the template in references/report-template.md. The template has:
- Executive summary (2–3 sentences, non-technical)
- Identification (hashes, file type, size, compile time, first-seen)
- Capabilities (categorized, mapped to ATT&CK)
- Host-based indicators (files, registry, mutexes, services, tasks)
- Network-based indicators (domains, IPs, URIs, User-Agents, protocol quirks)
- Persistence mechanism(s)
- Detection opportunities (Sigma / Splunk SPL / CrowdStrike CQL ideas)
- Analyst notes (confidence, caveats, gaps)
- Appendix (strings, interesting code snippets, references)
For machine-readable output, run scripts/ioc_formatter.py to emit STIX 2.1 SDOs.
Scripts
scripts/triage.py — orchestrates the Layer 1 static triage over REMnux MCP: hashes, file type, strings, PE headers, imports, packing check, and a first-pass hypothesis. Start here for any new sample.
scripts/ioc_formatter.py — takes extracted IOCs (hashes, domains, IPs, URLs, file paths, registry keys, mutexes) and produces STIX 2.1 JSON (Indicator, Malware, Relationship SDOs) ready for OpenCTI ingestion.
Both scripts accelerate the mechanical parts; they don't replace analyst judgment.
Deep-dive references
Load on demand — don't front-load them. The workflow above is self-contained for most triage work.
references/static-indicators.md — suspicious string patterns, PE header red flags, high-entropy section interpretation, import combinations by intent
references/dynamic-indicators.md — Procmon/ProcExp/Regshot/Wireshark interpretation; INetSim and FakeNet-NG usage
references/windows-apis.md — categorized Win32 API reference with MITRE ATT&CK mapping
references/behavior-patterns.md — malware category fingerprints (APIs, strings, behavior signatures)
references/advanced-static.md — disassembler workflow, finding main, recognizing C constructs
references/advanced-dynamic.md — debugging workflow, API breakpoints, unpacking, process dumping
references/anti-analysis.md — anti-disassembly, anti-debug, anti-VM, packer detection and bypass
references/report-template.md — standard analyst report format