zoukankan      html  css  js  c++  java
  • Windows ETW 学习与使用一

    ETW的学习和使用也有段时间了,在网上资料都比较零散,这里就对ETW相关知识做一个整理,方便积累和使用.

    一、Windows ETW基础知识

    1.下面是微软的文档对于ETW可以分为三部分Controller、Provider、Consumer,Provider是事件的提供者,Controller创建一会会话打开相关的ETW,Consumer使用Controller的会话,并解析ETW数据。

    Using Event Tracing

    二.Controller

    2.1 配置打开Manifest-based或者Classic的ETW

    Example that Creates a Session and Enables a Manifest-based or Classic Provider

    该方法可以自定义一个LOGSESSION_NAME,通过EnableTraceEx2传入一个需要监控的ProviderGuid,并传入EVENT_CONTROL_CODE_ENABLE_PROVIDER来开启该ETW的监控,需要注意有时候不同ETW事件的开启需要的权限会不同,不同的事件ETW,可以通过EnableTraceEx2的参数来进行过滤。

    可以通过logman query providers指令查询系统上所有的Provider的Guid

    #include <windows.h>
    #include <stdio.h>
    #include <conio.h>
    #include <strsafe.h>
    #include <wmistr.h>
    #include <evntrace.h>
    
    #define LOGFILE_PATH L"<FULLPATHTOLOGFILE.etl>"
    #define LOGSESSION_NAME L"My Event Trace Session"
    
    // GUID that identifies your trace session.
    // Remember to create your own session GUID.
    
    // {AE44CB98-BD11-4069-8093-770EC9258A12}
    static const GUID SessionGuid = 
    { 0xae44cb98, 0xbd11, 0x4069, { 0x80, 0x93, 0x77, 0xe, 0xc9, 0x25, 0x8a, 0x12 } };
    
    // GUID that identifies the provider that you want
    // to enable to your session.
    
    // {D8909C24-5BE9-4502-98CA-AB7BDC24899D}
    static const GUID ProviderGuid = 
    { 0xd8909c24, 0x5be9, 0x4502, {0x98, 0xca, 0xab, 0x7b, 0xdc, 0x24, 0x89, 0x9d } };
    
    void wmain(void)
    {
        ULONG status = ERROR_SUCCESS;
        TRACEHANDLE SessionHandle = 0;
        EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
        ULONG BufferSize = 0;
        BOOL TraceOn = TRUE;
    
        // Allocate memory for the session properties. The memory must
        // be large enough to include the log file name and session name,
        // which get appended to the end of the session properties structure.
        
        BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(LOGSESSION_NAME);
        pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);    
        if (NULL == pSessionProperties)
        {
            wprintf(L"Unable to allocate %d bytes for properties structure.
    ", BufferSize);
            goto cleanup;
        }
        
        // Set the session properties. You only append the log file name
        // to the properties structure; the StartTrace function appends
        // the session name for you.
    
        ZeroMemory(pSessionProperties, BufferSize);
        pSessionProperties->Wnode.BufferSize = BufferSize;
        pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
        pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
        pSessionProperties->Wnode.Guid = SessionGuid; 
        pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
        pSessionProperties->MaximumFileSize = 1;  // 1 MB
        pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
        pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME); 
        StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);
    
        // Create the trace session.
    
        status = StartTrace((PTRACEHANDLE)&SessionHandle, LOGSESSION_NAME, pSessionProperties);
        if (ERROR_SUCCESS != status)
        {
            wprintf(L"StartTrace() failed with %lu
    ", status);
            goto cleanup;
        }
    
        // Enable the providers that you want to log events to your session.
    
        status = EnableTraceEx2(
            SessionHandle,
            (LPCGUID)&ProviderGuid,
            EVENT_CONTROL_CODE_ENABLE_PROVIDER,
            TRACE_LEVEL_INFORMATION,
            0,
            0,
            0,
            NULL
            );
    
        if (ERROR_SUCCESS != status)
        {
            wprintf(L"EnableTrace() failed with %lu
    ", status);
            TraceOn = FALSE;
            goto cleanup;
        }
    
        wprintf(L"Run the provider application. Then hit any key to stop the session.
    ");
        _getch();
    
    cleanup:
    
        if (SessionHandle)
        {
            if (TraceOn)
            {
                status = EnableTraceEx2(
                    SessionHandle,
                    (LPCGUID)&ProviderGuid,
                    EVENT_CONTROL_CODE_DISABLE_PROVIDER,
                    TRACE_LEVEL_INFORMATION,
                    0,
                    0,
                    0,
                    NULL
                    );
            }
    
            status = ControlTrace(SessionHandle, LOGSESSION_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
    
            if (ERROR_SUCCESS != status)
            {
                wprintf(L"ControlTrace(stop) failed with %lu
    ", status);
            }
        }
    
        if (pSessionProperties)
        {
            free(pSessionProperties);
            pSessionProperties = NULL;
        }
    }

    2.2 配置打开NT Kernel Logger

    Configuring and Starting the NT Kernel Logger Session

    这种方法StartTrace传入的必须是KERNEL_LOGGER_NAME,不需要使用EnableTraceEx2来开启,通过pSessionProperties->EnableFlags = EVENT_TRACE_FLAG_NETWORK_TCPIP字段来指定需要关注的etw事件,可以指定监控的Flags枚举如下:

    //
    // Event types for system configuration records
    //
    #define EVENT_TRACE_TYPE_CONFIG_CPU             0x0A     // CPU Configuration
    #define EVENT_TRACE_TYPE_CONFIG_PHYSICALDISK    0x0B     // Physical Disk Configuration
    #define EVENT_TRACE_TYPE_CONFIG_LOGICALDISK     0x0C     // Logical Disk Configuration
    #define EVENT_TRACE_TYPE_CONFIG_NIC             0x0D     // NIC Configuration
    #define EVENT_TRACE_TYPE_CONFIG_VIDEO           0x0E     // Video Adapter Configuration
    #define EVENT_TRACE_TYPE_CONFIG_SERVICES        0x0F     // Active Services
    #define EVENT_TRACE_TYPE_CONFIG_POWER           0x10     // ACPI Configuration
    #define EVENT_TRACE_TYPE_CONFIG_NETINFO         0x11     // Networking Configuration
    
    #define EVENT_TRACE_TYPE_CONFIG_IRQ             0x15     // IRQ assigned to devices
    #define EVENT_TRACE_TYPE_CONFIG_PNP             0x16     // PnP device info
    #define EVENT_TRACE_TYPE_CONFIG_IDECHANNEL      0x17     // Primary/Secondary IDE channel Configuration
    #define EVENT_TRACE_TYPE_CONFIG_PLATFORM        0x19     // Platform Configuration
    
    //
    // Enable flags for Kernel Events
    //
    #define EVENT_TRACE_FLAG_PROCESS            0x00000001  // process start & end
    #define EVENT_TRACE_FLAG_THREAD             0x00000002  // thread start & end
    #define EVENT_TRACE_FLAG_IMAGE_LOAD         0x00000004  // image load
    
    #define EVENT_TRACE_FLAG_DISK_IO            0x00000100  // physical disk IO
    #define EVENT_TRACE_FLAG_DISK_FILE_IO       0x00000200  // requires disk IO
    
    #define EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS 0x00001000  // all page faults
    #define EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS 0x00002000  // hard faults only
    
    #define EVENT_TRACE_FLAG_NETWORK_TCPIP      0x00010000  // tcpip send & receive
    
    #define EVENT_TRACE_FLAG_REGISTRY           0x00020000  // registry calls
    #define EVENT_TRACE_FLAG_DBGPRINT           0x00040000  // DbgPrint(ex) Calls
    
    //
    // Enable flags for Kernel Events on Vista and above 
    //
    #define EVENT_TRACE_FLAG_PROCESS_COUNTERS   0x00000008  // process perf counters
    #define EVENT_TRACE_FLAG_CSWITCH            0x00000010  // context switches 
    #define EVENT_TRACE_FLAG_DPC                0x00000020  // deffered procedure calls 
    #define EVENT_TRACE_FLAG_INTERRUPT          0x00000040  // interrupts
    #define EVENT_TRACE_FLAG_SYSTEMCALL         0x00000080  // system calls
    
    #define EVENT_TRACE_FLAG_DISK_IO_INIT       0x00000400  // physical disk IO initiation
    
    #define EVENT_TRACE_FLAG_ALPC               0x00100000  // ALPC traces
    #define EVENT_TRACE_FLAG_SPLIT_IO           0x00200000  // split io traces (VolumeManager)
    
    #define EVENT_TRACE_FLAG_DRIVER             0x00800000  // driver delays
    #define EVENT_TRACE_FLAG_PROFILE            0x01000000  // sample based profiling
    #define EVENT_TRACE_FLAG_FILE_IO            0x02000000  // file IO
    #define EVENT_TRACE_FLAG_FILE_IO_INIT       0x04000000  // file IO initiation
    
    //
    // Enable flags for Kernel Events on Win7 and above
    //
    #define EVENT_TRACE_FLAG_DISPATCHER         0x00000800  // scheduler (ReadyThread)
    #define EVENT_TRACE_FLAG_VIRTUAL_ALLOC      0x00004000  // VM operations
    
    //
    // Pre-defined Enable flags for everybody else
    //
    #define EVENT_TRACE_FLAG_EXTENSION          0x80000000  // Indicates more flags
    #define EVENT_TRACE_FLAG_FORWARD_WMI        0x40000000  // Can forward to WMI
    #define EVENT_TRACE_FLAG_ENABLE_RESERVE     0x20000000  // Reserved
    View Code
    #define INITGUID  // Include this #define to use SystemTraceControlGuid in Evntrace.h.
    
    #include <windows.h>
    #include <stdio.h>
    #include <conio.h>
    #include <strsafe.h>
    #include <wmistr.h>
    #include <evntrace.h>
    
    #define LOGFILE_PATH L"<FULLPATHTOTHELOGFILE.etl>"
    
    void wmain(void)
    {
        ULONG status = ERROR_SUCCESS;
        TRACEHANDLE SessionHandle = 0;
        EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
        ULONG BufferSize = 0;
    
        // Allocate memory for the session properties. The memory must
        // be large enough to include the log file name and session name,
        // which get appended to the end of the session properties structure.
        
        BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(KERNEL_LOGGER_NAME);
        pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);    
        if (NULL == pSessionProperties)
        {
            wprintf(L"Unable to allocate %d bytes for properties structure.
    ", BufferSize);
            goto cleanup;
        }
        
        // Set the session properties. You only append the log file name
        // to the properties structure; the StartTrace function appends
        // the session name for you.
    
        ZeroMemory(pSessionProperties, BufferSize);
        pSessionProperties->Wnode.BufferSize = BufferSize;
        pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
        pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
        pSessionProperties->Wnode.Guid = SystemTraceControlGuid; 
        pSessionProperties->EnableFlags = EVENT_TRACE_FLAG_NETWORK_TCPIP;
        pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
        pSessionProperties->MaximumFileSize = 5;  // 5 MB
        pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
        pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(KERNEL_LOGGER_NAME); 
        StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);
    
        // Create the trace session.
    
        status = StartTrace((PTRACEHANDLE)&SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties);
    
        if (ERROR_SUCCESS != status)
        {
            if (ERROR_ALREADY_EXISTS == status)
            {
                wprintf(L"The NT Kernel Logger session is already in use.
    ");
            }
            else
            {
                wprintf(L"EnableTrace() failed with %lu
    ", status);
            }
    
            goto cleanup;
        }
    
        wprintf(L"Press any key to end trace session ");
        _getch();
    
    cleanup:
    
        if (SessionHandle)
        {
            status = ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
    
            if (ERROR_SUCCESS != status)
            {
                wprintf(L"ControlTrace(stop) failed with %lu
    ", status);
            }
        }
    
        if (pSessionProperties)
            free(pSessionProperties);
    }

    三、Consumer

    3.1 TdhFormatProperty

    Using TdhFormatProperty to Consume Event Data

    这种方法可以使用TdhFormatProperty对指定LOGGER_NAME或者LOGFILE_PATH的Etw进行解析

    //Turns the DEFINE_GUID for EventTraceGuid into a const.
    #define INITGUID
    
    #include <windows.h>
    #include <stdio.h>
    #include <wbemidl.h>
    #include <wmistr.h>
    #include <evntrace.h>
    #include <tdh.h>
    #include <in6addr.h>
    
    #pragma comment(lib, "tdh.lib")
    
    #define LOGFILE_PATH L"C:\Code\etw\V2EventTraceController\mylogfile.etl"
    
    // Used to calculate CPU usage
    
    ULONG g_TimerResolution = 0;
    
    // Used to determine if the session is a private session or kernel session.
    // You need to know this when accessing some members of the EVENT_TRACE.Header
    // member (for example, KernelTime or UserTime).
    
    BOOL g_bUserMode = FALSE;
    
    // Handle to the trace file that you opened.
    
    TRACEHANDLE g_hTrace = 0;  
    
    // Prototypes
    
    void WINAPI ProcessEvent(PEVENT_RECORD pEvent);
    DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo);
    PBYTE PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, DWORD PointerSize, USHORT i, PBYTE pUserData, PBYTE pEndOfUserData);
    DWORD GetPropertyLength(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT PropertyLength);
    DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize);
    DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO & pMapInfo);
    void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo);
    
    void wmain(void)
    {
        TDHSTATUS status = ERROR_SUCCESS;
        EVENT_TRACE_LOGFILE trace;
        TRACE_LOGFILE_HEADER* pHeader = &trace.LogfileHeader;
    
        // Identify the log file from which you want to consume events
        // and the callbacks used to process the events and buffers.
    
        ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));
        trace.LogFileName = (LPWSTR) LOGFILE_PATH;
        trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK) (ProcessEvent);
        trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;
    
        g_hTrace = OpenTrace(&trace);
        if (INVALID_PROCESSTRACE_HANDLE == g_hTrace)
        {
            wprintf(L"OpenTrace failed with %lu
    ", GetLastError());
            goto cleanup;
        }
    
        g_bUserMode = pHeader->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE;
    
        if (pHeader->TimerResolution > 0)
        {
            g_TimerResolution = pHeader->TimerResolution / 10000;
        }
    
        wprintf(L"Number of events lost:  %lu
    ", pHeader->EventsLost);
    
        // Use pHeader to access all fields prior to LoggerName.
        // Adjust pHeader based on the pointer size to access
        // all fields after LogFileName. This is required only if
        // you are consuming events on an architecture that is 
        // different from architecture used to write the events.
    
        if (pHeader->PointerSize != sizeof(PVOID))
        {
            pHeader = (PTRACE_LOGFILE_HEADER)((PUCHAR)pHeader +
                2 * (pHeader->PointerSize - sizeof(PVOID)));
        }
    
        wprintf(L"Number of buffers lost: %lu
    
    ", pHeader->BuffersLost);
    
        status = ProcessTrace(&g_hTrace, 1, 0, 0);
        if (status != ERROR_SUCCESS && status != ERROR_CANCELLED)
        {
            wprintf(L"ProcessTrace failed with %lu
    ", status);
            goto cleanup;
        }
    
    cleanup:
    
        if (INVALID_PROCESSTRACE_HANDLE != g_hTrace)
        {
            status = CloseTrace(g_hTrace);
        }
    }
    
    
    // Callback that receives the events. 
    
    VOID WINAPI ProcessEvent(PEVENT_RECORD pEvent)
    {
        DWORD status = ERROR_SUCCESS;
        PTRACE_EVENT_INFO pInfo = NULL;
        LPWSTR pwsEventGuid = NULL;
        PBYTE pUserData = NULL;
        PBYTE pEndOfUserData = NULL;
        DWORD PointerSize = 0;
        ULONGLONG TimeStamp = 0;
        ULONGLONG Nanoseconds = 0;
        SYSTEMTIME st;
        SYSTEMTIME stLocal;
        FILETIME ft;
    
    
        // Skips the event if it is the event trace header. Log files contain this event
        // but real-time sessions do not. The event contains the same information as 
        // the EVENT_TRACE_LOGFILE.LogfileHeader member that you can access when you open 
        // the trace. 
    
        if (IsEqualGUID(pEvent->EventHeader.ProviderId, EventTraceGuid) &&
            pEvent->EventHeader.EventDescriptor.Opcode == EVENT_TRACE_TYPE_INFO)
        {
            ; // Skip this event.
        }
        else
        {
            // Process the event. The pEvent->UserData member is a pointer to 
            // the event specific data, if it exists.
    
            status = GetEventInformation(pEvent, pInfo);
    
            if (ERROR_SUCCESS != status)
            {
                wprintf(L"GetEventInformation failed with %lu
    ", status);
                goto cleanup;
            }
    
            // Determine whether the event is defined by a MOF class, in an
            // instrumentation manifest, or a WPP template; to use TDH to decode
            // the event, it must be defined by one of these three sources.
    
            if (DecodingSourceWbem == pInfo->DecodingSource)  // MOF class
            {
                HRESULT hr = StringFromCLSID(pInfo->EventGuid, &pwsEventGuid);
    
                if (FAILED(hr))
                {
                    wprintf(L"StringFromCLSID failed with 0x%x
    ", hr);
                    status = hr;
                    goto cleanup;
                }
    
                wprintf(L"
    Event GUID: %s
    ", pwsEventGuid);
                CoTaskMemFree(pwsEventGuid);
                pwsEventGuid = NULL;
    
                wprintf(L"Event version: %d
    ", pEvent->EventHeader.EventDescriptor.Version);
                wprintf(L"Event type: %d
    ", pEvent->EventHeader.EventDescriptor.Opcode);
            }
            else if (DecodingSourceXMLFile == pInfo->DecodingSource) // Instrumentation manifest
            {
                wprintf(L"Event ID: %d
    ", pInfo->EventDescriptor.Id);
            }
            else // Not handling the WPP case
            {
                goto cleanup;
            }
    
            // Print the time stamp for when the event occurred.
    
            ft.dwHighDateTime = pEvent->EventHeader.TimeStamp.HighPart;
            ft.dwLowDateTime = pEvent->EventHeader.TimeStamp.LowPart;
    
            FileTimeToSystemTime(&ft, &st);
            SystemTimeToTzSpecificLocalTime(NULL, &st, &stLocal);
    
            TimeStamp = pEvent->EventHeader.TimeStamp.QuadPart;
            Nanoseconds = (TimeStamp % 10000000) * 100;
    
            wprintf(L"%02d/%02d/%02d %02d:%02d:%02d.%I64u
    ", 
                stLocal.wMonth, stLocal.wDay, stLocal.wYear, stLocal.wHour, stLocal.wMinute, stLocal.wSecond, Nanoseconds);
    
            // If the event contains event-specific data use TDH to extract
            // the event data. For this example, to extract the data, the event 
            // must be defined by a MOF class or an instrumentation manifest.
    
            // Need to get the PointerSize for each event to cover the case where you are
            // consuming events from multiple log files that could have been generated on 
            // different architectures. Otherwise, you could have accessed the pointer
            // size when you opened the trace above (see pHeader->PointerSize).
    
            if (EVENT_HEADER_FLAG_32_BIT_HEADER == (pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER))
            {
                PointerSize = 4;
            }
            else
            {
                PointerSize = 8;
            }
    
            pUserData = (PBYTE)pEvent->UserData;
            pEndOfUserData = (PBYTE)pEvent->UserData + pEvent->UserDataLength;
    
            // Print the event data for all the top-level properties. Metadata for all the 
            // top-level properties come before structure member properties in the 
            // property information array.
    
            for (USHORT i = 0; i < pInfo->TopLevelPropertyCount; i++)
            {
                pUserData = PrintProperties(pEvent, pInfo, PointerSize, i, pUserData, pEndOfUserData);
                if (NULL == pUserData)
                {
                    wprintf(L"Printing top level properties failed.
    ");
                    goto cleanup;
                }
            }
        }
    
    cleanup:
    
        if (pInfo)
        {
            free(pInfo);
        }
    
        if (ERROR_SUCCESS != status || NULL == pUserData)
        {
            CloseTrace(g_hTrace);
        }
    }
    
    
    // Print the property.
    
    PBYTE PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, DWORD PointerSize, USHORT i, PBYTE pUserData, PBYTE pEndOfUserData)
    {
        TDHSTATUS status = ERROR_SUCCESS;
        USHORT PropertyLength = 0;
        DWORD FormattedDataSize = 0;
        USHORT UserDataConsumed = 0;
        USHORT UserDataLength = 0;
        LPWSTR pFormattedData = NULL;
        DWORD LastMember = 0;  // Last member of a structure
        USHORT ArraySize = 0;
        PEVENT_MAP_INFO pMapInfo = NULL;
    
    
        // Get the length of the property.
    
        status = GetPropertyLength(pEvent, pInfo, i, &PropertyLength);
        if (ERROR_SUCCESS != status)
        {
            wprintf(L"GetPropertyLength failed.
    ");
            pUserData = NULL;
            goto cleanup;
        }
    
        // Get the size of the array if the property is an array.
    
        status = GetArraySize(pEvent, pInfo, i, &ArraySize);
    
        for (USHORT k = 0; k < ArraySize; k++)
        {
            // If the property is a structure, print the members of the structure.
    
            if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)
            {
                LastMember = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex + 
                    pInfo->EventPropertyInfoArray[i].structType.NumOfStructMembers;
    
                for (USHORT j = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex; j < LastMember; j++)
                {
                    pUserData = PrintProperties(pEvent, pInfo, PointerSize, j, pUserData, pEndOfUserData);
                    if (NULL == pUserData)
                    {
                        wprintf(L"Printing the members of the structure failed.
    ");
                        pUserData = NULL;
                        goto cleanup;
                    }
                }
            }
            else
            {
                // Get the name/value mapping if the property specifies a value map.
    
                status = GetMapInfo(pEvent, 
                    (PWCHAR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset),
                    pInfo->DecodingSource,
                    pMapInfo);
    
                if (ERROR_SUCCESS != status)
                {
                    wprintf(L"GetMapInfo failed
    ");
                    pUserData = NULL;
                    goto cleanup;
                }
    
                // Get the size of the buffer required for the formatted data.
    
                status = TdhFormatProperty(
                    pInfo, 
                    pMapInfo, 
                    PointerSize, 
                    pInfo->EventPropertyInfoArray[i].nonStructType.InType,
                    pInfo->EventPropertyInfoArray[i].nonStructType.OutType,
                    PropertyLength,
                    (USHORT)(pEndOfUserData - pUserData),
                    pUserData,
                    &FormattedDataSize,
                    pFormattedData,
                    &UserDataConsumed);
    
                if (ERROR_INSUFFICIENT_BUFFER == status)
                {
                    if (pFormattedData)
                    {
                        free(pFormattedData);
                        pFormattedData = NULL;
                    }
    
                    pFormattedData = (LPWSTR) malloc(FormattedDataSize);
                    if (pFormattedData == NULL)
                    {
                        wprintf(L"Failed to allocate memory for formatted data (size=%lu).
    ", FormattedDataSize);
                        status = ERROR_OUTOFMEMORY;
                        pUserData = NULL;
                        goto cleanup;
                    }
    
                    // Retrieve the formatted data.
    
                    status = TdhFormatProperty(
                        pInfo, 
                        pMapInfo, 
                        PointerSize, 
                        pInfo->EventPropertyInfoArray[i].nonStructType.InType,
                        pInfo->EventPropertyInfoArray[i].nonStructType.OutType,
                        PropertyLength,
                        (USHORT)(pEndOfUserData - pUserData),
                        pUserData,
                        &FormattedDataSize,
                        pFormattedData,
                        &UserDataConsumed);
                }
    
                if (ERROR_SUCCESS == status)
                {
                    wprintf(L"%s: %s
    ", 
                        (PWCHAR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset),
                        pFormattedData);
    
                    pUserData += UserDataConsumed;
                }
                else
                {
                    wprintf(L"TdhFormatProperty failed with %lu.
    ", status);
                    pUserData = NULL;
                    goto cleanup;
                }
            }
        }
    
    cleanup:
    
        if (pFormattedData)
        {
            free(pFormattedData);
            pFormattedData = NULL;
        }
    
        if (pMapInfo)
        {
            free(pMapInfo);
            pMapInfo = NULL;
        }
    
        return pUserData;
    }
    
    
    // Get the length of the property data. For MOF-based events, the size is inferred from the data type
    // of the property. For manifest-based events, the property can specify the size of the property value
    // using the length attribute. The length attribue can specify the size directly or specify the name 
    // of another property in the event data that contains the size. If the property does not include the 
    // length attribute, the size is inferred from the data type. The length will be zero for variable
    // length, null-terminated strings and structures.
    
    DWORD GetPropertyLength(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT PropertyLength)
    {
        DWORD status = ERROR_SUCCESS;
        PROPERTY_DATA_DESCRIPTOR DataDescriptor;
        DWORD PropertySize = 0;
    
        // If the property is a binary blob and is defined in a manifest, the property can 
        // specify the blob's size or it can point to another property that defines the 
        // blob's size. The PropertyParamLength flag tells you where the blob's size is defined.
    
        if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamLength) == PropertyParamLength)
        {
            DWORD Length = 0;  // Expects the length to be defined by a UINT16 or UINT32
            DWORD j = pInfo->EventPropertyInfoArray[i].lengthPropertyIndex;
            ZeroMemory(&DataDescriptor, sizeof(PROPERTY_DATA_DESCRIPTOR));
            DataDescriptor.PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[j].NameOffset);
            DataDescriptor.ArrayIndex = ULONG_MAX;
            status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize);
            status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Length);
            *PropertyLength = (USHORT)Length;
        }
        else
        {
            if (pInfo->EventPropertyInfoArray[i].length > 0)
            {
                *PropertyLength = pInfo->EventPropertyInfoArray[i].length;
            }
            else
            {
                // If the property is a binary blob and is defined in a MOF class, the extension
                // qualifier is used to determine the size of the blob. However, if the extension 
                // is IPAddrV6, you must set the PropertyLength variable yourself because the 
                // EVENT_PROPERTY_INFO.length field will be zero.
    
                if (TDH_INTYPE_BINARY == pInfo->EventPropertyInfoArray[i].nonStructType.InType &&
                    TDH_OUTTYPE_IPV6 == pInfo->EventPropertyInfoArray[i].nonStructType.OutType)
                {
                    *PropertyLength = (USHORT)sizeof(IN6_ADDR);
                }
                else if (TDH_INTYPE_UNICODESTRING == pInfo->EventPropertyInfoArray[i].nonStructType.InType ||
                         TDH_INTYPE_ANSISTRING == pInfo->EventPropertyInfoArray[i].nonStructType.InType ||
                         (pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)
                {
                    *PropertyLength = pInfo->EventPropertyInfoArray[i].length;
                }
                else
                {
                    wprintf(L"Unexpected length of 0 for intype %d and outtype %d
    ", 
                        pInfo->EventPropertyInfoArray[i].nonStructType.InType,
                        pInfo->EventPropertyInfoArray[i].nonStructType.OutType);
    
                    status = ERROR_EVT_INVALID_EVENT_DATA;
                    goto cleanup;
                }
            }
        }
    
    cleanup:
    
        return status;
    }
    
    
    // Get the size of the array. For MOF-based events, the size is specified in the declaration or using 
    // the MAX qualifier. For manifest-based events, the property can specify the size of the array
    // using the count attribute. The count attribue can specify the size directly or specify the name 
    // of another property in the event data that contains the size.
    
    DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize)
    {
        DWORD status = ERROR_SUCCESS;
        PROPERTY_DATA_DESCRIPTOR DataDescriptor;
        DWORD PropertySize = 0;
    
        if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamCount) == PropertyParamCount)
        {
            DWORD Count = 0;  // Expects the count to be defined by a UINT16 or UINT32
            DWORD j = pInfo->EventPropertyInfoArray[i].countPropertyIndex;
            ZeroMemory(&DataDescriptor, sizeof(PROPERTY_DATA_DESCRIPTOR));
            DataDescriptor.PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[j].NameOffset);
            DataDescriptor.ArrayIndex = ULONG_MAX;
            status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize);
            status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Count);
            *ArraySize = (USHORT)Count;
        }
        else
        {
            *ArraySize = pInfo->EventPropertyInfoArray[i].count;
        }
    
        return status;
    }
    
    
    // Both MOF-based events and manifest-based events can specify name/value maps. The
    // map values can be integer values or bit values. If the property specifies a value
    // map, get the map.
    
    DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO & pMapInfo)
    {
        DWORD status = ERROR_SUCCESS;
        DWORD MapSize = 0;
    
        // Retrieve the required buffer size for the map info.
    
        status = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &MapSize);
    
        if (ERROR_INSUFFICIENT_BUFFER == status)
        {
            pMapInfo = (PEVENT_MAP_INFO) malloc(MapSize);
            if (pMapInfo == NULL)
            {
                wprintf(L"Failed to allocate memory for map info (size=%lu).
    ", MapSize);
                status = ERROR_OUTOFMEMORY;
                goto cleanup;
            }
    
            // Retrieve the map info.
    
            status = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &MapSize);
        }
    
        if (ERROR_SUCCESS == status)
        {
            if (DecodingSourceXMLFile == DecodingSource)
            {
                RemoveTrailingSpace(pMapInfo);
            }
        }
        else
        {
            if  (ERROR_NOT_FOUND == status)
            {
                status = ERROR_SUCCESS; // This case is okay.
            }
            else
            {
                wprintf(L"TdhGetEventMapInformation failed with 0x%x.
    ", status);
            }
        }
    
    cleanup:
    
        return status;
    }
    
    
    // The mapped string values defined in a manifest will contain a trailing space
    // in the EVENT_MAP_ENTRY structure. Replace the trailing space with a null-
    // terminating character, so that the bit mapped strings are correctly formatted.
    
    void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo)
    {
        DWORD ByteLength = 0;
    
        for (DWORD i = 0; i < pMapInfo->EntryCount; i++)
        {
            ByteLength = (wcslen((LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset)) - 1) * 2;
            *((LPWSTR)((PBYTE)pMapInfo + (pMapInfo->MapEntryArray[i].OutputOffset + ByteLength))) = L'';
        }
    }
    
    
    // Get the metadata for the event.
    
    DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo)
    {
        DWORD status = ERROR_SUCCESS;
        DWORD BufferSize = 0;
    
        // Retrieve the required buffer size for the event metadata.
    
        status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);
    
        if (ERROR_INSUFFICIENT_BUFFER == status)
        {
            pInfo = (TRACE_EVENT_INFO*) malloc(BufferSize);
            if (pInfo == NULL)
            {
                wprintf(L"Failed to allocate memory for event info (size=%lu).
    ", BufferSize);
                status = ERROR_OUTOFMEMORY;
                goto cleanup;
            }
    
            // Retrieve the event metadata.
    
            status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);
        }
    
        if (ERROR_SUCCESS != status)
        {
            wprintf(L"TdhGetEventInformation failed with 0x%x.
    ", status);
        }
    
    cleanup:
    
        return status;
    }
    View Code

    3.2 TdhGetProperty 

    Using TdhGetProperty to Consume Event Data

    这种方法可以使用TdhGetProperty对指定LOGGER_NAME或者LOGFILE_PATH的Etw进行解析

    //Turns the DEFINE_GUID for EventTraceGuid into a const.
    #define INITGUID
    
    #include <windows.h>
    #include <stdio.h>
    #include <strsafe.h>
    #include <wbemidl.h>
    #include <wmistr.h>
    #include <evntrace.h>
    #include <tdh.h>
    #include <in6addr.h>
    
    #pragma comment(lib, "tdh.lib")
    #pragma comment(lib, "ws2_32.lib")  // For ntohs function
    
    #define LOGFILE_PATH L"C:\Code\etw\V2EventTraceController\mylogfile.etl"
    
    #define MAX_NAME 256
    
    // Used to determine the data size of property values that contain a
    // Pointer value. The value will be 4 or 8.
    USHORT g_PointerSize = 0;
    
    // Used to calculate CPU usage
    
    ULONG g_TimerResolution = 0;
    
    // Used to determine if the session is a private session or kernel session.
    // You need to know this when accessing some members of the EVENT_TRACE.Header
    // member (for example, KernelTime or UserTime).
    
    BOOL g_bUserMode = FALSE;
    
    // Handle to the trace file that you opened.
    
    TRACEHANDLE g_hTrace = 0;  
    
    
    // Prototypes
    
    void WINAPI ProcessEvent(PEVENT_RECORD pEvent);
    DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo);
    DWORD PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, LPWSTR pStructureName, USHORT StructIndex);
    DWORD FormatAndPrintData(PEVENT_RECORD pEvent, USHORT InType, USHORT OutType, PBYTE pData, DWORD DataSize, PEVENT_MAP_INFO pMapInfo); 
    void PrintMapString(PEVENT_MAP_INFO pMapInfo, PBYTE pData);
    DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize);
    DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO & pMapInfo);
    void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo);
    
    typedef LPTSTR (NTAPI *PIPV6ADDRTOSTRING)(
      const IN6_ADDR *Addr,
      LPTSTR S
    );
    
    
    void wmain(void)
    {
        ULONG status = ERROR_SUCCESS;
        EVENT_TRACE_LOGFILE trace;
        TRACE_LOGFILE_HEADER* pHeader = &trace.LogfileHeader;
    
        // Identify the log file from which you want to consume events
        // and the callbacks used to process the events and buffers.
    
        ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));
        trace.LogFileName = (LPWSTR) LOGFILE_PATH;
        trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK) (ProcessEvent);
        trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;
    
        g_hTrace = OpenTrace(&trace);
        if (INVALID_PROCESSTRACE_HANDLE == g_hTrace)
        {
            wprintf(L"OpenTrace failed with %lu
    ", GetLastError());
            goto cleanup;
        }
    
        g_bUserMode = pHeader->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE;
    
        if (pHeader->TimerResolution > 0)
        {
            g_TimerResolution = pHeader->TimerResolution / 10000;
        }
    
        wprintf(L"Number of events lost:  %lu
    ", pHeader->EventsLost);
    
        // Use pHeader to access all fields prior to LoggerName.
        // Adjust pHeader based on the pointer size to access
        // all fields after LogFileName. This is required only if
        // you are consuming events on an architecture that is 
        // different from architecture used to write the events.
    
        if (pHeader->PointerSize != sizeof(PVOID))
        {
            pHeader = (PTRACE_LOGFILE_HEADER)((PUCHAR)pHeader +
                2 * (pHeader->PointerSize - sizeof(PVOID)));
        }
    
        wprintf(L"Number of buffers lost: %lu
    
    ", pHeader->BuffersLost);
    
        status = ProcessTrace(&g_hTrace, 1, 0, 0);
        if (status != ERROR_SUCCESS && status != ERROR_CANCELLED)
        {
            wprintf(L"ProcessTrace failed with %lu
    ", status);
            goto cleanup;
        }
    
    cleanup:
    
        if (INVALID_PROCESSTRACE_HANDLE != g_hTrace)
        {
            status = CloseTrace(g_hTrace);
        }
    }
    
    
    // Callback that receives the events. 
    
    VOID WINAPI ProcessEvent(PEVENT_RECORD pEvent)
    {
        DWORD status = ERROR_SUCCESS;
        PTRACE_EVENT_INFO pInfo = NULL;
        LPWSTR pwsEventGuid = NULL;
        ULONGLONG TimeStamp = 0;
        ULONGLONG Nanoseconds = 0;
        SYSTEMTIME st;
        SYSTEMTIME stLocal;
        FILETIME ft;
    
    
        // Skips the event if it is the event trace header. Log files contain this event
        // but real-time sessions do not. The event contains the same information as 
        // the EVENT_TRACE_LOGFILE.LogfileHeader member that you can access when you open 
        // the trace. 
    
        if (IsEqualGUID(pEvent->EventHeader.ProviderId, EventTraceGuid) &&
            pEvent->EventHeader.EventDescriptor.Opcode == EVENT_TRACE_TYPE_INFO)
        {
            ; // Skip this event.
        }
        else
        {
            // Process the event. The pEvent->UserData member is a pointer to 
            // the event specific data, if it exists.
    
            status = GetEventInformation(pEvent, pInfo);
    
            if (ERROR_SUCCESS != status)
            {
                wprintf(L"GetEventInformation failed with %lu
    ", status);
                goto cleanup;
            }
    
            // Determine whether the event is defined by a MOF class, in an
            // instrumentation manifest, or a WPP template; to use TDH to decode
            // the event, it must be defined by one of these three sources.
    
            if (DecodingSourceWbem == pInfo->DecodingSource)  // MOF class
            {
                HRESULT hr = StringFromCLSID(pInfo->EventGuid, &pwsEventGuid);
    
                if (FAILED(hr))
                {
                    wprintf(L"StringFromCLSID failed with 0x%x
    ", hr);
                    status = hr;
                    goto cleanup;
                }
    
                wprintf(L"
    Event GUID: %s
    ", pwsEventGuid);
                CoTaskMemFree(pwsEventGuid);
                pwsEventGuid = NULL;
    
                wprintf(L"Event version: %d
    ", pEvent->EventHeader.EventDescriptor.Version);
                wprintf(L"Event type: %d
    ", pEvent->EventHeader.EventDescriptor.Opcode);
            }
            else if (DecodingSourceXMLFile == pInfo->DecodingSource) // Instrumentation manifest
            {
                wprintf(L"Event ID: %d
    ", pInfo->EventDescriptor.Id);
            }
            else // Not handling the WPP case
            {
                goto cleanup;
            }
    
            // Print the time stamp for when the event occurred.
    
            ft.dwHighDateTime = pEvent->EventHeader.TimeStamp.HighPart;
            ft.dwLowDateTime = pEvent->EventHeader.TimeStamp.LowPart;
    
            FileTimeToSystemTime(&ft, &st);
            SystemTimeToTzSpecificLocalTime(NULL, &st, &stLocal);
    
            TimeStamp = pEvent->EventHeader.TimeStamp.QuadPart;
            Nanoseconds = (TimeStamp % 10000000) * 100;
    
            wprintf(L"%02d/%02d/%02d %02d:%02d:%02d.%I64u
    ", 
                stLocal.wMonth, stLocal.wDay, stLocal.wYear, stLocal.wHour, stLocal.wMinute, stLocal.wSecond, Nanoseconds);
    
            // If the event contains event-specific data use TDH to extract
            // the event data. For this example, to extract the data, the event 
            // must be defined by a MOF class or an instrumentation manifest.
    
            // Need to get the PointerSize for each event to cover the case where you are
            // consuming events from multiple log files that could have been generated on 
            // different architectures. Otherwise, you could have accessed the pointer
            // size when you opened the trace above (see pHeader->PointerSize).
    
            if (EVENT_HEADER_FLAG_32_BIT_HEADER == (pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER))
            {
                g_PointerSize = 4;
            }
            else
            {
                g_PointerSize = 8;
            }
    
            // Print the event data for all the top-level properties. Metadata for all the 
            // top-level properties come before structure member properties in the 
            // property information array. If the EVENT_HEADER_FLAG_STRING_ONLY flag is set,
            // the event data is a null-terminated string, so just print it.
    
            if (EVENT_HEADER_FLAG_STRING_ONLY == (pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_STRING_ONLY))
            {
                wprintf(L"%s
    ", (LPWSTR)pEvent->UserData);
            }
            else
            {
                for (USHORT i = 0; i < pInfo->TopLevelPropertyCount; i++)
                {
                    status = PrintProperties(pEvent, pInfo, i, NULL, 0);
                    if (ERROR_SUCCESS != status)
                    {
                        wprintf(L"Printing top level properties failed.
    ");
                        goto cleanup;
                    }
                }
            }
        }
    
    cleanup:
    
        if (pInfo)
        {
            free(pInfo);
        }
    
        if (ERROR_SUCCESS != status)
        {
            CloseTrace(g_hTrace);
        }
    }
    
    
    // Print the property.
    
    DWORD PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, LPWSTR pStructureName, USHORT StructIndex)
    {
        DWORD status = ERROR_SUCCESS;
        DWORD LastMember = 0;  // Last member of a structure
        USHORT ArraySize = 0;
        PEVENT_MAP_INFO pMapInfo = NULL;
        PROPERTY_DATA_DESCRIPTOR DataDescriptors[2];
        ULONG DescriptorsCount = 0;
        DWORD PropertySize = 0;
        PBYTE pData = NULL;
    
        // Get the size of the array if the property is an array.
    
        status = GetArraySize(pEvent, pInfo, i, &ArraySize);
    
        for (USHORT k = 0; k < ArraySize; k++)
        {
            wprintf(L"%*s%s: ", (pStructureName) ? 4 : 0, L"", (LPWSTR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset));
    
            // If the property is a structure, print the members of the structure.
    
            if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)
            {
                wprintf(L"
    ");
    
                LastMember = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex + 
                    pInfo->EventPropertyInfoArray[i].structType.NumOfStructMembers;
    
                for (USHORT j = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex; j < LastMember; j++)
                {
                    status = PrintProperties(pEvent, pInfo, j, (LPWSTR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset), k);
                    if (ERROR_SUCCESS != status)
                    {
                        wprintf(L"Printing the members of the structure failed.
    ");
                        goto cleanup;
                    }
                }
            }
            else
            {
                ZeroMemory(&DataDescriptors, sizeof(DataDescriptors));
    
                // To retrieve a member of a structure, you need to specify an array of descriptors. 
                // The first descriptor in the array identifies the name of the structure and the second 
                // descriptor defines the member of the structure whose data you want to retrieve. 
    
                if (pStructureName)
                {
                    DataDescriptors[0].PropertyName = (ULONGLONG)pStructureName;
                    DataDescriptors[0].ArrayIndex = StructIndex;
                    DataDescriptors[1].PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset);
                    DataDescriptors[1].ArrayIndex = k;
                    DescriptorsCount = 2;
                }
                else
                {
                    DataDescriptors[0].PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset);
                    DataDescriptors[0].ArrayIndex = k;
                    DescriptorsCount = 1;
                }
    
                // The TDH API does not support IPv6 addresses. If the output type is TDH_OUTTYPE_IPV6,
                // you will not be able to consume the rest of the event. If you try to consume the
                // remainder of the event, you will get ERROR_EVT_INVALID_EVENT_DATA.
    
                if (TDH_INTYPE_BINARY == pInfo->EventPropertyInfoArray[i].nonStructType.InType &&
                    TDH_OUTTYPE_IPV6 == pInfo->EventPropertyInfoArray[i].nonStructType.OutType)
                {
                    wprintf(L"The event contains an IPv6 address. Skipping event.
    ");
                    status = ERROR_EVT_INVALID_EVENT_DATA;
                    break;
                }
                else
                {
                    status = TdhGetPropertySize(pEvent, 0, NULL, DescriptorsCount, &DataDescriptors[0], &PropertySize);
    
                    if (ERROR_SUCCESS != status)
                    {
                        wprintf(L"TdhGetPropertySize failed with %lu
    ", status);
                        goto cleanup;
                    }
    
                    pData = (PBYTE)malloc(PropertySize);
    
                    if (NULL == pData)
                    {
                        wprintf(L"Failed to allocate memory for property data
    ");
                        status = ERROR_OUTOFMEMORY;
                        goto cleanup;
                    }
    
                    status = TdhGetProperty(pEvent, 0, NULL, DescriptorsCount, &DataDescriptors[0], PropertySize, pData);
    
                    // Get the name/value mapping if the property specifies a value map.
    
                    status = GetMapInfo(pEvent, 
                        (PWCHAR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset),
                        pInfo->DecodingSource,
                        pMapInfo);
    
                    if (ERROR_SUCCESS != status)
                    {
                        wprintf(L"GetMapInfo failed
    ");
                        goto cleanup;
                    }
    
                    status = FormatAndPrintData(pEvent, 
                        pInfo->EventPropertyInfoArray[i].nonStructType.InType,
                        pInfo->EventPropertyInfoArray[i].nonStructType.OutType,
                        pData, 
                        PropertySize,
                        pMapInfo 
                        );
    
                    if (ERROR_SUCCESS != status)
                    {
                        wprintf(L"GetMapInfo failed
    ");
                        goto cleanup;
                    }
    
                    if (pData)
                    {
                        free(pData);
                        pData = NULL;
                    }
    
                    if (pMapInfo)
                    {
                        free(pMapInfo);
                        pMapInfo = NULL;
                    }
                }
            }
        }
    
    cleanup:
    
        if (pData)
        {
            free(pData);
            pData = NULL;
        }
    
        if (pMapInfo)
        {
            free(pMapInfo);
            pMapInfo = NULL;
        }
    
        return status;
    }
    
    
    DWORD FormatAndPrintData(PEVENT_RECORD pEvent, USHORT InType, USHORT OutType, PBYTE pData, DWORD DataSize, PEVENT_MAP_INFO pMapInfo)
    {
        UNREFERENCED_PARAMETER(pEvent);
        
        DWORD status = ERROR_SUCCESS;
    
        switch (InType)
        {
            case TDH_INTYPE_UNICODESTRING:
            case TDH_INTYPE_COUNTEDSTRING:
            case TDH_INTYPE_REVERSEDCOUNTEDSTRING:
            case TDH_INTYPE_NONNULLTERMINATEDSTRING:
            {
                size_t StringLength = 0;
    
                if (TDH_INTYPE_COUNTEDSTRING == InType)
                {
                    StringLength = *(PUSHORT)pData;
                }
                else if (TDH_INTYPE_REVERSEDCOUNTEDSTRING == InType)
                {
                    StringLength = MAKEWORD(HIBYTE((PUSHORT)pData), LOBYTE((PUSHORT)pData));
                }
                else if (TDH_INTYPE_NONNULLTERMINATEDSTRING == InType)
                {
                    StringLength = DataSize;
                }
                else
                {
                    StringLength = wcslen((LPWSTR)pData);
                }
    
                wprintf(L"%.*s
    ", StringLength, (LPWSTR)pData);
                break;
            }
    
            case TDH_INTYPE_ANSISTRING:
            case TDH_INTYPE_COUNTEDANSISTRING:
            case TDH_INTYPE_REVERSEDCOUNTEDANSISTRING:
            case TDH_INTYPE_NONNULLTERMINATEDANSISTRING:
            {
                size_t StringLength = 0;
    
                if (TDH_INTYPE_COUNTEDANSISTRING == InType)
                {
                    StringLength = *(PUSHORT)pData;
                }
                else if (TDH_INTYPE_REVERSEDCOUNTEDANSISTRING == InType)
                {
                    StringLength = MAKEWORD(HIBYTE((PUSHORT)pData), LOBYTE((PUSHORT)pData));
                }
                else if (TDH_INTYPE_NONNULLTERMINATEDANSISTRING == InType)
                {
                    StringLength = DataSize;
                }
                else
                {
                    StringLength = strlen((LPSTR)pData);
                }
    
                wprintf(L"%.*S
    ", StringLength, (LPSTR)pData);
                break;
            }
    
            case TDH_INTYPE_INT8:
            {
                wprintf(L"%hd
    ", *(PCHAR)pData);
                break;
            }
    
            case TDH_INTYPE_UINT8:
            {
                if (TDH_OUTTYPE_HEXINT8 == OutType)
                {
                    wprintf(L"0x%x
    ", *(PBYTE)pData);
                }
                else
                {
                    wprintf(L"%hu
    ", *(PBYTE)pData);
                }
    
                break;
            }
    
            case TDH_INTYPE_INT16:
            {
                wprintf(L"%hd
    ", *(PSHORT)pData);
                break;
            }
    
            case TDH_INTYPE_UINT16:
            {
                if (TDH_OUTTYPE_HEXINT16 == OutType)
                {
                    wprintf(L"0x%x
    ", *(PUSHORT)pData);
                }
                else if (TDH_OUTTYPE_PORT == OutType)
                {
                    wprintf(L"%hu
    ", ntohs(*(PUSHORT)pData));
                }
                else
                {
                    wprintf(L"%hu
    ", *(PUSHORT)pData);
                }
    
                break;
            }
    
            case TDH_INTYPE_INT32:
            {
                if (TDH_OUTTYPE_HRESULT == OutType)
                {
                    wprintf(L"0x%x
    ", *(PLONG)pData);
                }
                else
                {
                    wprintf(L"%d
    ", *(PLONG)pData);
                }
    
                break;
            }
    
            case TDH_INTYPE_UINT32:
            {
                if (TDH_OUTTYPE_HRESULT == OutType ||
                    TDH_OUTTYPE_WIN32ERROR == OutType ||
                    TDH_OUTTYPE_NTSTATUS == OutType ||
                    TDH_OUTTYPE_HEXINT32 == OutType)
                {
                    wprintf(L"0x%x
    ", *(PULONG)pData);
                }
                else if (TDH_OUTTYPE_IPV4 == OutType)
                {
                    wprintf(L"%d.%d.%d.%d
    ", (*(PLONG)pData >>  0) & 0xff,
                                              (*(PLONG)pData >>  8) & 0xff,
                                              (*(PLONG)pData >>  16) & 0xff,
                                              (*(PLONG)pData >>  24) & 0xff);
                }
                else
                {
                    if (pMapInfo)
                    {
                        PrintMapString(pMapInfo, pData);
                    }
                    else
                    {
                        wprintf(L"%lu
    ", *(PULONG)pData);
                    }
                }
    
                break;
            }
    
            case TDH_INTYPE_INT64:
            {
                wprintf(L"%I64d
    ", *(PLONGLONG)pData);
    
                break;
            }
    
            case TDH_INTYPE_UINT64:
            {
                if (TDH_OUTTYPE_HEXINT64 == OutType)
                {
                    wprintf(L"0x%x
    ", *(PULONGLONG)pData);
                }
                else
                {
                    wprintf(L"%I64u
    ", *(PULONGLONG)pData);
                }
    
                break;
            }
    
            case TDH_INTYPE_FLOAT:
            {
                wprintf(L"%f
    ", *(PFLOAT)pData);
    
                break;
            }
    
            case TDH_INTYPE_DOUBLE:
            {
                wprintf(L"%I64f
    ", *(DOUBLE*)pData);
    
                break;
            }
    
            case TDH_INTYPE_BOOLEAN:
            {
                wprintf(L"%s
    ", (0 == (PBOOL)pData) ? L"false" : L"true");
    
                break;
            }
    
            case TDH_INTYPE_BINARY:
            {
                if (TDH_OUTTYPE_IPV6 == OutType)
                {
                    WCHAR IPv6AddressAsString[46];
                    PIPV6ADDRTOSTRING fnRtlIpv6AddressToString;
    
                    fnRtlIpv6AddressToString = (PIPV6ADDRTOSTRING)GetProcAddress(
                        GetModuleHandle(L"ntdll"), "RtlIpv6AddressToStringW");
    
                    if (NULL == fnRtlIpv6AddressToString)
                    {
                        wprintf(L"GetProcAddress failed with %lu.
    ", status = GetLastError());
                        goto cleanup;
                    }
    
                    fnRtlIpv6AddressToString((IN6_ADDR*)pData, IPv6AddressAsString);
    
                    wprintf(L"%s
    ", IPv6AddressAsString);
                }
                else
                {
                    for (DWORD i = 0; i < DataSize; i++)
                    {
                        wprintf(L"%.2x", pData[i]);
                    }
    
                    wprintf(L"
    ");
                }
    
                break;
            }
    
            case TDH_INTYPE_GUID:
            {
                WCHAR szGuid[50];
                
                StringFromGUID2(*(GUID*)pData, szGuid, sizeof(szGuid)-1);
                wprintf(L"%s
    ", szGuid);
                    
                break;
            }
    
            case TDH_INTYPE_POINTER:
            case TDH_INTYPE_SIZET:
            {
                if (4 == g_PointerSize)
                {
                    wprintf(L"0x%x
    ", *(PULONG)pData);
                }
                else
                {
                    wprintf(L"0x%x
    ", *(PULONGLONG)pData);
                }
    
                break;
            }
    
            case TDH_INTYPE_FILETIME:
            {
                break;
            }
    
            case TDH_INTYPE_SYSTEMTIME:
            {
                break;
            }
    
            case TDH_INTYPE_SID:
            {
                WCHAR UserName[MAX_NAME];
                WCHAR DomainName[MAX_NAME];
                DWORD cchUserSize = MAX_NAME;
                DWORD cchDomainSize = MAX_NAME;
                SID_NAME_USE eNameUse;
    
                if (!LookupAccountSid(NULL, (PSID)pData, UserName, &cchUserSize, DomainName, &cchDomainSize, &eNameUse))
                {
                    if (ERROR_NONE_MAPPED == status)
                    {
                        wprintf(L"Unable to locate account for the specified SID
    ");
                        status = ERROR_SUCCESS;
                    }
                    else
                    {
                        wprintf(L"LookupAccountSid failed with %lu
    ", status = GetLastError());
                    }
    
                    goto cleanup;
                }
                else
                {
                    wprintf(L"%s\%s
    ", DomainName, UserName);
                }
    
                break;
            }
    
            case TDH_INTYPE_HEXINT32:
            {
                wprintf(L"0x%x
    ", (PULONG)pData);
                break;
            }
    
            case TDH_INTYPE_HEXINT64:
            {
                wprintf(L"0x%x
    ", (PULONGLONG)pData);
                break;
            }
    
            case TDH_INTYPE_UNICODECHAR:
            {
                wprintf(L"%c
    ", *(PWCHAR)pData);
                break;
            }
    
            case TDH_INTYPE_ANSICHAR:
            {
                wprintf(L"%C
    ", *(PCHAR)pData);
                break;
            }
    
            case TDH_INTYPE_WBEMSID:
            {
                WCHAR UserName[MAX_NAME];
                WCHAR DomainName[MAX_NAME];
                DWORD cchUserSize = MAX_NAME;
                DWORD cchDomainSize = MAX_NAME;
                SID_NAME_USE eNameUse;
    
                if ((PULONG)pData > 0)
                {
                    // A WBEM SID is actually a TOKEN_USER structure followed 
                    // by the SID. The size of the TOKEN_USER structure differs 
                    // depending on whether the events were generated on a 32-bit 
                    // or 64-bit architecture. Also the structure is aligned
                    // on an 8-byte boundary, so its size is 8 bytes on a
                    // 32-bit computer and 16 bytes on a 64-bit computer.
                    // Doubling the pointer size handles both cases.
    
                    pData += g_PointerSize * 2;
    
                    if (!LookupAccountSid(NULL, (PSID)pData, UserName, &cchUserSize, DomainName, &cchDomainSize, &eNameUse))
                    {
                        if (ERROR_NONE_MAPPED == status)
                        {
                            wprintf(L"Unable to locate account for the specified SID
    ");
                            status = ERROR_SUCCESS;
                        }
                        else
                        {
                            wprintf(L"LookupAccountSid failed with %lu
    ", status = GetLastError());
                        }
    
                        goto cleanup;
                    }
                    else
                    {
                        wprintf(L"%s\%s
    ", DomainName, UserName);
                    }
                }
    
                break;
            }
    
        default:
            status = ERROR_NOT_FOUND;
        }
    
    cleanup:
    
        return status;
    }
    
    
    void PrintMapString(PEVENT_MAP_INFO pMapInfo, PBYTE pData)
    {
        BOOL MatchFound = FALSE;
    
        if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP) == EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP ||
            ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_VALUEMAP) == EVENTMAP_INFO_FLAG_WBEM_VALUEMAP &&
            (pMapInfo->Flag & (~EVENTMAP_INFO_FLAG_WBEM_VALUEMAP)) != EVENTMAP_INFO_FLAG_WBEM_FLAG))
        {
            if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_NO_MAP) == EVENTMAP_INFO_FLAG_WBEM_NO_MAP)
            {
                wprintf(L"%s
    ", (LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[*(PULONG)pData].OutputOffset));
            }
            else
            {
                for (DWORD i = 0; i < pMapInfo->EntryCount; i++)
                {
                    if (pMapInfo->MapEntryArray[i].Value == *(PULONG)pData)
                    {
                        wprintf(L"%s
    ", (LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset));
                        MatchFound = TRUE;
                        break;
                    }
                }
    
                if (FALSE == MatchFound)
                {
                    wprintf(L"%lu
    ", *(PULONG)pData);
                }
            }
        }
        else if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_MANIFEST_BITMAP) == EVENTMAP_INFO_FLAG_MANIFEST_BITMAP ||
            (pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_BITMAP) == EVENTMAP_INFO_FLAG_WBEM_BITMAP ||
            ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_VALUEMAP) == EVENTMAP_INFO_FLAG_WBEM_VALUEMAP &&
            (pMapInfo->Flag & (~EVENTMAP_INFO_FLAG_WBEM_VALUEMAP)) == EVENTMAP_INFO_FLAG_WBEM_FLAG))
        {
            if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_NO_MAP) == EVENTMAP_INFO_FLAG_WBEM_NO_MAP)
            {
                DWORD BitPosition = 0;
    
                for (DWORD i = 0; i < pMapInfo->EntryCount; i++)
                {
                    if ((*(PULONG)pData & (BitPosition = (1 << i))) == BitPosition)
                    {
                        wprintf(L"%s%s", 
                            (MatchFound) ? L" | " : L"", 
                            (LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset));
    
                        MatchFound = TRUE;
                    }
                }
    
            }
            else
            {
                for (DWORD i = 0; i < pMapInfo->EntryCount; i++)
                {
                    if ((pMapInfo->MapEntryArray[i].Value & *(PULONG)pData) == pMapInfo->MapEntryArray[i].Value)
                    {
                        wprintf(L"%s%s", 
                            (MatchFound) ? L" | " : L"", 
                            (LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset));
    
                        MatchFound = TRUE;
                    }
                }
            }
    
            if (MatchFound)
            {
                wprintf(L"
    ");
            }
            else
            {
                wprintf(L"%lu
    ", *(PULONG)pData);
            }
        }
    }
    
    
    // Get the size of the array. For MOF-based events, the size is specified in the declaration or using 
    // the MAX qualifier. For manifest-based events, the property can specify the size of the array
    // using the count attribute. The count attribue can specify the size directly or specify the name 
    // of another property in the event data that contains the size.
    
    DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize)
    {
        DWORD status = ERROR_SUCCESS;
        PROPERTY_DATA_DESCRIPTOR DataDescriptor;
        DWORD PropertySize = 0;
    
        if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamCount) == PropertyParamCount)
        {
            DWORD Count = 0;  // Expects the count to be defined by a UINT16 or UINT32
            DWORD j = pInfo->EventPropertyInfoArray[i].countPropertyIndex;
            ZeroMemory(&DataDescriptor, sizeof(PROPERTY_DATA_DESCRIPTOR));
            DataDescriptor.PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[j].NameOffset);
            DataDescriptor.ArrayIndex = ULONG_MAX;
            status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize);
            status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Count);
            *ArraySize = (USHORT)Count;
        }
        else
        {
            *ArraySize = pInfo->EventPropertyInfoArray[i].count;
        }
    
        return status;
    }
    
    
    // Both MOF-based events and manifest-based events can specify name/value maps. The
    // map values can be integer values or bit values. If the property specifies a value
    // map, get the map.
    
    DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO & pMapInfo)
    {
        DWORD status = ERROR_SUCCESS;
        DWORD MapSize = 0;
    
        // Retrieve the required buffer size for the map info.
    
        status = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &MapSize);
    
        if (ERROR_INSUFFICIENT_BUFFER == status)
        {
            pMapInfo = (PEVENT_MAP_INFO) malloc(MapSize);
            if (pMapInfo == NULL)
            {
                wprintf(L"Failed to allocate memory for map info (size=%lu).
    ", MapSize);
                status = ERROR_OUTOFMEMORY;
                goto cleanup;
            }
    
            // Retrieve the map info.
    
            status = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &MapSize);
        }
    
        if (ERROR_SUCCESS == status)
        {
            if (DecodingSourceXMLFile == DecodingSource)
            {
                RemoveTrailingSpace(pMapInfo);
            }
        }
        else
        {
            if  (ERROR_NOT_FOUND == status)
            {
                status = ERROR_SUCCESS; // This case is okay.
            }
            else
            {
                wprintf(L"TdhGetEventMapInformation failed with 0x%x.
    ", status);
            }
        }
    
    cleanup:
    
        return status;
    }
    
    
    // The mapped string values defined in a manifest will contain a trailing space
    // in the EVENT_MAP_ENTRY structure. Replace the trailing space with a null-
    // terminating character, so that the bit mapped strings are correctly formatted.
    
    void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo)
    {
        SIZE_T ByteLength = 0;
    
        for (DWORD i = 0; i < pMapInfo->EntryCount; i++)
        {
            ByteLength = (wcslen((LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset)) - 1) * 2;
            *((LPWSTR)((PBYTE)pMapInfo + (pMapInfo->MapEntryArray[i].OutputOffset + ByteLength))) = L'';
        }
    }
    
    
    // Get the metadata for the event.
    
    DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo)
    {
        DWORD status = ERROR_SUCCESS;
        DWORD BufferSize = 0;
    
        // Retrieve the required buffer size for the event metadata.
    
        status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);
    
        if (ERROR_INSUFFICIENT_BUFFER == status)
        {
            pInfo = (TRACE_EVENT_INFO*) malloc(BufferSize);
            if (pInfo == NULL)
            {
                wprintf(L"Failed to allocate memory for event info (size=%lu).
    ", BufferSize);
                status = ERROR_OUTOFMEMORY;
                goto cleanup;
            }
    
            // Retrieve the event metadata.
    
            status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);
        }
    
        if (ERROR_SUCCESS != status)
        {
            wprintf(L"TdhGetEventInformation failed with 0x%x.
    ", status);
        }
    
    cleanup:
    
        return status;
    }
    View Code
  • 相关阅读:
    Spring中的AOP实现思路
    手写IOC-SPRINGPMVC-CONNPOOL
    职责链模式
    判断一个二叉树是不是对称二叉树
    合并区间
    shell命令中用source 和sh(或者bash)执行脚本的区别,以及export的作用
    angular指令的compile,prelink 和 postlink以及controller
    angular的启动原理
    高并发优化方法
    搭建ssm框架的一个小坑
  • 原文地址:https://www.cnblogs.com/aliflycoris/p/13854046.html
Copyright © 2011-2022 走看看