News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

ETW event consumer EnableTraceEx.

Started by Fraile, February 13, 2024, 10:03:20 PM

Previous topic - Next topic

Fraile

I find myself in the following predicament: I am attempting to capture events according to a C++ example. However, the issue arises when it gets stuck in the EnableTraceEx function. According to Microsoft documentation, the error it gives, which is error code 87, occurs because the "sessionHandle" or "GUID" is equal to NULL. However, this is not the case. If I do not use EnableTraceEx and instead use EnableTrace, it proceeds to the next function of the program, but ultimately fails in ProcessTrace. Any assistance would be greatly appreciated. Thank you in advance.

Code in c++: https://gist.github.com/aaaddress1/4add6b873ae6ed70cb125a7587d2e1bc


Code in Masm32:

AsigText Macro Name, Text:VarArg
    Local lbl
    Jmp lbl
        Name DB Text, 0
lbl:
EndM

.Const

  WNODE_FLAG_TRACED_GUID          Equ 20000H ; Constante para indicar que el GUID del proveedor está incluido en el nodo
  EVENT_TRACE_REAL_TIME_MODE      Equ 100H
  EVENT_TRACE_USE_PAGED_MEMORY    Equ 4000H
  PROCESS_TRACE_MODE_EVENT_RECORD Equ 1000H

.Data?



.Data

_SYSTEMTIME Struct
    wYear          Word 0
    wMonth          Word 0
    wDayOfWeek      Word 0
    wDay            Word 0
    wHour          Word 0
    wMinute        Word 0
    wSecond        Word 0
    wMilliseconds  Word 0
_SYSTEMTIME EndS
_TIME_ZONE_INFORMATION Struct
    Bias            LONG 0
    StandardName    WCHAR 32 Dup (0)
    StandardDate    _SYSTEMTIME <>
    StandardBias    LONG 0
    DaylightName    WCHAR 32 Dup (0)
    DaylightDate    _SYSTEMTIME <>
    DaylightBias    LONG 0
_TIME_ZONE_INFORMATION EndS
TRACE_LOGFILE_HEADER Struct
    BufferSize              DWord 0
    Union
        VersionA            DWord 0
        Struc
            MajorVersion    Byte 0
            MinorVersion    Byte 0
            SubVersion        Byte 0
            SubMinorVersion    Byte 0
        EndS
    EndS
    ProviderVersion        DWord 0
    NumberOfProcessors      DWord 0
    EndTime                LARGE_INTEGER <>
    TimerResolution        DWord 0
    MaximumFileSize        DWord 0
    LogFileMode            DWord 0
    BuffersWritten          DWord 0
    Union
        LogInstanceGuid    GUID <>
        Struc
            StartBuffers    DWord 0
            PointerSize        DWord 0
            EventsLost        DWord 0
            CpuSpeedInMHz    DWord 0
        EndS
    EndS
    LoggerName              DWord 0
    LogFileName            DWord 0
    TimeZone                _TIME_ZONE_INFORMATION <>
    BootTime                LARGE_INTEGER <>
    PerfFreq                LARGE_INTEGER <>
    StartTime              LARGE_INTEGER <>
    ReservedFlags          DWORD ?
    BuffersLost            DWORD ?
TRACE_LOGFILE_HEADER EndS

ETW_BUFFER_CONTEXT Struct
    Union
        Struct
            ProcessorNumber Byte 0
            Alignment      Byte 0
        EndS
        ProcessorIndex  Word 0
    EndS
    LoggerId            Word ?
ETW_BUFFER_CONTEXT EndS
EVENT_TRACE_HEADER Struct
    SizeA              Word 0
    Union
        FieldTypeFlags  Word 0
        Struct
            HeaderType  Byte 0
            MarkerFlags  Byte 0
        EndS
    EndS
    Union
        Version        DWord 0
        Struc
            TypeA      Byte 0
            Level        Byte 0
            VersionA    Byte 0
        EndS
    EndS
    ThreadId            DWord 0
    ProcessId          DWord 0
    TimeStamp          LARGE_INTEGER <>
    Union
        Guid            GUID <>
        GuidPtr        QWord 0
    EndS
    Union
        Struct
            KernelTime  DWord 0
            UserTime    DWord 0
        EndS
        ProcessorTime  QWord 0
        Struct
            ClientContext DWord 0
            Flags        DWord 0
        EndS
    EndS
