npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- A suspicious Windows executable has been collected and needs initial triage before sandbox execution
- You need to identify imports, strings, and resources that reveal malware functionality without running the sample
- Determining whether a PE file is packed, obfuscated, or contains anti-analysis techniques
- Extracting indicators of compromise (hashes, URLs, IPs, registry keys) embedded in a binary
- Classifying a sample's capabilities based on its import table and section characteristics
Do not use for dynamic behavioral analysis requiring execution; use a sandbox (Cuckoo, ANY.RUN) for runtime behavior observation.
Prerequisites
- PEStudio (free edition from https://www.winitor.com/) installed on an isolated analysis workstation
- Python 3.8+ with
pefilelibrary for scripted PE analysis (pip install pefile) - CFF Explorer or PE-bear as supplementary PE analysis tools
- Access to VirusTotal API for hash lookups and community intelligence
- Isolated analysis VM with no network connectivity to production systems
- FLOSS (FireEye Labs Obfuscated String Solver) for extracting obfuscated strings
Workflow
Step 1: Compute File Hashes and Verify Sample Integrity
Generate cryptographic hashes for identification and intelligence lookup:
# Generate MD5, SHA-1, and SHA-256 hashes
md5sum suspect.exe
sha1sum suspect.exe
sha256sum suspect.exe
# Check hash against VirusTotal
curl -s -X GET "https://www.virustotal.com/api/v3/files/$(sha256sum suspect.exe | cut -d' ' -f1)" \
-H "x-apikey: $VT_API_KEY" | jq '.data.attributes.last_analysis_stats'
# Get file type with magic bytes verification
file suspect.exeStep 2: Examine PE Headers and Section Table
Open the sample in PEStudio and inspect structural properties:
PEStudio Analysis Points:
━━━━━━━━━━━━━━━━━━━━━━━━━
File Header: Compilation timestamp, target architecture (x86/x64)
Optional Header: Entry point address, image base, subsystem (GUI/console)
Section Table: Section names, virtual/raw sizes, entropy values
High entropy (>7.0) in .text/.rsrc suggests packing
Signatures: Authenticode signature presence and validityScripted PE Header Analysis with pefile:
import pefile
import hashlib
import math
pe = pefile.PE("suspect.exe")
# Compilation timestamp
import datetime
timestamp = pe.FILE_HEADER.TimeDateStamp
compile_time = datetime.datetime.utcfromtimestamp(timestamp)
print(f"Compile Time: {compile_time} UTC")
# Section analysis with entropy calculation
for section in pe.sections:
name = section.Name.decode().rstrip('\x00')
entropy = section.get_entropy()
raw_size = section.SizeOfRawData
virtual_size = section.Misc_VirtualSize
ratio = virtual_size / raw_size if raw_size > 0 else 0
print(f"Section: {name:8s} Entropy: {entropy:.2f} Raw: {raw_size:>10} Virtual: {virtual_size:>10} Ratio: {ratio:.2f}")
if entropy > 7.0:
print(f" [!] HIGH ENTROPY - likely packed or encrypted")
if ratio > 10:
print(f" [!] HIGH V/R RATIO - unpacking stub likely present")Step 3: Analyze Import Address Table (IAT)
Identify suspicious API imports that indicate malware capabilities:
# Extract and categorize imports
suspicious_imports = {
"Process Injection": ["VirtualAllocEx", "WriteProcessMemory", "CreateRemoteThread", "NtCreateThreadEx"],
"Keylogging": ["GetAsyncKeyState", "SetWindowsHookExA", "GetKeyState"],
"Persistence": ["RegSetValueExA", "CreateServiceA", "SchTasksCreate"],
"Evasion": ["IsDebuggerPresent", "CheckRemoteDebuggerPresent", "NtQueryInformationProcess"],
"Network": ["InternetOpenA", "HttpSendRequestA", "URLDownloadToFileA", "WSAStartup"],
"File Operations": ["CreateFileA", "WriteFile", "DeleteFileA", "MoveFileA"],
"Crypto": ["CryptEncrypt", "CryptDecrypt", "CryptAcquireContextA"],
}
for entry in pe.DIRECTORY_ENTRY_IMPORT:
dll_name = entry.dll.decode()
for imp in entry.imports:
if imp.name:
func_name = imp.name.decode()
for category, funcs in suspicious_imports.items():
if func_name in funcs:
print(f"[!] {category}: {dll_name} -> {func_name}")Step 4: Extract and Analyze Strings
Use FLOSS for obfuscated strings and standard strings extraction:
# Standard strings extraction (ASCII and Unicode)
strings -a suspect.exe > strings_ascii.txt
strings -el suspect.exe > strings_unicode.txt
# FLOSS for decoded/deobfuscated strings
floss suspect.exe --output-json floss_output.json
# Search for network indicators in strings
grep -iE "(http|https|ftp)://" strings_ascii.txt
grep -iE "([0-9]{1,3}\.){3}[0-9]{1,3}" strings_ascii.txt
grep -iE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" strings_ascii.txt
# Search for registry keys
grep -i "HKLM\\|HKCU\\|SOFTWARE\\|CurrentVersion\\Run" strings_ascii.txt
# Search for file paths and extensions
grep -iE "\.(exe|dll|bat|ps1|vbs|tmp)" strings_ascii.txtStep 5: Inspect Resources and Embedded Data
Examine the PE resource section for embedded payloads or configuration:
# Extract resources from PE file
if hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
if hasattr(resource_type, 'directory'):
for resource_id in resource_type.directory.entries:
if hasattr(resource_id, 'directory'):
for resource_lang in resource_id.directory.entries:
data = pe.get_data(resource_lang.data.struct.OffsetToData,
resource_lang.data.struct.Size)
entropy = calculate_entropy(data)
print(f"Resource Type: {resource_type.id} Size: {len(data)} Entropy: {entropy:.2f}")
if entropy > 7.0:
print(f" [!] High entropy resource - possible embedded payload")
# Check for PE signature in resource (embedded executable)
if data[:2] == b'MZ':
print(f" [!] Embedded PE detected in resource")
with open(f"extracted_resource_{resource_type.id}.bin", "wb") as f:
f.write(data)Step 6: Check for Packing and Protection
Determine if the binary is packed or protected:
# Detect packer with Detect It Easy (DIE)
diec suspect.exe
# Check with PEiD signatures (command-line version)
python3 -c "
import pefile
pe = pefile.PE('suspect.exe')
# Check for common packer section names
packer_sections = {'.upx0': 'UPX', '.aspack': 'ASPack', '.adata': 'ASPack',
'.nsp0': 'NsPack', '.vmprotect': 'VMProtect', '.themida': 'Themida'}
for section in pe.sections:
name = section.Name.decode().rstrip('\x00').lower()
if name in packer_sections:
print(f'[!] Packer detected: {packer_sections[name]} (section: {name})')
# Check import table size (very few imports suggest packing)
import_count = sum(len(entry.imports) for entry in pe.DIRECTORY_ENTRY_IMPORT)
if import_count < 10:
print(f'[!] Only {import_count} imports - likely packed')
"Step 7: Generate Static Analysis Report
Compile all findings into a structured triage report:
Document the following for each analyzed sample:
- File identification (hashes, file type, size, compile timestamp)
- Packing/protection status and identified packer
- Suspicious imports categorized by capability
- Network indicators extracted from strings (IPs, domains, URLs)
- Embedded resources and their characteristics
- Overall threat assessment and recommended next steps (sandbox execution, YARA rule creation)Key Concepts
| Term | Definition |
|---|---|
| PE (Portable Executable) | The file format for Windows executables (.exe, .dll, .sys) containing headers, sections, imports, and resources that define how the OS loads the binary |
| Import Address Table (IAT) | PE structure listing external DLL functions the executable calls at runtime; reveals program capabilities and intent |
| Section Entropy | Statistical measure of randomness in a PE section; values above 7.0 (out of 8.0) indicate compression, encryption, or packing |
| FLOSS | FireEye Labs Obfuscated String Solver; automatically extracts and decodes obfuscated strings that standard strings misses |
| Packing | Compression or encryption of a PE file's code section to hinder static analysis; requires runtime unpacking stub to execute |
| PE Resources | Data section within a PE file that can contain icons, dialogs, version info, or attacker-embedded payloads and configuration data |
| Compilation Timestamp | Timestamp in the PE header indicating when the binary was compiled; can be forged but often reveals development timeline |
Tools & Systems
- PEStudio: Free Windows tool for static analysis of PE files providing indicators, imports, strings, and resource inspection in a single interface
- pefile (Python): Python library for parsing and analyzing PE file structures programmatically for automated analysis pipelines
- FLOSS: FireEye tool that extracts obfuscated strings from malware using static analysis techniques including stack string decoding
- Detect It Easy (DIE): Packer and compiler detection tool that identifies protectors, compilers, and linkers used to build PE files
- CFF Explorer: Advanced PE editor and viewer for detailed inspection of PE headers, sections, imports, and resource directories
Common Scenarios
Scenario: Triaging a Suspicious Email Attachment
Context: SOC receives an alert on a suspicious executable attached to a phishing email. The file needs rapid triage to determine if it is malicious before committing sandbox resources.
Approach:
- Compute SHA-256 hash and query VirusTotal for existing detections and community comments
- Open in PEStudio and check the indicators tab for red/yellow flagged items
- Verify compile timestamp (future dates or dates from 1970 indicate timestamp manipulation)
- Check imports for VirtualAllocEx, CreateRemoteThread (injection), URLDownloadToFileA (downloader)
- Extract strings and search for C2 URLs, IP addresses, and file paths
- Check resources for embedded PE files or high-entropy data blobs
- Assess packing status; if packed, note the packer and plan for unpacking before deeper analysis
Pitfalls:
- Trusting the PE compile timestamp without corroborating evidence (timestamps are trivially forged)
- Concluding a file is benign because it has few suspicious imports (packed malware hides real imports)
- Missing Unicode strings by only running ASCII string extraction
- Not checking overlay data appended after the last PE section (common hiding spot for configuration data)
Output Format
STATIC MALWARE ANALYSIS REPORT
=================================
Sample: suspect.exe
MD5: d41d8cd98f00b204e9800998ecf8427e
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
File Size: 245,760 bytes
File Type: PE32 executable (GUI) Intel 80386
Compile Time: 2025-09-14 08:23:15 UTC
PACKING STATUS
Packer Detected: None (native binary)
Section Entropy: .text=6.42 .rdata=4.89 .data=3.21 .rsrc=7.81
Note: .rsrc section entropy elevated - check resources
SUSPICIOUS IMPORTS
[INJECTION] kernel32.dll -> VirtualAllocEx
[INJECTION] kernel32.dll -> WriteProcessMemory
[INJECTION] kernel32.dll -> CreateRemoteThread
[EVASION] kernel32.dll -> IsDebuggerPresent
[NETWORK] wininet.dll -> InternetOpenA
[NETWORK] wininet.dll -> HttpSendRequestA
[PERSISTENCE] advapi32.dll -> RegSetValueExA
EXTRACTED INDICATORS
URLs: hxxps://update.malicious[.]com/gate.php
IPs: 185.220.101[.]42, 91.215.85[.]17
Registry Keys: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\svchost
File Paths: C:\Users\Public\svchost.exe
EMBEDDED RESOURCES
Resource 101: Size=98304 Entropy=7.89 [!] Embedded PE detected
Resource 102: Size=4096 Entropy=2.14 (configuration XML)
ASSESSMENT
Threat Level: HIGH
Classification: Dropper with process injection capabilities
Recommended: Execute in sandbox, extract embedded PE for separate analysisReferences and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.1 KB
API Reference: Static Malware Analysis with PE Studio Agent
Overview
Performs automated static analysis of Windows PE binaries using pefile to inspect headers, sections, imports, strings, and resources for malware indicators.
Dependencies
| Package | Version | Purpose |
|---|---|---|
| pefile | >= 2023.2.7 | PE file parsing and section analysis |
| hashlib | stdlib | MD5, SHA-1, SHA-256 hash computation |
Core Functions
compute_hashes(filepath)
Generates MD5, SHA-1, SHA-256 hashes and file size.
- Returns:
dictwithmd5,sha1,sha256,size
analyze_sections(pe)
Inspects PE sections for entropy, virtual/raw size ratios, and packing indicators.
- Flags:
HIGH_ENTROPY(>7.0),HIGH_VR_RATIO(>10x) - Returns:
list[dict]- section analysis entries
detect_packer(pe)
Identifies known packer section names (UPX, ASPack, VMProtect, Themida) and low import counts.
- Returns:
list[str]- detected packer names
analyze_imports(pe)
Categorizes imports into Process Injection, Keylogging, Persistence, Evasion, Network, Crypto.
- Returns:
list[dict]withcategory,dll,function
extract_strings(filepath, min_length=6)
Extracts ASCII strings and classifies into URLs, IPs, emails, registry keys, file paths.
- Returns:
dict[str, list[str]]- categorized string indicators
analyze_resources(pe)
Inspects PE resources for high-entropy data and embedded PE files.
- Returns:
list[dict]withtype_id,size,entropy,flags
analyze_pe(filepath)
Full analysis pipeline producing structured report.
- Returns:
dict- complete analysis report
Suspicious Import Categories
| Category | Example Functions |
|---|---|
| Process Injection | VirtualAllocEx, WriteProcessMemory, CreateRemoteThread |
| Keylogging | GetAsyncKeyState, SetWindowsHookExA |
| Persistence | RegSetValueExA, CreateServiceA |
| Evasion | IsDebuggerPresent, CheckRemoteDebuggerPresent |
| Network | InternetOpenA, URLDownloadToFileA, WSAStartup |
| Crypto | CryptEncrypt, CryptDecrypt |
Usage
python agent.py suspect.exeScripts 1
agent.py7.8 KB
#!/usr/bin/env python3
"""Static malware analysis agent using pefile for PE binary inspection."""
import pefile
import hashlib
import math
import os
import re
import sys
import datetime
SUSPICIOUS_IMPORTS = {
"Process Injection": [
"VirtualAllocEx", "WriteProcessMemory", "CreateRemoteThread",
"NtCreateThreadEx", "QueueUserAPC", "NtMapViewOfSection",
],
"Keylogging": [
"GetAsyncKeyState", "SetWindowsHookExA", "SetWindowsHookExW",
"GetKeyState", "GetKeyboardState",
],
"Persistence": [
"RegSetValueExA", "RegSetValueExW", "CreateServiceA",
"CreateServiceW", "RegCreateKeyExA",
],
"Evasion": [
"IsDebuggerPresent", "CheckRemoteDebuggerPresent",
"NtQueryInformationProcess", "GetTickCount", "QueryPerformanceCounter",
],
"Network": [
"InternetOpenA", "InternetOpenW", "HttpSendRequestA",
"URLDownloadToFileA", "URLDownloadToFileW", "WSAStartup",
"InternetConnectA", "HttpOpenRequestA",
],
"Crypto": [
"CryptEncrypt", "CryptDecrypt", "CryptAcquireContextA",
"CryptGenKey", "CryptImportKey",
],
}
PACKER_SECTIONS = {
".upx0": "UPX", ".upx1": "UPX", ".aspack": "ASPack",
".adata": "ASPack", ".nsp0": "NsPack", ".vmprotect": "VMProtect",
".themida": "Themida", ".enigma1": "Enigma", ".petite": "Petite",
}
def compute_hashes(filepath):
with open(filepath, "rb") as f:
data = f.read()
return {
"md5": hashlib.md5(data).hexdigest(),
"sha1": hashlib.sha1(data).hexdigest(),
"sha256": hashlib.sha256(data).hexdigest(),
"size": len(data),
}
def analyze_sections(pe):
sections = []
for section in pe.sections:
name = section.Name.decode(errors="replace").rstrip("\x00")
entropy = section.get_entropy()
raw_size = section.SizeOfRawData
virtual_size = section.Misc_VirtualSize
ratio = virtual_size / raw_size if raw_size > 0 else 0
flags = []
if entropy > 7.0:
flags.append("HIGH_ENTROPY")
if ratio > 10:
flags.append("HIGH_VR_RATIO")
sections.append({
"name": name, "entropy": round(entropy, 2),
"raw_size": raw_size, "virtual_size": virtual_size,
"ratio": round(ratio, 2), "flags": flags,
})
return sections
def detect_packer(pe):
detected = []
for section in pe.sections:
name = section.Name.decode(errors="replace").rstrip("\x00").lower()
if name in PACKER_SECTIONS:
detected.append(PACKER_SECTIONS[name])
import_count = 0
if hasattr(pe, "DIRECTORY_ENTRY_IMPORT"):
import_count = sum(len(e.imports) for e in pe.DIRECTORY_ENTRY_IMPORT)
if import_count < 10:
detected.append(f"SUSPECTED_PACKED (only {import_count} imports)")
return detected
def analyze_imports(pe):
findings = []
if not hasattr(pe, "DIRECTORY_ENTRY_IMPORT"):
return [{"category": "PACKED", "dll": "N/A", "function": "No imports found"}]
for entry in pe.DIRECTORY_ENTRY_IMPORT:
dll_name = entry.dll.decode(errors="replace")
for imp in entry.imports:
if imp.name:
func_name = imp.name.decode(errors="replace")
for category, funcs in SUSPICIOUS_IMPORTS.items():
if func_name in funcs:
findings.append({
"category": category, "dll": dll_name,
"function": func_name,
})
return findings
def extract_strings(filepath, min_length=6):
indicators = {"urls": [], "ips": [], "emails": [], "registry": [], "paths": []}
with open(filepath, "rb") as f:
data = f.read()
ascii_strings = re.findall(rb"[\x20-\x7e]{%d,}" % min_length, data)
for s in ascii_strings:
s_decoded = s.decode("ascii", errors="ignore")
if re.search(r"https?://", s_decoded):
indicators["urls"].append(s_decoded)
if re.search(r"\b(\d{1,3}\.){3}\d{1,3}\b", s_decoded):
indicators["ips"].append(s_decoded)
if re.search(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", s_decoded):
indicators["emails"].append(s_decoded)
if re.search(r"HKLM|HKCU|CurrentVersion\\Run", s_decoded, re.IGNORECASE):
indicators["registry"].append(s_decoded)
if re.search(r"\.(exe|dll|bat|ps1|vbs|tmp)", s_decoded, re.IGNORECASE):
indicators["paths"].append(s_decoded)
for key in indicators:
indicators[key] = list(set(indicators[key]))[:20]
return indicators
def analyze_resources(pe):
resources = []
if not hasattr(pe, "DIRECTORY_ENTRY_RESOURCE"):
return resources
for rtype in pe.DIRECTORY_ENTRY_RESOURCE.entries:
if hasattr(rtype, "directory"):
for rid in rtype.directory.entries:
if hasattr(rid, "directory"):
for rlang in rid.directory.entries:
data = pe.get_data(
rlang.data.struct.OffsetToData,
rlang.data.struct.Size,
)
entropy = 0.0
if len(data) > 0:
freq = [0] * 256
for b in data:
freq[b] += 1
for f in freq:
if f > 0:
p = f / len(data)
entropy -= p * math.log2(p)
flags = []
if entropy > 7.0:
flags.append("HIGH_ENTROPY")
if data[:2] == b"MZ":
flags.append("EMBEDDED_PE")
resources.append({
"type_id": rtype.id, "size": len(data),
"entropy": round(entropy, 2), "flags": flags,
})
return resources
def analyze_pe(filepath):
hashes = compute_hashes(filepath)
pe = pefile.PE(filepath)
timestamp = pe.FILE_HEADER.TimeDateStamp
compile_time = datetime.datetime.utcfromtimestamp(timestamp).isoformat() + "Z"
report = {
"file": os.path.basename(filepath),
"hashes": hashes,
"compile_time": compile_time,
"sections": analyze_sections(pe),
"packer_indicators": detect_packer(pe),
"suspicious_imports": analyze_imports(pe),
"string_indicators": extract_strings(filepath),
"resources": analyze_resources(pe),
}
pe.close()
return report
def print_report(report):
print("STATIC MALWARE ANALYSIS REPORT")
print("=" * 40)
print(f"Sample: {report['file']}")
print(f"MD5: {report['hashes']['md5']}")
print(f"SHA-256: {report['hashes']['sha256']}")
print(f"Size: {report['hashes']['size']} bytes")
print(f"Compile Time: {report['compile_time']}")
if report["packer_indicators"]:
print(f"\nPACKER: {', '.join(report['packer_indicators'])}")
print("\nSECTIONS:")
for s in report["sections"]:
flags = f" [{', '.join(s['flags'])}]" if s["flags"] else ""
print(f" {s['name']:8s} entropy={s['entropy']} raw={s['raw_size']}{flags}")
print("\nSUSPICIOUS IMPORTS:")
for imp in report["suspicious_imports"]:
print(f" [{imp['category']}] {imp['dll']} -> {imp['function']}")
indicators = report["string_indicators"]
if any(indicators.values()):
print("\nEXTRACTED INDICATORS:")
for key, vals in indicators.items():
if vals:
print(f" {key}: {', '.join(vals[:5])}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python agent.py <pe_file>")
sys.exit(1)
result = analyze_pe(sys.argv[1])
print_report(result)