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, StartTraceA API

Started by Fraile, February 11, 2024, 07:54:00 AM

Previous topic - Next topic

Fraile

Hi Six_l, I'm trying to convert your code to 32 bits, just out of stubbornness, hehe. One question, do you allocate memory with this part of your code:


    invoke    HeapAlloc,hHeap,HEAP_ZERO_MEMORY, bufferSize
    mov    traceProp,rax
   
    mov    rbx,traceProp
    mov    eax,bufferSize
    mov    (EVENT_TRACE_PROPERTIES PTR [rbx]).Wnode.BufferSize,eax
    mov    (EVENT_TRACE_PROPERTIES PTR [rbx]).Wnode.ClientContext,2
    mov    (EVENT_TRACE_PROPERTIES PTR [rbx]).Wnode.Flags,WNODE_FLAG_TRACED_GUID
    mov    (EVENT_TRACE_PROPERTIES PTR [rbx]).LogFileMode,EVENT_TRACE_REAL_TIME_MODE or EVENT_TRACE_USE_PAGED_MEMORY
    mov    (EVENT_TRACE_PROPERTIES PTR [rbx]).LogFileNameOffset,0
    mov    (EVENT_TRACE_PROPERTIES PTR [rbx]).LoggerNameOffset,sizeof EVENT_TRACE_PROPERTIES


This would be mandatory, or can I pass the structure directly without going through the memory allocation definition? I have it like this:


Invoke RtlZeroMemory, Addr TraceProperties, SizeOf EVENT_TRACE_PROPERTIES

Mov TraceProperties.Props.Wnode.BufferSize, SizeOf EventTracePropertyData
Mov TraceProperties.Props.Wnode.ClientContext, 2
Mov TraceProperties.Props.Wnode.Flags, WNODE_FLAG_TRACED_GUID
Mov TraceProperties.Props.LogFileMode, EVENT_TRACE_REAL_TIME_MODE + EVENT_TRACE_USE_PAGED_MEMORY
Mov TraceProperties.Props.LoggerNameOffset, SizeOf TraceProperties.Props + 4
Mov TraceProperties.Props.LogFileNameOffset, 0


Thank you very much for your help.


Fraile

Please Six_L, could you execute "D:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit>xperf -loggers" and send me a screenshot to see the difference in capture between your application and mine. Thank you very much.

six_L

#47
Hi, Fraile
Quotecould you execute "D:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit>xperf -loggers" and send me a screenshot to see the difference in capture between your application and mine.

I didn't download the Windows Performance Toolkit.

i'm transfering your codes. If your codes come from C codes, please post the C codes here.

about the memory allocation, you do which you'r liking mode. due to the "dotnet trace:     traceProp = (EVENT_TRACE_PROPERTIES*)LocalAlloc(LPTR, bufferSize) ", i did that.

You have provided a new idea that i never run into. i'll learn a lot knowledge about the process event trace. the dotnet trace codes works fine. he can capture a lot of the ID of .net event(143,144,145,146). i'v only understood the 143.


regard.
Say you, Say me, Say the codes together for ever.

Fraile

Hello Six_L, a question, in theory, do the structures you have put in your code work for both 64-bit and 32-bit systems?

Fraile

Hello Six_L, another question. In your 64-bit code, I notice that you are calling elements of the EVENT_TRACE_LOGFILEA structure, which are within a "union," but you are not referencing the name of the "union":

invoke RtlZeroMemory, ADDR trace, sizeof trace
mov trace.ProcessTraceMode, PROCESS_TRACE_MODE_REAL_TIME or PROCESS_TRACE_MODE_EVENT_RECORD
lea rax, Name
mov trace.LoggerName, rax
lea rax, ProcessEvent
mov trace.EventRecordCallback, rax


But in the structure, for example "EventRecordCallback," it's inside a "union.