EVENT_TRACE_HEADER EndS
EVENT_TRACE Struct
    Header              EVENT_TRACE_HEADER <>
    InstanceId          DWord 0
    ParentInstanceId    DWord 0
    ParentGuid          GUID <>
    MofData            DWord 0
    MofLength          DWord 0
    Union
        ClientContext  DWord 0
        BufferContext  ETW_BUFFER_CONTEXT <>
    EndS
EVENT_TRACE EndS
EventTraceLogfileA Struct
    LogFileName        DWord 0
    LoggerName          DWord 0
    CurrentTime        QWord 0
    BuffersRead        DWord 0
    Union
        LogFileMode    DWord 0
        ProcessTraceMode DWord 0
    EndS
    CurrentEvent        EVENT_TRACE <>
    LogfileHeader      TRACE_LOGFILE_HEADER <>
    BufferCallback      DWord 0
    BufferSize          DWord 0
    Filled              DWord 0
    EventsLost          DWord 0
    Union
        EventCallback          DWord 0
        EventRecordCallback    DWord 0
    EndS
    IsKernelTrace      DWord 0
    Context            DWord 0
EventTraceLogfileA EndS

WNODE_HEADER    Struct
    BufferSize    DWORD    ?
    ProviderId    DWORD    ?

    union
        HistoricalContext  ULONG64 ?
        struct
        Version            DWORD  ?
        Linkage            DWORD  ?
        ends
    ends

    union
        KernelHandle    HANDLE      ?
        TimeStamp      LARGE_INTEGER  <>
    ends
 
    Guid                GUID        <>
    ClientContext      DWORD      ?
    Flags              DWORD      ?
 
    WNODE_HEADER EndS
EVENT_TRACE_PROPERTIES Struct
  Wnode        WNODE_HEADER <>
  BufferSize    DWord 0
  MinimumBuffers DWord 0
  MaximumBuffers DWord 0
  MaximumFileSize DWord 0
  LogFileMode  DWord 0
  FlushTimer    DWord 0
  EnableFlags  DWord 0
  AgeLimit      DWord 0
  FlushThreshold DWord 0
  NumberOfBuffers      DWord 0
  FreeBuffers          DWord 0
  EventsLost          DWord 0
  BuffersWritten      DWord 0
  LogBuffersLost      DWord 0
  RealTimeBuffersLost  DWord 0
  LoggerThreadId      HANDLE 0
  LogFileNameOffset    DWord 0
  LoggerNameOffset    DWord 0
EVENT_TRACE_PROPERTIES EndS
ENABLE_TRACE_PARAMETERS STRUCT
    Version              DWord  0
    EnableProperty      DWord  0
    ControlFlags        DWord  0
    SourceId            GUID    <>
    EnableFilterDesc    DWord  0
    FilterDescCount      DWord  0
ENABLE_TRACE_PARAMETERS EndS
EVENT_FILTER_DESCRIPTOR STRUCT
    PtrA      QWord      0
    SizeA    DWord      0
    TypeA    DWord      0
EVENT_FILTER_DESCRIPTOR EndS
EVENT_DESCRIPTOR Struct
    Id        Word          0
    Version    Byte          0
    Channel    Byte          0
    Level      Byte          0
    Opcode    Byte          0
    Task      Word          0
    Keyword    QWord        0
EVENT_DESCRIPTOR EndS
EVENT_HEADER Struct
    SizeA            Word            0
    HeaderType        Word            0
    Flags            Word            0
    EventProperty    Word            0
    ThreadId          DWord            0
    ProcessId        DWord            0
    TimeStamp        LARGE_INTEGER    <>
    ProviderId        GUID            <>
    EventDescriptor  EVENT_DESCRIPTOR <>
    Union                ; Comienzo de la unión
        Struct              ; Comienzo de la estructura anidada
            KernelTime  DWord        ?
            UserTime    DWORD        ?
            ProcessorTime    QWord        ? ; Puedes ajustar el tamaño dependiendo del uso
        EndS
    EndS                                ; Fin de la unión
    ActivityId        GUID            <>
EVENT_HEADER EndS
EVENT_RECORD Struct
    EventHeader            EVENT_HEADER          <>
    BufferContext          ETW_BUFFER_CONTEXT    <>
    ExtendedDataCount      Word                  0
    UserDataLength          Word                  0
    ExtendedData            PVOID                    ?
    UserData                PVOID                    ?
    UserContext            PVOID                    ?
