ETW的使用
1.准备知识
ETW全称Event Tracing for Windows,可以从名称中看出来ETW是用来进行事件追踪的。在ETW中,使用ETW输出追踪消息的目标程序称之为提供器Provider,接收和查看追踪消息的工具或文件被称之为消耗器Consumer,负责控制追踪会话的工具称为控制器Controller。3者之间的关系如图

用于支持ETW传输追踪信息的通信被称为ETW会话。系统会为每个ETW会话维持一定数量的缓冲区用以缓存发送到该会话的ETW消息。ETW控制器可以定制缓冲区的大小。系统会定期地将缓冲区中的信息发送给ETW消耗器或冲转到追踪文件中(.etl格式)。当缓冲区已满或者会话停止时,系统会提前冲转缓冲区中的内容。ETW控制器可以显式要求冲转缓冲区。当系统崩溃时,系统会将缓冲区的内容转储到DUMP文件中。
2.提供ETW消息
ETW通过RegisterTraceGuid API来向系统注册GUID,这样ETW控制器可以通过GUID找到提供器。

注册成功后,如果有ETW控制器启动或停止该提供器,系统会调用RequestAddress所指向的回调函数。在回调函数中,通过参数请求代码可以判断被调用的原因。如若被启用,那么应该调用GetTraceLoggerHandle获取ETW会话的句柄。

有了会话句柄,就可以调用TraceEvent进行信息的输出。

参数EventTrace用来指定存放追踪信息的内存缓冲区的起始地址,缓冲区应该以一个EVENT_TRACE_HEADER结构开始,后面跟随追踪事件的具体数据。

以上函数中没有判断是否启用追踪,应该在代码段外层加这样的检查。
除了TraceEvent,还可以使用TraceMessage和TraceMessageVa向ETW会话发送消息。

3. ETW会话控制
ETW控制器程序可以使用StartTrace来启用一个追踪会话,并取得会话信息和句柄。

其中,SessionName指定会话的名称,Properties指定会话的属性。


在这个结构体中,LogFileMode指定消息投递模式,一种是实时投递给消耗器,一种是将消息存储到.etl文件中。
在StartTrace调用时,需要在EVENT_TRACE_PROPERTIES结构体后面多申请一部分用于存储记录器名称和etl文件路径的空间,记录器名称空间为空,但文件路径空间需要进行填充。
BOOL CNKLMgr::StartNKL(LPCTSTR lpszLogFile,DWORD dwEnableFlags)
{
ULONG BufferSize = 0;
ULONG rc = 0;
BufferSize = sizeof(EVENT_TRACE_PROPERTIES) +
sizeof(TCHAR)*(_tcslen(lpszLogFile)+1) + sizeof(KERNEL_LOGGER_NAME);
if(m_pNklProperties==NULL)
m_pNklProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);
if (NULL == m_pNklProperties)
{
wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
return FALSE;
}
ZeroMemory(m_pNklProperties, BufferSize);
m_pNklProperties->Wnode.BufferSize = BufferSize;
m_pNklProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
m_pNklProperties->Wnode.ClientContext = 1; //QPC clock resolution
m_pNklProperties->Wnode.Guid = SystemTraceControlGuid;
//m_pNklProperties->BufferSize = 4;
m_pNklProperties->EnableFlags = dwEnableFlags;
m_pNklProperties->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
m_pNklProperties->MaximumFileSize = 5;
m_pNklProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
m_pNklProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES)
+ sizeof(KERNEL_LOGGER_NAME);
_tcscpy((LPTSTR)((char*)m_pNklProperties + m_pNklProperties->LogFileNameOffset),
lpszLogFile);
rc = StartTrace((PTRACEHANDLE)&m_hNklSessionHandle,
KERNEL_LOGGER_NAME, m_pNklProperties);
其中EnableFlags可以指定监控的事件,如下

启用会话之后,便可以使用句柄和ETW提供器的GUID启动ETW提供器。使其向这个会话输出追踪消息。

最后使用ControlTrace来查询或控制ETW会话。其中一二参数指定其一即可。


还可以使用QueryAllTraces查询系统内所有启动的ETW会话。EnumertateTraceGuids枚举系统中注册的ETW提供器。
4.ETW消耗器
ETW消耗器在接收ETW消息之前,需使用OpenTrace打开一个etl文件或者实时ETW会话,同时注册接收消息的回调函数。