EVENT_TRACE_LOGFILEA STRUCT
    LogFileName    QWORD ?                ; Logfile Name
    LoggerName    QWORD ?                ; LoggerName
    CurrentTime    LONGLONG ?            ; timestamp of last event
    BuffersRead    ULONG ?                ; buffers read to date
    union    DUMMYUNIONNAME
        LogFileMode        DWORD ?        ; Mode of the logfile
        ProcessTraceMode    DWORD ?        ; Processing flags
    ENDS
    CurrentEvent    EVENT_TRACE <>            ; Current Event from this stream
    LogfileHeader    TRACE_LOGFILE_HEADER <>        ; logfile header structure
    BufferCallback    QWORD ?                ; is read
    BufferSize    DWORD ?
    Filled        DWORD ?
    EventsLost    DWORD ?
    union    DUMMYUNIONNAME2
        EventCallback        QWORD ?        ; callback for every event
        EventRecordCallback    QWORD ?
    ENDS
    IsKernelTrace    DWORD ?                ; TRUE for kernel logfile
    Context        QWORD ?                ; reserved for internal use
EVENT_TRACE_LOGFILEA ENDS

six_L

Hi,Fraile
Quotea question, in theory, do the structures you have put in your code work for both 64-bit and 32-bit systems?
1) The address is DWORD in 32bit os. The address is QWORD in 64bit os.
about the structure, you need to edit some variables to DWORD.
for example:
MS:
;============================================
typedef struct _EVENT_TRACE_LOGFILEA {
  LPSTR                         LogFileName;
  LPSTR                         LoggerName;
  LONGLONG                      CurrentTime;
  ULONG                         BuffersRead;
  union {
    ULONG LogFileMode;
    ULONG ProcessTraceMode;
  } DUMMYUNIONNAME;
  EVENT_TRACE                   CurrentEvent;
  TRACE_LOGFILE_HEADER          LogfileHeader;
  PEVENT_TRACE_BUFFER_CALLBACKA BufferCallback;
  ULONG                         BufferSize;
  ULONG                         Filled;
  ULONG                         EventsLost;
  union {
    PEVENT_CALLBACK        EventCallback;
    PEVENT_RECORD_CALLBACK EventRecordCallback;
  } DUMMYUNIONNAME2;
  ULONG                         IsKernelTrace;
  PVOID                         Context;
} EVENT_TRACE_LOGFILEA, *PEVENT_TRACE_LOGFILEA;
;============================================
64bit os:
;============================================
EVENT_TRACE_LOGFILEA STRUCT
    LogFileName    QWORD ?                ; Logfile Name
    LoggerName    QWORD ?                ; LoggerName
    CurrentTime    LONGLONG ?            ; timestamp of last event
    BuffersRead    ULONG ?                ; buffers read to date
    union    DUMMYUNIONNAME
        LogFileMode        DWORD ?        ; Mode of the logfile
        ProcessTraceMode    DWORD ?        ; Processing flags
    ENDS
    CurrentEvent    EVENT_TRACE <>            ; Current Event from this stream
    LogfileHeader    TRACE_LOGFILE_HEADER <>        ; logfile header structure
    BufferCallback    QWORD ?                ; is read
    BufferSize    DWORD ?
    Filled        DWORD ?
    EventsLost    DWORD ?
    union    DUMMYUNIONNAME2
        EventCallback        QWORD ?        ; callback for every event
        EventRecordCallback    QWORD ?
    ENDS
    IsKernelTrace    DWORD ?                ; TRUE for kernel logfile
    Context        QWORD ?                ; reserved for internal use
EVENT_TRACE_LOGFILEA ENDS
PEVENT_TRACE_LOGFILEA typedef ptr EVENT_TRACE_LOGFILEA
;============================================
32bit os:
;============================================
EVENT_TRACE_LOGFILEA STRUCT
    LogFileName    DWORD ?                ; Logfile Name
    LoggerName    DWORD ?                ; LoggerName
    CurrentTime    LONGLONG ?            ; timestamp of last event
    BuffersRead    ULONG ?                ; buffers read to date
    union    DUMMYUNIONNAME
        LogFileMode        DWORD ?        ; Mode of the logfile
        ProcessTraceMode    DWORD ?        ; Processing flags
    ENDS
    CurrentEvent    EVENT_TRACE <>            ; Current Event from this stream
    LogfileHeader    TRACE_LOGFILE_HEADER <>        ; logfile header structure
    BufferCallback    DWORD ?                ; is read
    BufferSize    DWORD ?
    Filled        DWORD ?
    EventsLost    DWORD ?
    union    DUMMYUNIONNAME2
        EventCallback        DWORD ?        ; callback for every event
        EventRecordCallback    DWORD ?
    ENDS
    IsKernelTrace    DWORD ?                ; TRUE for kernel logfile
    Context        DWORD ?                ; reserved for internal use