EVENT_RECORD EndS
  HandleConsola              DD 0

  Trace                  EventTraceLogfileA <>
  TraceProperties    EVENT_TRACE_PROPERTIES <>
  TraceParam          ENABLE_TRACE_PARAMETERS <>

  LoggerName      DB 'frai18', 0
  LogFileName    DB  0


  sessionHandle          HANDLE 0
  ProviderHandle          HANDLE 0

  tempbuffer              DB 10 Dup(NULL)      ; Buffer temporal para la rutina de paso a numeros decimales.

  ; Definir la estructura de GUID para el proveedor de eventos
  generatedGuid GUID <>

  BufferSize              DD 0

  HandleLibrary              DD 0

.Code


start:

    Invoke GetStdHandle, STD_OUTPUT_HANDLE
    Mov HandleConsola, Eax  ; edx ahora contiene el identificador de la consola

    ; Llama a CoInitialize para inicializar la biblioteca COM
    Invoke CoInitialize, NULL
;   
    ; Llama a CoCreateGuid para generar un GUID

    Invoke CoCreateGuid, Addr generatedGuid
    Test Eax, Eax
    Jnz Error_ExitSiete

        ; Copia el GUID generado a la estructura WNODE_HEADER
;        Lea Esi, generatedGuid
;        Lea Edi, TraceProperties.Props.Wnode.Guid
;        Mov Ecx, SizeOf GUID
;        Rep Movsb
;
    ; Llama a CoUninitialize para finalizar la biblioteca COM
    Invoke CoUninitialize


    ; Convertir el GUID a una cadena hexadecimal


  ; Cargar la biblioteca dinámica wnetapi32.dll
  Invoke LoadLibrary, TextStr("Advapi32.dll")

  .If Eax

        Mov Edi, Eax
        Mov HandleLibrary, Eax

        ; Registramos un proveedor para registro de eventos.
        Invoke GetProcAddress, Edi, TextStr("EventRegister")
        Mov Esi, Eax

        Lea Eax, ProviderHandle
        Push Eax
        Push NULL
        Push NULL
        Lea Eax, generatedGuid
        Push Eax

        Call Esi

        Test Eax, Eax
        Jnz error_exitCinco



        ; Obtener el puntero a la función StartTraceA
        ; Crear una sesión de ETW
        Invoke GetProcAddress, Edi, TextStr("StartTraceA")
        Mov Esi, Eax


        ; Inicializar las propiedades de traza

        Mov TraceProperties.Wnode.BufferSize, SizeOf EVENT_TRACE_PROPERTIES + SizeOf LoggerName
        Mov TraceProperties.Wnode.ClientContext, 2
        Mov TraceProperties.Wnode.Flags, WNODE_FLAG_TRACED_GUID

;        Push Esi
;        Push Edi
;
;        ; Copia el GUID generado a la estructura WNODE_HEADER
;        Lea Esi, generatedGuid
;        Lea Edi, TraceProperties.Wnode.Guid
;        Mov Ecx, SizeOf GUID
;        Rep Movsb
;
;        Pop Edi
;        Pop Esi



        Mov TraceProperties.LogFileMode, EVENT_TRACE_REAL_TIME_MODE + EVENT_TRACE_USE_PAGED_MEMORY
        Mov TraceProperties.LoggerNameOffset, SizeOf EVENT_TRACE_PROPERTIES
        Mov TraceProperties.LogFileNameOffset, 0



        Lea Eax, TraceProperties
        Push Eax
        Lea Eax, LoggerName
        Push Eax
        Lea Eax, sessionHandle
        Push Eax

        Call Esi
        Test Eax, Eax
        Jnz error_exit


        Push Esi
        Push Edi

        Mov Eax, SizeOf generatedGuid    ; Obtener el tamaño de ProviderGuid
        Cmp Eax, SizeOf GUID            ; Comparar con el tamaño esperado de un GUID
        Jne guid_invalido              ; Si los tamaños no coinciden, salta a guid_invalido


        ; Comprobamos que el handle de sesion es correcto.
        Xor Eax, Eax
        Mov Eax, sessionHandle
        Test Eax, Eax
        Jz Error_HandleSesion



        Pop Edi
        Pop Esi

      ; *******************************************************
      ; Habilitamos el traceo de eventos.
      ; *******************************************************

