Win7、win10下利用ETW Trace跟踪用户的文件读写信息
2017-06-30 22:37
274 查看
发表于freebuf : http://www.freebuf.com/column/138862.html
Windows® 事件跟踪
(ETW) 是操作系统提供的一个高速通用的跟踪工具。ETW 使用内核中实现的缓冲和日志记录机制,提供对用户模式应用程序和内核模式设备驱动程序引发的事件的跟踪机制。自windows2000开始,各种核心的操作系统和服务器组件开始纷纷采用 ETW 对其活动进行检测。ETW 主要包含四种类型的组件:事件提供程序、控制器、使用者和事件跟踪会话。
ETW主要包括3个component:Controller,
Provider, and Consumer,下面我就以文件读写为例进行讲解使用过程。
一、 Controller
使用StartTrace在内存创建一个Event
Session,这个时候session是没有关联任何Provider的。
看该函数的第三个参数类型PEVENT_TRACE_PROPERTIES,EVENT_TRACE_PROPERTIES的结构体定义如下:
所以在创建调用StartTrace 之前需要分配一定的该结构内存,按照MSDN的介绍至少要填写该结构体的一下几个字段
需要定义一个sessionname,即:
#define SESSION_NAME_FILE L”Test_FileTrace_Sample”
ULONG uBufferSize = sizeof(EVENT_TRACE_PROPERTIES)
+ 20*MAX_PATH*sizeof(TCHAR);
EVENT_TRACE_PROPERTIES pTraceConfig
= new char[uBufferSize];
if(pTraceConfig ){
ZeroMemory(pTraceConfig, uBufferSize);
pTraceConfig->Wnode.BufferSize = uBufferSize;
pTraceConfig->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
pTraceConfig->Wnode.ClientContext =
3;
pTraceConfig->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
pTraceConfig->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
pTraceConfig->FlushTimer =
1;
wcsncpy((LPWSTR)((char*)pTraceConfig + pTraceConfig->LoggerNameOffset), SESSION_NAME_FILE, wcslen(SESSION_NAME_FILE));
接下来就可以使用StartTrace去创建内存Session了,
TRACEHANDLE hSessionHandle
HRESULT hr =
::StartTrace(
(PTRACEHANDLE)&hSessionHandle,
SESSION_NAME_FILE,
pTraceConfig);
Controller的第二步是启动(API:
EnableTrace)和停止(API: ControlTrace)Provider(它是使用Provider的GUID来区分不同的provider的)。
如果StartTrace直接创建成功我们就可以直接调用EnableTrace去开启想要监控的事件Provider
Guid,如果StartTrace创建失败过程中,如果返回的错误值是ERROR_ALREADY_EXISTS,就必须调用ControlTrace去停止当前已经的Sessions事件实例,如下
hr = ::StartTrace(
(PTRACEHANDLE)&hSessionHandle,
SESSION_NAME_FILE,
pTraceConfig);
if( hr == ERROR_ALREADY_EXISTS )
{
hr =
::ControlTrace(
(TRACEHANDLE)NULL,
SESSION_NAME_FILE,
pTraceConfig,
EVENT_TRACE_CONTROL_STOP);
if (SUCCEEDED(hr))
{
hr = ::StartTrace(
(PTRACEHANDLE)&hSessionHandle,
SESSION_NAME_FILE,
pTraceConfig);
}
注意第1、3、4、5这几个参数,必须填写的参数
ProviderId [in]
GUID of the event trace provider that you want to enableor disable.
TraceHandle [in]
Handle of the event tracing session to which you want toenable or disable the provider. The StartTrace functionreturns
this handle.
IsEnabled [in]
Set to 1 to receive events when the provider isregistered; otherwise, set to 0 to no longer receive events from the provider.
Level [in]
Provider-definedvalue that specifies the level of detail included in the event. Specify one ofthe following levels that are defined in Winmeta.h. Higher numbers
imply thatyou get lower levels as well. For example, if you specify TRACE_LEVEL_WARNING,you also receive all warning, error,and critical events.
按照msdn的说明,我们监控的是文件读写,因为文件内核的ETW日志GUID是
DEFINE_GUID( /*90cbdc39-4a3e-11d1-84f4-0000f80464e3
*/
FileIoGuid,
0x90cbdc39,
0x4a3e,
0x11d1,
0×84, 0xf4, 0×00, 0×00, 0xf8, 0×04,0×64, 0xe3
);
那么第一参数就是&FileProvGuid,我们第三个参数就是前面创建hSessionHandle,第四个参数就是TRUE,第五个参数根据日志Level填写,我们选择的是TRACE_LEVEL_INFORMATION,那么代码就可以写为:
rc = ::EnableTraceEx(
&FileProvGuid,
NULL,
hSessionHandle,
1,
TRACE_LEVEL_INFORMATION,
0,
0,
0,
0);
if (ERROR_SUCCESS != rc)
{
LOG_F(LS_WARNING) << “Failed
to set file trace callback,rc: “ << rc;
}
一、 Consumer
使用OpenTrace 打开事件通道
第一个参数结构体 EVENT_TRACE_LOGFILE ,该结构主要定义着事件接受事件的方式,可以是文件也可以是内存,也可以是通过设置回调接口去获得信息,本文主要是通过毁掉接口是获取信息,调用方式为:
EVENT_TRACE_LOGFILE trace;
ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));
trace.LoggerName = SESSION_NAME_FILE;
trace.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
trace.EventRecordCallback = ProcessRecordEvents;
trace.LogFileMode |=
0x10000000u;
hTraceHandle =
::OpenTrace(&trace);
if (hTraceHandle == NULL)
{
LOG_F(LS_WARNING) << ::GetLastError();
}
EVENT_TRACE_REAL_TIME_MODE 表示实时获取数据,ProcessRecordEvents接收信息的回调函数,定义如下:
Void ProcessRecordEvents2(PEVENT_RECORD EventRecord);
接下来就是使用processTrace去开启监控,调用如下
rc = ::ProcessTrace(&hTraceHandle,
1, 0, 0);
调用成功会有数据进入回调ProcessRecordEvents函数
EVENT_RECORD结构里有很多信息,主要用于区别不同日志信息,结构定义如下:
在EVENT_HEADER里有进程相关的信息,有文件操作码的信息:
比如本文监控文件读写信息:
EventRecord->EventHeader.EventDescriptor.Id == 0xA表示读文件
EventRecord->EventHeader.EventDescriptor.Id == 0xB表示写文件
还有一个重要的数据结构是EventRecord-> UserDataLength 和EventRecord-> UserData,这个就是我们想要的日志信息的数据大小和具体数据
得到的文件名是:\Device\HarddiskVolume1\Windows\System32\LogFiles\WM.I\RtBackup\EtwRTWDC_8060FileTrace000-9878654.etl
你会发现获得的名字是带Nt Device符号链接的路径的名字,因为这个是直接从windows的文件系统内打印的出来日志,所以带Nt Device符号的名字,只需要私用QueryDosDevice去转换获取对应的盘符的Nt Device链接去取代这个就可以获得应用层的对应名字,即
c:\ \Windows\System32\LogFiles\WM.I\RtBackup\EtwRTWDC_8060FileTrace000-9878654.etl
至此我们获取了windows的文件读写操作。
通过本文的方法我们还能监控很多windows的相应事件信息,ETW诊断的目的就是方便windows软件开发者在正常情况下或者无法预料的情况下能够通过ETW事件去分析诊断软件或者系统的各种问题,也可以用来对软件的性能进行完整记录与分析,ETW 使软件开发者能够动态地启用和禁用日志记录,轻松地在实际生产环境下进行详细跟踪问题并快速分析与解决。
Windows® 事件跟踪
(ETW) 是操作系统提供的一个高速通用的跟踪工具。ETW 使用内核中实现的缓冲和日志记录机制,提供对用户模式应用程序和内核模式设备驱动程序引发的事件的跟踪机制。自windows2000开始,各种核心的操作系统和服务器组件开始纷纷采用 ETW 对其活动进行检测。ETW 主要包含四种类型的组件:事件提供程序、控制器、使用者和事件跟踪会话。
ETW主要包括3个component:Controller,
Provider, and Consumer,下面我就以文件读写为例进行讲解使用过程。
一、 Controller
使用StartTrace在内存创建一个Event
Session,这个时候session是没有关联任何Provider的。
ULONG StartTrace( _ Out_ PTRACEHANDLE SessionHandle, _In_ LPCTSTR SessionName, _Inout_ PEVENT_TRACE_PROPERTIES Properties );
看该函数的第三个参数类型PEVENT_TRACE_PROPERTIES,EVENT_TRACE_PROPERTIES的结构体定义如下:
typedef struct _EVENT_TRACE_PROPERTIES { WNODE_HEADER Wnode; ULONG BufferSize; ULONG MinimumBuffers; ULONG MaximumBuffers; ULONG MaximumFileSize; ULONG LogFileMode; ULONG FlushTimer; ULONG EnableFlags; LONG AgeLimit; ULONG NumberOfBuffers; ULONG FreeBuffers; ULONG EventsLost; ULONG BuffersWritten; ULONG LogBuffersLost; ULONG RealTimeBuffersLost; HANDLE LoggerThreadId; ULONG LogFileNameOffset; ULONG LoggerNameOffset; } EVENT_TRACE_PROPERTIES, *PEVENT_TRACE_PROPERTIES;
所以在创建调用StartTrace 之前需要分配一定的该结构内存,按照MSDN的介绍至少要填写该结构体的一下几个字段
需要定义一个sessionname,即:
#define SESSION_NAME_FILE L”Test_FileTrace_Sample”
ULONG uBufferSize = sizeof(EVENT_TRACE_PROPERTIES)
+ 20*MAX_PATH*sizeof(TCHAR);
EVENT_TRACE_PROPERTIES pTraceConfig
= new char[uBufferSize];
if(pTraceConfig ){
ZeroMemory(pTraceConfig, uBufferSize);
pTraceConfig->Wnode.BufferSize = uBufferSize;
pTraceConfig->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
pTraceConfig->Wnode.ClientContext =
3;
pTraceConfig->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
pTraceConfig->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
pTraceConfig->FlushTimer =
1;
wcsncpy((LPWSTR)((char*)pTraceConfig + pTraceConfig->LoggerNameOffset), SESSION_NAME_FILE, wcslen(SESSION_NAME_FILE));
接下来就可以使用StartTrace去创建内存Session了,
TRACEHANDLE hSessionHandle
HRESULT hr =
::StartTrace(
(PTRACEHANDLE)&hSessionHandle,
SESSION_NAME_FILE,
pTraceConfig);
Controller的第二步是启动(API:
EnableTrace)和停止(API: ControlTrace)Provider(它是使用Provider的GUID来区分不同的provider的)。
如果StartTrace直接创建成功我们就可以直接调用EnableTrace去开启想要监控的事件Provider
Guid,如果StartTrace创建失败过程中,如果返回的错误值是ERROR_ALREADY_EXISTS,就必须调用ControlTrace去停止当前已经的Sessions事件实例,如下
hr = ::StartTrace(
(PTRACEHANDLE)&hSessionHandle,
SESSION_NAME_FILE,
pTraceConfig);
if( hr == ERROR_ALREADY_EXISTS )
{
hr =
::ControlTrace(
(TRACEHANDLE)NULL,
SESSION_NAME_FILE,
pTraceConfig,
EVENT_TRACE_CONTROL_STOP);
if (SUCCEEDED(hr))
{
hr = ::StartTrace(
(PTRACEHANDLE)&hSessionHandle,
SESSION_NAME_FILE,
pTraceConfig);
}
下面就是EnableTrace开启我们需要监控的事件Id,win7和win10 我们一般使用的是EnableTraceEx,该函数定义:
注意第1、3、4、5这几个参数,必须填写的参数
ProviderId [in]
GUID of the event trace provider that you want to enableor disable.
TraceHandle [in]
Handle of the event tracing session to which you want toenable or disable the provider. The StartTrace functionreturns
this handle.
IsEnabled [in]
Set to 1 to receive events when the provider isregistered; otherwise, set to 0 to no longer receive events from the provider.
Level [in]
Provider-definedvalue that specifies the level of detail included in the event. Specify one ofthe following levels that are defined in Winmeta.h. Higher numbers
imply thatyou get lower levels as well. For example, if you specify TRACE_LEVEL_WARNING,you also receive all warning, error,and critical events.
Value | Meaning |
---|---|
TRACE_LEVEL_CRITICAL1 | Abnormal exit or termination events |
TRACE_LEVEL_ERROR2 | Severe error events |
TRACE_LEVEL_WARNING3 | Warning events such as allocation failures |
TRACE_LEVEL_INFORMATION4 | Non-error events such as entry or exit events |
TRACE_LEVEL_VERBOSE5 | Detailed trace events |
DEFINE_GUID( /*90cbdc39-4a3e-11d1-84f4-0000f80464e3
*/
FileIoGuid,
0x90cbdc39,
0x4a3e,
0x11d1,
0×84, 0xf4, 0×00, 0×00, 0xf8, 0×04,0×64, 0xe3
);
那么第一参数就是&FileProvGuid,我们第三个参数就是前面创建hSessionHandle,第四个参数就是TRUE,第五个参数根据日志Level填写,我们选择的是TRACE_LEVEL_INFORMATION,那么代码就可以写为:
rc = ::EnableTraceEx(
&FileProvGuid,
NULL,
hSessionHandle,
1,
TRACE_LEVEL_INFORMATION,
0,
0,
0,
0);
if (ERROR_SUCCESS != rc)
{
LOG_F(LS_WARNING) << “Failed
to set file trace callback,rc: “ << rc;
}
一、 Consumer
使用OpenTrace 打开事件通道
第一个参数结构体 EVENT_TRACE_LOGFILE ,该结构主要定义着事件接受事件的方式,可以是文件也可以是内存,也可以是通过设置回调接口去获得信息,本文主要是通过毁掉接口是获取信息,调用方式为:
EVENT_TRACE_LOGFILE trace;
ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));
trace.LoggerName = SESSION_NAME_FILE;
trace.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
trace.EventRecordCallback = ProcessRecordEvents;
trace.LogFileMode |=
0x10000000u;
hTraceHandle =
::OpenTrace(&trace);
if (hTraceHandle == NULL)
{
LOG_F(LS_WARNING) << ::GetLastError();
}
EVENT_TRACE_REAL_TIME_MODE 表示实时获取数据,ProcessRecordEvents接收信息的回调函数,定义如下:
Void ProcessRecordEvents2(PEVENT_RECORD EventRecord);
接下来就是使用processTrace去开启监控,调用如下
rc = ::ProcessTrace(&hTraceHandle,
1, 0, 0);
调用成功会有数据进入回调ProcessRecordEvents函数
EVENT_RECORD结构里有很多信息,主要用于区别不同日志信息,结构定义如下:
typedef struct _EVENT_RECORD { EVENT_HEADER EventHeader; ETW_BUFFER_CONTEXT BufferContext; USHORT ExtendedDataCount; USHORT UserDataLength; PEVENT_HEADER_EXTENDED_DATA_ITEM ExtendedData; PVOID UserData; PVOID UserContext; } EVENT_RECORD, *PEVENT_RECORD;
在EVENT_HEADER里有进程相关的信息,有文件操作码的信息:
typedef struct _EVENT_HEADER { USHORT Size; USHORT HeaderType; USHORT Flags; USHORT EventProperty; ULONG ThreadId; 线程id ULONG ProcessId; 进程id LARGE_INTEGER TimeStamp; GUID ProviderId; EVENT_DESCRIPTOR EventDescriptor; 操作码描述 union { struct { ULONG KernelTime; ULONG UserTime; }; ULONG64 ProcessorTime; }; GUID ActivityId; } EVENT_HEADER, *PEVENT_HEADER;
比如本文监控文件读写信息:
EventRecord->EventHeader.EventDescriptor.Id == 0xA表示读文件
EventRecord->EventHeader.EventDescriptor.Id == 0xB表示写文件
还有一个重要的数据结构是EventRecord-> UserDataLength 和EventRecord-> UserData,这个就是我们想要的日志信息的数据大小和具体数据
得到的文件名是:\Device\HarddiskVolume1\Windows\System32\LogFiles\WM.I\RtBackup\EtwRTWDC_8060FileTrace000-9878654.etl
你会发现获得的名字是带Nt Device符号链接的路径的名字,因为这个是直接从windows的文件系统内打印的出来日志,所以带Nt Device符号的名字,只需要私用QueryDosDevice去转换获取对应的盘符的Nt Device链接去取代这个就可以获得应用层的对应名字,即
c:\ \Windows\System32\LogFiles\WM.I\RtBackup\EtwRTWDC_8060FileTrace000-9878654.etl
至此我们获取了windows的文件读写操作。
通过本文的方法我们还能监控很多windows的相应事件信息,ETW诊断的目的就是方便windows软件开发者在正常情况下或者无法预料的情况下能够通过ETW事件去分析诊断软件或者系统的各种问题,也可以用来对软件的性能进行完整记录与分析,ETW 使软件开发者能够动态地启用和禁用日志记录,轻松地在实际生产环境下进行详细跟踪问题并快速分析与解决。
相关文章推荐
- 利用POI对MS Excel进行读写(可以设置写入文件的样式),利用tm-extractor对Word进行读取操作并将信息用(log4j)日志信息显示出
- 利用samba实现Ubuntu和win7文件共享配置过程
- "无法启动应用程序,工作组信息文件丢失,或是已被其他用户已独占方式打开"解决办法
- 利用JDK7的NIO2.0进行I/O读写和文件操作监控
- 利用ThreadLocal管理request和session以及用户信息,实现 Use anywhere
- 用户调研:利用选择题进行信息关注度研究案例解析
- 解析用PHP读写音频文件信息的详解(支持WMA和MP3)
- Installshield x:实现序列号检验,获取用户信息并写入指定_ini文件1 - 子夜 MySpace聚友博客
- mp3文件后128字节歌曲信息读写操作
- Git利用.gitignore不跟踪某些文件(以及不生效的解决办法)
- Linux 用户和用户组,以及目录或文件的权限配置信息
- 利用Jakarta Commons Digester匹配xml配置文件信息与其对应的xml规则文件形成Java Object
- Linux用户相关文件之用户信息文件
- 使用TraceListener 自动保存跟踪信息到文件中
- 利用C++标准符号,把调试信息输出到文件
- 利用FSO取得BMP,JPG,PNG,GIF文件信息
- 利用FSO取得BMP,JPG,PNG,GIF文件信息
- JSP中利用Properties读写配置文件
- java Web项目中,利用其过滤功能,实现访问者每次访问服务器时,记录访问者的IP,访问时间,Url等信息,并保存到文件的操作
- hadoop利用FileSystem API 执行hadoop文件读写操作