您的位置:首页 > 其它

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的。
 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.

ValueMeaning
TRACE_LEVEL_CRITICAL1Abnormal exit or termination events
TRACE_LEVEL_ERROR2Severe error events
TRACE_LEVEL_WARNING3Warning events such as allocation failures
TRACE_LEVEL_INFORMATION4Non-error events such as entry or exit events
TRACE_LEVEL_VERBOSE5Detailed trace 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结构里有很多信息,主要用于区别不同日志信息,结构定义如下:
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 使软件开发者能够动态地启用和禁用日志记录,轻松地在实际生产环境下进行详细跟踪问题并快速分析与解决。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dlp etw trace
相关文章推荐