;            WINEVENT_KEYWORD_PROCESS                  = 0x10,
;            WINEVENT_KEYWORD_THREAD                  = 0x20,
;            WINEVENT_KEYWORD_IMAGE                    = 0x40,
;            WINEVENT_KEYWORD_CPU_PRIORITY            = 0x80,
;            WINEVENT_KEYWORD_OTHER_PRIORITY          = 0x100,
;            WINEVENT_KEYWORD_PROCESS_FREEZE          = 0x200,


;        Invoke GetProcAddress, Edi, TextStr("EnableTrace")
;        Mov Esi, Eax
;
;        Push sessionHandle
;        Lea Eax, generatedGuid
;        Push Eax
;        Push 4
;        Push 0
;        Push 1

        Invoke GetProcAddress, Edi, TextStr("EnableTraceEx")
        Mov Esi, Eax

        Push NULL
        Push 0
        Push 0
        Push 0
        Push 4
        Push 1
        Push sessionHandle
        Push NULL
        Lea Eax, generatedGuid
        Push Eax


        Call Esi
        Test Eax, Eax
        Jnz Error_ExitSeis

        ; ******************************************************************
        ; Armamos el identificador de seguimiento ETW para consumir eventos.
        ; ******************************************************************

        Mov Trace.ProcessTraceMode, EVENT_TRACE_REAL_TIME_MODE + PROCESS_TRACE_MODE_EVENT_RECORD
        Mov Trace.LogFileName, NULL
        Mov Trace.LoggerName, Offset LoggerName
        Mov Trace.EventRecordCallback, Offset ProcessEvent
        ;Mov Trace.BufferCallback, Offset ProcessEvent
        Mov Trace.Context, 2


        Invoke GetProcAddress, Edi, TextStr("OpenTraceA")
        Mov Esi, Eax

        Lea Eax, Trace
        Push Eax

        Call Esi
        Cmp Eax, -1
        Je Error_ExitOcho

        Mov sessionHandle, Eax



        Invoke GetProcAddress, Edi, TextStr("ProcessTrace")

        Mov Esi, Eax

        Push NULL
        Push NULL
        Push 1
        Push sessionHandle

        Call Esi
        Test Eax, Eax
        Jnz Error_ExitNueve

        Push Edi

        Invoke PasarADecimal, Eax
        Invoke WriteConsoleA, HandleConsola, Addr tempbuffer, 4, 0, 0

        Pop Edi



Jmp exit



  .EndIf


;    ; Terminar la sesión de ETW y liberar los recursos
;    invoke ControlTrace, NULL, ADDR ETW_SESSION_NAME, ADDR sessionHandle, 2
    jmp exit

error_exit:
    ; Manejar errores aquí
    ; Por ejemplo, imprimir un mensaje de error y salir

        Invoke PasarADecimal, Eax
        Invoke WriteConsoleA, HandleConsola, Addr tempbuffer, 4, 0, 0

   
    AsigText Error1, "Error al iniciar StartTraceA."
    Invoke WriteConsoleA, HandleConsola, Addr Error1, 29, 0, 0
    Jmp exit

error_exitDos:
    ; Manejar errores aquí
    ; Por ejemplo, imprimir un mensaje de error y salir
    AsigText Error2, "Error al iniciar EnableTrace."
    Invoke WriteConsoleA, HandleConsola, Addr Error2, 29, 0, 0
    Jmp exit

error_exitTres:
    ; Manejar errores aquí
    ; Por ejemplo, imprimir un mensaje de error y salir
    AsigText Error3, "Error al iniciar el procesador de eventos."
    Invoke WriteConsoleA, HandleConsola, Addr Error3, 42, 0, 0
    Jmp exit

error_exitCuatro:
    AsigText Error4, "Error en captura de fundion de proceso de evento."
    Invoke WriteConsoleA, HandleConsola, Addr Error4, 49, 0, 0
    Jmp exit

error_exitCinco:

    Invoke PasarADecimal, Eax
    Invoke WriteConsoleA, HandleConsola, Addr tempbuffer, 4, 0, 0

    AsigText Error8, "Erron al iniciar EventRegister."
    Invoke WriteConsoleA, HandleConsola, Addr Error8, 31, 0, 0
    Jmp exit

Error_ExitSeis:

    Invoke PasarADecimal, Eax
    Invoke WriteConsoleA, HandleConsola, Addr tempbuffer, 4, 0, 0

    AsigText Error6, "Erron al iniciar EnableTraceEx2."
    Invoke WriteConsoleA, HandleConsola, Addr Error6, 32, 0, 0
    Jmp exit