EVENT_TRACE_LOGFILEA ENDS
PEVENT_TRACE_LOGFILEA typedef ptr EVENT_TRACE_LOGFILEA

2) about union in the structures, you can use directly, don't care it. if you want to understand UNION, JJ2007 done an articulate explain. search the forum.

regard.
Say you, Say me, Say the codes together for ever.

TimoVJL

With C-compiler, it's possible to check aligments
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stddef.h>
// http://www.catb.org/esr/structure-packing/
// http://stackoverflow.com/questions/1208954/c-struct-grabbing-data-by-offset
#ifndef offsetof
#define offsetof(ty,m)  ((size_t)&(((ty*)0)->m))
#endif
#define GET_FIELD_OFFSET(type, field)    ((size_t)&(((type *)0)->field))
#define GET_FIELD_SIZE(type, field)      (sizeof(((type *)0)->field))

#define PRINTSIZE(x)  printf("\n%-16s %d %Xh bytes\n",#x,sizeof(x),sizeof(x));
#define PRINTOFSSIZE(type,field) printf("%-16s +%Xh %Xh\n",#field,(LONG)&(((type *)0)->field),sizeof(((type *)0)->field));
int main(void)
{
PRINTSIZE(PSINJECTDATA);
PRINTOFSSIZE(PSINJECTDATA,DataBytes);
PRINTOFSSIZE(PSINJECTDATA,InjectionPoint);
PRINTOFSSIZE(PSINJECTDATA,PageNumber);
return 0;
}
May the source be with you

Fraile

Hello Six_l and TimoVjl, I've done it!!! The event capturer is finally working. It was an alignment issue, after reviewing all the structures and adapting them to 32 bits, as Six_L suggested. Then, I checked the sizes of the structures in bytes, an idea I got from TimoVjl. After all this, I forced alignment to 8, and for now, it's capturing events from the .NET provider. However, my goal is to capture events from the "Microsoft Windows security auditing" provider, whose GUID is "{54849625-5478-4994-a5ba-3e3b0328c30d}". But it seems that it's not working with this provider... I tried to force a connection from the console using net use \\192.168.168.10\admin$ /user:fraile Entrada2020. This triggers a login error event, which is reflected in the event viewer, but the program doesn't CAPTURE it... frustrating.

Thank you for all the collaboration. Truly, thank you very much. If anyone feels like continuing with the project... I'll keep pursuing my goal, which is to capture login session events.

Six_L, do you feel like continuing?


Fraile

Hello Six_L, can you read the "UserData" field from the "Event_Record" structure?


ProcessEvent Proc Uses Ebx Esi Edi pEvent:PEVENT_RECORD

    Local eventHeader:PEVENT_HEADER
    Local eventDescriptor:PEVENT_DESCRIPTOR
    Local assemblyUserData:PAssemblyLoadUnloadRundown_V1
    Local szTmp[512]:Byte
    Local IDEvent:Word

Push Esi
Push Edi
Push Ebx


    Invoke RtlZeroMemory, Addr szTmp, SizeOf szTmp
    Invoke RtlZeroMemory, Addr tempbuffer, SizeOf tempbuffer

Mov Ebx, pEvent
Lea Eax, (EVENT_RECORD Ptr [Ebx]).EventHeader
Mov eventHeader, Eax

Lea Eax, (EVENT_RECORD Ptr [Ebx]).UserData
Mov assemblyUserData, Eax


Mov Esi, eventHeader
Lea Eax, (EVENT_HEADER Ptr [Esi]).EventDescriptor
Mov eventDescriptor, Eax

Mov Edi, eventDescriptor
Mov Cx, (EVENT_DESCRIPTOR Ptr [Edi]).Id
Mov IDEvent, Cx

.If IDEvent != 0

; Mostramos el ID.
; ****************
Invoke PasarADecimal, DWord Ptr IDEvent
Invoke WriteConsoleA, HandleConsola, Addr tempbuffer, 4, 0, 0

; Mostramos la descripciĆ³n.
; ************************
Mov Edi, assemblyUserData
Lea Eax, (AssemblyLoadUnloadRundown_V1 Ptr [Edi]).FullyQualifiedAssemblyName

