#define AssemblyDCStart_V1 155 #define MethodLoadVerbose_V1 143 #include #include #include #include #include #include static GUID ClrRuntimeProviderGuid = { 0xe13c0d23, 0xccbc, 0x4e12, { 0x93, 0x1b, 0xd9, 0xcc, 0x2e, 0xee, 0x27, 0xe4 } }; // Can be stopped with 'logman stop "dotnet trace" -etw' const char name[] = "dotnet trace\0"; #pragma pack(1) typedef struct _AssemblyLoadUnloadRundown_V1 { ULONG64 AssemblyID; ULONG64 AppDomainID; ULONG64 BindingID; ULONG AssemblyFlags; WCHAR FullyQualifiedAssemblyName[1]; } AssemblyLoadUnloadRundown_V1, *PAssemblyLoadUnloadRundown_V1; typedef struct _MethodLoadVerbose_V1 { ULONG64 MethodID; ULONG64 ModuleID; ULONG64 MethodStartAddress; DWORD MethodSize; DWORD MethodToken; DWORD MethodFlags; WCHAR MethodNameSpace[1]; } MethodLoadUnloadVerbose_V1, *PMethodLoadUnloadVerbose_V1; #pragma pack() static void NTAPI ProcessEvent(PEVENT_RECORD EventRecord) { PEVENT_HEADER eventHeader = &EventRecord->EventHeader; PEVENT_DESCRIPTOR eventDescriptor = &eventHeader->EventDescriptor; AssemblyLoadUnloadRundown_V1* assemblyUserData; MethodLoadUnloadVerbose_V1* methodUserData; switch (eventDescriptor->Id) { case AssemblyDCStart_V1: assemblyUserData = (AssemblyLoadUnloadRundown_V1*)EventRecord->UserData; wprintf(L"[%d] - Assembly: %s\n", eventHeader->ProcessId, assemblyUserData->FullyQualifiedAssemblyName); break; case MethodLoadVerbose_V1: methodUserData = (struct _MethodLoadVerbose_V1*)EventRecord->UserData; WCHAR* MethodNameSpace = methodUserData->MethodNameSpace; WCHAR* MethodName = (WCHAR*)(((char*)methodUserData->MethodNameSpace) + (lstrlenW(methodUserData->MethodNameSpace) * 2) + 2); WCHAR* MethodSignature = (WCHAR*)(((char*)MethodName) + (lstrlenW(MethodName) * 2) + 2); wprintf(L"[%d] - MethodNameSpace: %s\n", eventHeader->ProcessId, methodUserData->MethodNameSpace); wprintf(L"[%d] - MethodName: %s\n", eventHeader->ProcessId, MethodName); wprintf(L"[%d] - MethodSignature: %s\n", eventHeader->ProcessId, MethodSignature); break; } } int main(void) { TRACEHANDLE hTrace = 0; ULONG result, bufferSize; EVENT_TRACE_LOGFILEA trace; EVENT_TRACE_PROPERTIES *traceProp; printf("ETW .NET Trace example - @_xpn_\n\n"); memset(&trace, 0, sizeof(EVENT_TRACE_LOGFILEA)); trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD; trace.LoggerName = (LPSTR)name; trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK)ProcessEvent; bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(name) + sizeof(WCHAR); traceProp = (EVENT_TRACE_PROPERTIES*)LocalAlloc(LPTR, bufferSize); traceProp->Wnode.BufferSize = bufferSize; traceProp->Wnode.ClientContext = 2; traceProp->Wnode.Flags = WNODE_FLAG_TRACED_GUID; traceProp->LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY; traceProp->LogFileNameOffset = 0; traceProp->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); if ((result = StartTraceA(&hTrace, (LPCSTR)name, traceProp)) != ERROR_SUCCESS) { printf("[!] Error starting trace: %d\n", result); return 1; } if ((result = EnableTraceEx( &ClrRuntimeProviderGuid, NULL, hTrace, 1, TRACE_LEVEL_VERBOSE, 0x8 | 0x10, // LoaderKeyword | JITKeyword 0, 0, NULL )) != ERROR_SUCCESS) { printf("[!] Error EnableTraceEx\n"); return 2; } hTrace = OpenTrace(&trace); if (hTrace == INVALID_PROCESSTRACE_HANDLE) { printf("[!] Error OpenTrace\n"); return 3; } result = ProcessTrace(&hTrace, 1, NULL, NULL); if (result != ERROR_SUCCESS) { printf("[!] Error ProcessTrace\n"); return 4; } return 0; }