Behavior & Triage
Learning Objectives
- Run a fast static triage on an unknown sample
- Build a hypothesis from strings, imports, and metadata
- Know when to move from static to dynamic analysis
- Document findings as you go
- Classify malware family by capability profile
- Generate initial IOCs from static analysis
Triage Is Rapid Hypothesis
You have an unknown binary and no time to reverse it fully. Triage is the 10-minute scan that tells you where to focus.
The Triage Sequence
- File type & metadata —
file, hash it (SHA-256), note size and compile time. - Strings — URLs, registry keys, mutexes, PowerShell, suspicious paths.
- Imports — capabilities: network? injection? persistence?
- Sections/entropy — packed? RWX?
- Resources — embedded binaries, config, icons.
- Hypothesis — write it down: “likely a downloader that persists via Run key.”
Detailed Triage Checklist
1. File Identification
# Hashes
sha256sum sample.exe
md5sum sample.exe
# File info
file sample.exe
# PE32+ executable (GUI) x86-64, for MS Windows
# PE headers (with pefile, CFF Explorer, PE-bear)
# - Machine: 0x8664 (x64) or 0x14c (x86)
# - TimeDateStamp: compile time (may be forged)
# - Subsystem: GUI (2) vs Console (3)
# - DLL Characteristics: ASLR, DEP, CFG, etc.
2. Strings (Triaged)
# Full scan, both encodings
strings -a -n 6 sample.exe > strings_ascii.txt
strings -el -n 6 sample.exe > strings_unicode.txt
# Categorize immediately:
grep -iE "http|https|ftp" strings_ascii.txt # C2
grep -iE "run|runonce|service|startup" strings_ascii.txt # Persistence
grep -iE "global\\|local\\|mutex" strings_ascii.txt # Mutex
grep -iE "%appdata%|%temp%|%system%" strings_ascii.txt # Paths
grep -iE "powershell|cmd\.exe|wscript|cscript" strings_ascii.txt # Scripting
High-value strings: Specific to malware behavior (URLs, mutex names, registry paths). Low-value strings: Generic format strings, error messages, CRT artifacts.
3. Imports = Capability Fingerprint
| Capability | Key Imports | MITRE ATT&CK |
|---|---|---|
| Network/C2 | InternetOpen, InternetConnect, HttpSendRequest, WSASocket, connect, WSAConnect | T1071 |
| Process Injection | OpenProcess, VirtualAllocEx, WriteProcessMemory, CreateRemoteThread, VirtualProtectEx | T1055 |
| Persistence | RegSetValueEx, RegCreateKeyEx, CreateService, CopyFile, SHGetFolderPath | T1547 |
| Credential Access | LsaEnumerateLogonSessions, CredEnumerate, CryptUnprotectData, LsaGetLogonSessionData | T1003 |
| Discovery | GetSystemInfo, GetVersionEx, EnumProcesses, NetShareEnum, GetAdaptersInfo | T1082 |
| Defense Evasion | IsDebuggerPresent, CheckRemoteDebuggerPresent, VirtualProtect (RWX), SetThreadContext | T1622 |
| Execution | CreateProcess, WinExec, ShellExecute, CreateThread, QueueUserAPC | T1059 |
| Lateral Movement | WNetAddConnection2, NetUseAdd, CreateRemoteThread (remote), SMB APIs | T1021 |
4. Sections & Entropy
# pefile entropy scan
python3 -c "
import pefile, math
pe = pefile.PE('sample.exe')
for s in pe.sections:
data = s.get_data()
entropy = -sum((data.count(b)/len(data))*math.log2(data.count(b)/len(data)) for b in set(data))
print(f'{s.Name.decode().strip():10s} VA={s.VirtualAddress:08X} VS={s.Misc_VirtualSize:08X} RS={s.SizeOfRawData:08X} Entropy={entropy:.2f}')
"
Interpretation:
- Code (.text): 6.0-7.2 (normal), >7.5 = packed/encrypted
- Data (.rdata, .data): 4.0-6.5
- Resources (.rsrc): Variable
- Packed: High entropy in ALL sections, few/no imports, entry point in weird section
5. Resources
# Dump resources
wrestool -x -t14 sample.exe # RT_GROUP_ICON
wrestool -x -t16 sample.exe # RT_VERSION
wrestool -x sample.exe # All resources
Look for:
- Embedded binaries (RT_RCDATA, custom types)
- Version info (company, product, copyright — often fake)
- Manifests (requestedExecutionLevel = admin?)
6. Packer Detection
| Indicator | Meaning |
|---|---|
Few imports (only LoadLibrary/GetProcAddress) | Manual import resolution |
| High entropy sections | Packed/encrypted |
Section names: UPX0, UPX1, .aspack, .themida, .vmp0 | Known packer |
Entry point in last section / not in .text | Packer stub |
| TLS callbacks present | Pre-entry unpacking |
VirtualProtect on own .text at runtime | Self-modifying/unpacking |
Static vs Dynamic — When to Switch
Static analysis is safe but limited (encrypted strings, packed code defeat it). Move to dynamic when:
- The sample is packed — you need runtime to unpack it.
- Strings/imports are deliberately stripped.
- You need to observe behavior (what does it actually do?).
Always dynamic-analyze in an isolated VM with snapshots and no network access to the real internet.
Hypothesis Template
From minute one, keep notes:
=== SAMPLE TRIAGE ===
SHA-256: a1b2c3d4e5f6...
File Type: PE32+ executable (GUI) x86-64
Size: 124 KB
Compile Time: 2024-01-15 14:32:10 (may be forged)
STRINGS (high-value):
C2: http://c2.example.com/beacon
Mutex: Global\Mutex_A1B2C3
Persistence: Software\Microsoft\Windows\CurrentVersion\Run
Paths: %APPDATA%\svchost.exe
IMPORTS (capabilities):
Network: InternetOpen, InternetConnect, HttpSendRequest
Injection: VirtualAllocEx, WriteProcessMemory, CreateRemoteThread
Persistence: RegSetValueEx
Anti-Debug: IsDebuggerPresent
SECTIONS:
.text: Entropy 6.8 (normal)
.rdata: Entropy 5.2
.data: Entropy 4.1
No suspicious section names.
HYPOTHESIS:
Implant/Beacon with process injection capability.
Persists via Run key. Single-instance mutex.
C2 over HTTP. Likely a RAT or loader.
NEXT STEPS:
1. Dynamic: Run in VM with Procmon/Regshot
2. Dump memory after unpack (if packed)
3. Extract full C2 config from memory
4. YARA rule from strings + imports
Classification by Capability Profile
| Profile | Capabilities | Typical Family |
|---|---|---|
| Downloader | Network only | Emotet, TrickBot (loader) |
| Dropper | Network + File Write | Various |
| Injector | Injection + Network | Cobalt Strike, custom |
| RAT/Implant | Network + Injection + Persistence + Discovery | AsyncRAT, njRAT, custom |
| Ransomware | File Encrypt + Persistence + Network (C2) | LockBit, Conti |
| Wiper | Disk/Filesystem destroy | NotPetya, Shamoon |
| Spyware/Stealer | Credential Access + Network | RedLine, Vidar |
| Botnet | Network + Persistence + Lateral | Mirai, QakBot |
Documentation Habit
Documentation is not optional — it’s how you track reasoning across hours.
Interactive: Triage a Sample
The hex dump below contains suspicious strings. Apply the triage sequence and form a hypothesis.
Takeaway
Triage is fast hypothesis, not deep analysis. Find the interesting corner, then dig.
Next: Persistence Mechanisms.
Practice Exercises
- Triage Drill: Given 5 samples (from MalwareBazaar), spend 5 min each. Write hypothesis for each.
- Entropy Scan: Write a script to flag PE sections with entropy > 7.5.
- Import Classifier: Build a dictionary mapping API → ATT&CK technique. Auto-tag samples.
- String Clustering: Group samples by shared strings (mutex, C2 domain, PDB path).
- Packer ID: Collect 10 packed samples. Identify packer by section names/entry point/imports.
- False Positive Hunt: Find a legitimate binary with “suspicious” imports (e.g.,
VirtualAllocExin a debugger). Why is it benign?