Invoke wsprintf, Addr szTmp, Eax
Invoke WriteConsoleA, HandleConsola, Addr szTmp, SizeOf szTmp, 0, 0

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

    Invoke ImprimirSaltoDeLinea

.EndIf

Pop Ebx
Pop Edi
Pop Esi

Xor Eax, Eax

Ret
ProcessEvent EndP


If I can capture with your code, the ID, it works perfectly, but I want to try reading the .NET-specific events from the "AssemblyLoadUnloadRundown_V1" structure, where the event's identification is supposed to be more customized.


six_L

Hi,Fraile
1)
Quotecan you read the "UserData" field from the "Event_Record" structure?
Only 143 MethodLoadVerbose_V1 Event id(143,144,145,146) happens in my system. the author of dotnet trace gave the means of data.
.elseif cx == MethodLoadVerbose_V1 ;/*case MethodLoadVerbose_V1:
invoke  wsprintf,addr szTmp,CStr("(%d) MethodLoadVerbose_V1: Id of EVENT_DESCRIPTOR = %i",13,10),dqIndex,cxId
invoke  AddLog,addr szTmp
mov rax,(EVENT_RECORD PTR [rbx]).UserData
mov methodUserData,rax

;MethodNameSpace = methodUserData->MethodNameSpace
lea rcx,(_MethodLoadVerbose_V1 PTR [rax]).MethodNameSpace
mov MethodNameSpace,rcx

lea rsi,methodUserData
;MethodName = (WCHAR*)(((char*)methodUserData->MethodNameSpace) + (lstrlenW(methodUserData->MethodNameSpace) * 2) + 2)
;invoke  lstrlenW,addr (_MethodLoadVerbose_V1 PTR [rsi]).MethodNameSpace
invoke  lstrlenW,MethodNameSpace
shl rax,1 ;*2
;lea rcx,(_MethodLoadVerbose_V1 PTR [rsi]).MethodNameSpace
mov rcx,MethodNameSpace
add rcx,rax
add rcx,2
mov MethodName,rcx

;MethodSignature = (WCHAR*)(((char*)MethodName) + (lstrlenW(MethodName) * 2) + 2);
invoke  lstrlenW,MethodName
shl rax,1 ;*2
mov rcx,MethodName
add rcx,rax
add rcx,2
mov MethodSignature,rcx

  invoke RtlZeroMemory,ADDR szTmp,sizeof szTmp
mov rbx,eventHeader
invoke  wsprintf,addr szTmp,CStr("    ProcessId(%d), MethodNameSpace: %S, MethodName: %S, MethodSignature: %S",13,10),(EVENT_HEADER PTR [rbx]).ProcessId, MethodNameSpace,MethodName,MethodSignature
  invoke  AddLog,addr szTmp
2)
how do you know the guid of {54849625-5478-4994-a5ba-3e3b0328c30d} is the Microsoft Windows security auditing?

regard.
Say you, Say me, Say the codes together for ever.

Fraile

Hi Six_L, you can see it in different ways, one with the xperf utility using "-providers". Another way is through the Event Viewer; when you go into Security, it shows you the provider you need to capture. I'll send you a picture.


NoCforMe

Quote from: Fraile on March 22, 2024, 10:01:02 PM
ProcessEvent Proc Uses Ebx Esi Edi pEvent:PEVENT_RECORD
. . .
    Push Esi
    Push Edi
    Push Ebx
. . .
Just a small meta-note: if you use
USES <reg>, <reg> ...
in your code, all those pushes and pops are redundant and totally unnecessary, as that's what the assembler codes for you.
Assembly language programming should be fun. That's why I do it.

Fraile

Hi NoCforMe,
I don't fully agree with you, the procedure you are showing is a child procedure, which uses the same registers as the parent procedure. The child procedure should preserve the registers used by the parent procedure. If it doesn't, I would appreciate clarification. Thank you very much for your comment.

NoCforMe

I'm just saying that you have two things in that code that do exactly the same thing, which is redundant. When you put in USES <reg> <reg> ..., the assembler generates PUSHes and POPs for those registers for you, so your explicitly coding them is superflous and redundant. Not a show-stopper, no harm, but unnecessary.
Assembly language programming should be fun. That's why I do it.