ETW机制学习
文章目录
概述
该文写于2018年7月,整理资料找到,现整理放于博客上。
经过初步研究了解,通过ETW获取的信息非常丰富,可以通过ETW获取到的信息有:
- 文件类信息,包括文件创建、删除、读写等信息。
- 注册表信息,包括注册表的创建、删除、读写等信息。
- 进程线程信息,包括进程创建退出、线程创建退出、模块加载等。
- 网络信息,TCP、UDP协议的发送,接收ip地址以及数据长度等。
- CPU的使用情况、内存使用情况以及发生事件时的堆栈信息等。
更多的信息获取参见msdn中EnableFlags选项介绍。
由于ETW获取的信息非常丰富,且对系统性能影响不是很大,因此用来作为一种系统监控手段非常合适。
ETW框架模型概述
Event Trace for Windows
(ETW) 是一个高效的内核级别的事件追踪机制,它可以记录系统内核或是应用程序的事件到日志文件。我们可以通过实时获取或是从一个日志文件来解析处理这些事件,之后通过这些事件用来调试程序或是找到程序的性能问题。
ETW主要由三部分组成,分别是:
- Controllers(事件控制器),用来开关event trace 会话 和 Providers。
- Providers(事件提供器), 用来提供事件。
- Consumers(事件消耗器),用来处理事件。
另有一个关键的概念Sessions。
这四者的关系图如下图所示:
Controllers
通过Controllers可以进行各种设置。如设置日志是输出到文件还是实时解析,设置Session的打开和关闭,设置Session中数据缓冲池的大小以及其他统计信息等。
Providers
Providers是提供事件的程序,当一个Provider注册后,可以通过Controller控制它是否输出事件。
常见的provider共有四种,分别是MOF Providers
, WPP Providers
, manifest-based Providers
, 和 TraceLogging Providers
。在vista之后应当使用manifest-based
和TraceLogging Provider
。
Consumers
Consumers是一种可以选取一个或多个Session作为事件源的事件处理程序,它可以同时接收多个Session的事件。Consumers可以接收处理存储在日志文件中的事件,或是实时处理从Session获取的事件。
事件在某些情况下会丢失,这一般是设置不当导致的,可能的原因有以下几个:
- 事件内容的总大小超过64kb。
- 设置的事件缓冲区的大小小于事件的总大小。
- 实时的事件处理器处理事件不够快或是记录到文件时,文件已经填满。
- 当记录到文件时,磁盘速度太慢不足以快速的写入事件。
需要注意的是,这三个组件可以在一个应用程序中,也可以根据情况分布在不同的应用程序中。
Sessions
除了上述三个组件外,还有一个概念也较为重要,这便是Session。Session由Controllers定义,Session记录了一个或多个Providers输出的事件,其主要用来管理和刷新事件的缓存。
系统同时最多支持64个Session,这些Session中有两个Session比较特殊,由操作系统直接定义,可直接使用,分别是:
Global Logger Session
, 它用来记录操作系统早期启动过程中的事件,例如设备驱动相关的事件。NT Kernel Logger Session
,它用来记录操作系统生成的预定义系统事件,例如磁盘IO或页面错误事件。
基本实现
ETW本质上是一个日志记录追踪系统,一般的用法是让自己的程序作为Provider,并使用ETW机制输出日志,之后建立相应的Consumer来解析日志,根据日志分析应用程序的执行过程。
由于操作系统默认提供了NT Kerner Logger Session,且该Session提供了众多操作系统中的重要事件信息,因此可以直接使用该Session获取系统事件。由于该Session中已经包含了输出事件的Providers,因此在使用中只需要建立相应的Controller和Consumer即可。Controller用来控制Session的开关 ,Consumer用来处理从Session中拿到的事件。
整个实现以监控文件创建事件为例进行说明,程序中主要分为两个部分,一部分是Controller,用来控制Session的打开关闭;另一部分是Consumer,用来从Session中获取解析事件。
部分代码实现如下:
|
|
程序开启后,可以使用命令logman –ets query "NT Kernel Logger"
查看当前的kernel session的状态,这里测试如下:
图中画框的部分即为设置EVENT_TRACE_PROPERTIES
结构体的EnableFlags
成员时的EVENT_TRACE_FLAG_FILE_IO_INIT
宏的值。
程序运行截图如下。
EventType
为64,代表了文件创建事件,文件相关的事件类型码可参考MSDNIrpPtr
是io请求数据包。此属性用来标识io活动。TTID
是创建该文件的线程ID,可通过函数GetProcessIdOfThread
获取到对应的进程ID。FileObject
是文件标识符,用来关联到文件创建和关闭事件之间的文件对象实例。CreateOptions
是调用NTCreateFile
函数时传入的CreateOptions
和CreateDispositions
参数。FileAttributes
是调用NTCreateFile
函数时传入的FileAttributes
参数。ShareAccess
是调用NTCreateFile
函数时传入的ShareAccess
参数。OpenPath
是要打开的文件路径,这里的路径是DOS设备路径,可转为逻辑路径。
本例主要关注文件的创建事件,如果希望获取其他信息,可以在设置trace_config->EnableFlags
时,指定其他的Flag标志,Flag标志可参考MSDN。
在代码中直接修改EnableFlags
字段的值即可,通过修改为EVENT_TRACE_FLAG_IMAGE_LOAD
可以获取dll加载的相关信息,测试结果如下图所示。
通过修改为EVENT_TRACE_FLAG_PROCESS
可以获取进程的相关信息,测试结果如下。
通过修改为EVENT_TRACE_FLAG_NETWORK_TCPIP
可以获得网络的相关信息。
其他应用
根据网上资料,发现有根据ETW获取键盘按键信息的文章,文章中提供了C#的测试代码,执行效果如下:
在测试中发现按键信息的记录稍有延迟,在另一篇文章上看到该方法目前已经被杀软封杀。
使用virustotal检测后,共66款杀软,其中10款报毒(10款为18年结论,现在则有45款杀软报毒),详细信息见链接。
根据文章,该代码的基本原理是,操作系统中默认提供了很多的Providers,查看系统上提供了哪些Providers可以在命令行中使用命令logman query providers
查看。
这些Providers中有一些和USB相关,其主要目的是用来提供调试驱动和总线的一些问题的。
这些USB相关的Providers中,有两个比较特殊,分别是:
Microsoft-Windows-USB-UCX
(36DA592D-E43A-4E28-AF6F-4BC57C5A11E8)Microsoft-Windows-USB-USBPORT
(C88A4EF5-D048-4013-9408-E04B7DB2814A)
第一个provider是USB3.0相关的,第二个则是USB2.0相关的。通过研究这两个provider的数据,发现数据中有疑似USB键盘和鼠标输入的数据。
该代码的原理也就是获取这两个provider的数据,对数据进行过滤分析后,得到了其中键盘的按键信息。