使用ProcessTrace通知系统启动消息传递。

其中,HandleArray数组包含了OpenTrace打开的ETW会话句柄,每个句柄代表一个ETW实时会话或者ETL文件。
在调用ProcessTrace之后,如果指定的会话有输出事件,那么系统便会调用消耗器所注册的回调函数。
BufferCallback用来接收关于绘画缓冲区的统计信息。EventCallback、EventClassCallback两者用于接收追踪事件。默认情况下,系统会将ProcessTrace指定的所有会话事件发送给EventCallback函数,但是ETW允许通过SetTraceCallback通知系统按事件所属的分类发给不同的回调函数。

调用SetTraceCallback后,当有指定GUID相符的事件发生时,系统便会调用与其对应的EventClassCallback。
BufferCallback函数原型如下

5.格式描述
ETW输出信息为二进制,即etl文件为二进制的。要想解读它,就需要使用格式描述文件。ETW提供了3种方式描述格式信息。第一种为MOF文件,第二种为使用WPP写在源文件中,然后利用工具从编译好的pdb文件中提取出格式文件,第三种为Manifest文件和TDH API。
5.1 WPP
WPP在驱动程序中实现ETW提供器。通过ETW输出追踪事件,
在使用WPP时,需要在程序源文件中定义GUID和追踪标志位。

而后在DriverEntry中加入WPP的初始化宏,

在驱动卸载函数中添加WPP清理宏

在使用WPP的时候,还会自动生成追踪消息的tmh头文件,要让tmh头文件自动产生,需要在项目属性WPP
Tracing中做如下配置, -km为生成tmh头文件

DoTraceLevelMessage为自定义的事件发送消息宏,tracedrv.h为GUID定义的文件,以及使用自定义宏需要在此文件中添加
#define WPP_LEVEL_FLAGS_LOGGER(level,flags) WPP_LEVEL_LOGGER(flags)
#define WPP_LEVEL_FLAGS_ENABLED(level, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= level)

使用以上3个宏可以输出事件,但是在启动跟踪会话的时候需要添加-flag 参数,这样才能获得相应的事件消息。比如-flag 1就会收到FLAG_ONE的消息。
这里的话可以参考MSDN。
阅读WPP生成的etl文件可以按以下步骤来进行

但是笔者在试过之后,.out文件中并没有可以阅读的信息。但是可以使用traceview打开etl文件,并选择pdb文件进行事件消息的阅读。
6. NT Kernel Logger
在内核中, NKL是Windows内建的用于记录内核事件的系统组件。Windows的会话中,就有一种是用于NKL的会话,另外一种是用于Global Logger Session。
可以使用traceview来进行NKL事件的解析。


其中启动NKL追踪会话代码已在上面给出,会话停止代码如下。

7. Global Logger Session
尽管我们可以使用NKL来获取内核事件,但是要启用NKL是在启动之后了。如果想要在系统启动的时候,进行相关事件的输出,我们就需要用到GLS。GLS可以把事件输出到文件中,并且GLS无论是在用户态还是内核态都可以使用。
7.1 启动GLS会话
GLS是记录启动早期的事件,所以GLS是可以通过注册表来进行启动与配置。控制GLS的表键如下
HKEY LOCAL_MACHINE\SYSTEM\CurrentControlset\Control\wMI\GlobalLogger。如果GlobalLogger不在,加上即可。在表键下加上Start的键值(REG_DWORD),值为1,那么下次系统启动时,就会启动GLS会话。也可以使用tracelog来添加注册表和删除注册表选项。

系统会把GLS的结果写道GlobalLogger表键下,键值名为Status,成功值为0,失败为WIN32错误码。
7.2 注册表配置GLS

其中,指定EnableKernelFlags可以使GLS会话追踪NKL会话。其内容时DWORD数组,每个元素都是NKL启动时的标志。FileName键值指定输出的文件路径。LogFileMode指定GLS处理文件的方式。

7.3 在驱动中使用GLS
在驱动中使用GLS输出ETW消息。使用方式如下

本文固定链接: https://www.socarates.online/index.php/2024/04/16/etw%e7%9a%84%e4%bd%bf%e7%94%a8/ | 安全技术研究
ETW的使用:等您坐沙发呢!
发表评论