Error_ExitSiete:

    Invoke PasarADecimal, Eax
    Invoke WriteConsoleA, HandleConsola, Addr tempbuffer, 4, 0, 0

    AsigText Error9, "Erron al iniciar CreandoGUID."
    Invoke WriteConsoleA, HandleConsola, Addr Error9, 29, 0, 0
    Jmp exit

guid_invalido:
    AsigText Error10, "Erron validar GUID."
    Invoke WriteConsoleA, HandleConsola, Addr Error10, 19, 0, 0
    Jmp exit

Error_HandleSesion:
    AsigText Error11, "Erron validar Handle Sesion."
    Invoke WriteConsoleA, HandleConsola, Addr Error11, 28, 0, 0
    Jmp exit

Error_ExitOcho:

    Invoke GetLastError
    Invoke PasarADecimal, Eax
    Invoke WriteConsoleA, HandleConsola, Addr tempbuffer, 4, 0, 0


    AsigText Error13, "Error en OpenTraceA."
    Invoke WriteConsoleA, HandleConsola, Addr Error13, 20, 0, 0
    Jmp exit

Error_ExitNueve:

    Invoke PasarADecimal, Eax
    Invoke WriteConsoleA, HandleConsola, Addr tempbuffer, 4, 0, 0

    AsigText Error14, "Error en ProcessTrace."
    Invoke WriteConsoleA, HandleConsola, Addr Error14, 22, 0, 0
    Jmp exit


exit:

        Mov Edi, HandleLibrary

        Invoke GetProcAddress, Edi, TextStr("StopTrace")
        Mov Esi, Eax

        Push NULL
        Push NULL
        Push sessionHandle

        Call Esi

        Invoke GetProcAddress, Edi, TextStr("CloseTrace")
        Mov Esi, Eax

        Push sessionHandle

        Call Esi



    AsigText Error15, "Fin programa."
    Invoke WriteConsoleA, HandleConsola, Addr Error15, 13, 0, 0
    invoke ExitProcess, 0

ProcessEvent Proc  Uses Ebx Esi Edi, pEvent:Ptr EVENT_RECORD

    AsigText Error12, "Entra captura."
    Invoke WriteConsoleA, HandleConsola, Addr Error12, 14, 0, 0



    Ret
ProcessEvent EndP

PasarADecimal Proc Valor:DWord
        Push Esi
        Push Edi

        Mov Esi, Valor
        Mov Edi, Offset tempbuffer
        Invoke dwtoa, Esi, Edi

        Pop Edi
        Pop Esi

        Ret

PasarADecimal EndP
End start


_japheth

I haven't scrutinized your code, but one thing caught my eye:

Quote from: Fraile on February 13, 2024, 10:03:20 PMEVENT_HEADER Struct
    SizeA            Word            0
    HeaderType        Word            0
    Flags            Word            0
    EventProperty    Word            0
    ThreadId          DWord            0
    ProcessId        DWord            0
    TimeStamp        LARGE_INTEGER    <>
    ProviderId        GUID            <>
    EventDescriptor  EVENT_DESCRIPTOR <>
    Union                ; Comienzo de la unión
        Struct              ; Comienzo de la estructura anidada
            KernelTime  DWord        ?
            UserTime    DWORD        ?
            ProcessorTime    QWord        ? ; Puedes ajustar el tamaño dependiendo del uso
        EndS
    EndS                                ; Fin de la unión
    ActivityId        GUID            <>
EVENT_HEADER EndS

The union that is defined in this structure contains just one member - and that's obviously not a smart thing to do. So I guessed it might be wrong - and it indeed is: there are 2 members, variable ProcessorTime should be placed behind the ENDS belonging to the struct.

Don't you use a reliable tool to convert C structs to MASM structs?
Dummheit, gepaart mit Dreistigkeit - eine furchtbare Macht.

Fraile

I look at the structures in Microsoft and convert them to MASM32 using ChatGPT (which, to be honest, doesn't convert very well...). Then I tweak them, in this case, the flaw you've seen has been on my part. Thank you very much for the feedback.

Fraile

Hello _japheth, thank you very much for your help and for taking the time to convert the C structures to masm32. I do use tools like Lib, dumpbind, l2inc... The mention of ChatGPT was partly a joke, but well, don't think it's going badly either, it helps. Anyway, I continue with the project, I have made some progress, some calls are no longer giving me errors. Once I have it finished, I'll publish it here, in case it can help the community. I'm learning a lot about ETW, I'm reading documentation to write a book, hehehehe. Best regards and thank you very much.