当前位置: 首页 > 内核 > 正文

ETW监控进程

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wbemidl.h>
#include <wmistr.h>
#include <evntrace.h>
#include <Evntcons.h>
#include <vector>
#include <tdh.h>
#include <string>
#include <in6addr.h>

#pragma comment(lib, "tdh.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "Advapi32.lib")

using namespace std;

#define filename(x) strrchr(x,'\\')?strrchr(x,'\\')+1:x
#define GetLastErrorEx(lpszFunction){LPVOID lpMsgBuf;DWORD dw = GetLastError();FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,NULL,dw,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&lpMsgBuf,0, NULL);\
if (lpszFunction)\
printf("%s(Line:%d)->Funtion:%s\ndiyInfo:%s\nError(%d)->Info:%s\n",\
filename(__FILE__), __LINE__, __FUNCTION__, lpszFunction, dw, lpMsgBuf);\
else \
printf("%s(Line:%d)->Funtion:%s\nError(%d)->Info:%s\n",\
filename(__FILE__), __LINE__, __FUNCTION__, dw, lpMsgBuf);\
LocalFree(lpMsgBuf);\
}

#define LOGSESSION_NAME L"Testing ETW Consumer"

TRACEHANDLE sessionHandle;
TRACEHANDLE traceHandle;

DWORD PointerSize = 0;

int bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME) + sizeof(WCHAR);

auto pSessionProperties = static_cast<PEVENT_TRACE_PROPERTIES>(malloc(bufferSize));

//"{b2bcc945-9eb9-4231-883c-d6455cf4d86b}"
static const GUID SessionGuid =
{ 0xb2bcc945, 0x9eb9, 0x4231,{ 0x88, 0x3c, 0xd6, 0x45, 0x5c, 0xf4, 0xd8, 0x6b } };

// Microsoft-Windows-Kernel-Process {22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716}
static const GUID PROCESS_PROVIDER_GUID =
{ 0x22fb2cd6, 0x0e7b, 0x422b,{ 0xa0, 0xc7, 0x2f, 0xad, 0x1f, 0xd0, 0xe7, 0x16 } };

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\n", (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\n", (LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset));
					MatchFound = TRUE;
					break;
				}
			}

			if (FALSE == MatchFound)
			{
				wprintf(L"%lu\n", *(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"\n");
		}
		else
		{
			wprintf(L"%lu\n", *(PULONG)pData);
		}
	}
}

#define MAX_NAME 256
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\n", 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\n", StringLength, (LPSTR)pData);
		break;
	}

	case TDH_INTYPE_INT8:
	{
		wprintf(L"%hd\n", *(PCHAR)pData);
		break;
	}

	case TDH_INTYPE_UINT8:
	{
		if (TDH_OUTTYPE_HEXINT8 == OutType)
		{
			wprintf(L"0x%x\n", *(PBYTE)pData);
		}
		else
		{
			wprintf(L"%hu\n", *(PBYTE)pData);
		}

		break;
	}

	case TDH_INTYPE_INT16:
	{
		wprintf(L"%hd\n", *(PSHORT)pData);
		break;
	}

	case TDH_INTYPE_UINT16:
	{
		if (TDH_OUTTYPE_HEXINT16 == OutType)
		{
			wprintf(L"0x%x\n", *(PUSHORT)pData);
		}
		else if (TDH_OUTTYPE_PORT == OutType)
		{
			wprintf(L"%hu\n", ntohs(*(PUSHORT)pData));
		}
		else
		{
			wprintf(L"%hu\n", *(PUSHORT)pData);
		}

		break;
	}

	case TDH_INTYPE_INT32:
	{
		if (TDH_OUTTYPE_HRESULT == OutType)
		{
			wprintf(L"0x%x\n", *(PLONG)pData);
		}
		else
		{
			wprintf(L"%d\n", *(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\n", *(PULONG)pData);
		}
		else if (TDH_OUTTYPE_IPV4 == OutType)
		{
			wprintf(L"%d.%d.%d.%d\n", (*(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\n", *(PULONG)pData);
			}
		}

		break;
	}

	case TDH_INTYPE_INT64:
	{
		wprintf(L"%I64d\n", *(PLONGLONG)pData);

		break;
	}

	case TDH_INTYPE_UINT64:
	{
		if (TDH_OUTTYPE_HEXINT64 == OutType)
		{
			wprintf(L"0x%x\n", *(PULONGLONG)pData);
		}
		else
		{
			wprintf(L"%I64u\n", *(PULONGLONG)pData);
		}

		break;
	}

	case TDH_INTYPE_FLOAT:
	{
		wprintf(L"%f\n", *(PFLOAT)pData);

		break;
	}

	case TDH_INTYPE_DOUBLE:
	{
		wprintf(L"%I64f\n", *(DOUBLE*)pData);

		break;
	}

	case TDH_INTYPE_BOOLEAN:
	{
		wprintf(L"%s\n", (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.\n", status = GetLastError());
			//	goto cleanup;
			//}

			//fnRtlIpv6AddressToString((IN6_ADDR*)pData, IPv6AddressAsString);

			//wprintf(L"%s\n", IPv6AddressAsString);
		}
		else
		{
			for (DWORD i = 0; i < DataSize; i++)
			{
				wprintf(L"%.2x", pData[i]);
			}

			wprintf(L"\n");
		}

		break;
	}

	case TDH_INTYPE_GUID:
	{
		WCHAR szGuid[50];

		StringFromGUID2(*(GUID*)pData, szGuid, sizeof(szGuid) - 1);
		wprintf(L"%s\n", szGuid);

		break;
	}

	case TDH_INTYPE_POINTER:
	case TDH_INTYPE_SIZET:
	{
		if (4 == PointerSize)
		{
			wprintf(L"0x%x\n", *(PULONG)pData);
		}
		else
		{
			wprintf(L"0x%x\n", *(PULONGLONG)pData);
		}

		break;
	}

	case TDH_INTYPE_FILETIME:
	{
		ULONGLONG TimeStamp = 0;
		SYSTEMTIME st;
		SYSTEMTIME stLocal;
		FILETIME ft;
		ft.dwHighDateTime = pEvent->EventHeader.TimeStamp.HighPart;
		ft.dwLowDateTime = pEvent->EventHeader.TimeStamp.LowPart;

		FileTimeToSystemTime(&ft, &st);
		SystemTimeToTzSpecificLocalTime(NULL, &st, &stLocal);

		TimeStamp = pEvent->EventHeader.TimeStamp.QuadPart;

		//Local System Time(YYYY-MM-DD HH:MM:SS): 
		wprintf(L"%d-%d-%d %d:%d:%d\n", stLocal.wYear, stLocal.wMonth, stLocal.wDay, stLocal.wHour, stLocal.wMinute, stLocal.wSecond);

		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\n");
				status = ERROR_SUCCESS;
			}
			else
			{
				wprintf(L"LookupAccountSid failed with %lu\n", status = GetLastError());
			}

			goto cleanup;
		}
		else
		{
			wprintf(L"%s\\%s\n", DomainName, UserName);
		}

		break;
	}

	case TDH_INTYPE_HEXINT32:
	{
		wprintf(L"0x%x\n", (PULONG)pData);
		break;
	}

	case TDH_INTYPE_HEXINT64:
	{
		wprintf(L"0x%x\n", (PULONGLONG)pData);
		break;
	}

	case TDH_INTYPE_UNICODECHAR:
	{
		wprintf(L"%c\n", *(PWCHAR)pData);
		break;
	}

	case TDH_INTYPE_ANSICHAR:
	{
		wprintf(L"%C\n", *(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 += 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\n");
					status = ERROR_SUCCESS;
				}
				else
				{
					wprintf(L"LookupAccountSid failed with %lu\n", status = GetLastError());
				}

				goto cleanup;
			}
			else
			{
				wprintf(L"%s\\%s\n", DomainName, UserName);
			}
		}

		break;
	}

	default:
		status = ERROR_NOT_FOUND;
	}

cleanup:

	return status;
}

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;
}

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'\0';
	}
}

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).\n", 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.\n", status);
		}
	}

cleanup:

	return status;
}

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"\n");

			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.\n");
					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.\n");
				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\n", status);
					goto cleanup;
				}

				pData = (PBYTE)malloc(PropertySize);

				if (NULL == pData)
				{
					wprintf(L"Failed to allocate memory for property data\n");
					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\n");
					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\n");
					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;
}

void Showinfo(PTRACE_EVENT_INFO& pInfo)
{
	printf(("Id: %u\n"), pInfo->EventDescriptor.Id);
	printf(("Version: %u\n"), pInfo->EventDescriptor.Version);
	printf(("Channel: %u\n"), pInfo->EventDescriptor.Channel);
	printf(("Level: %u\n"), pInfo->EventDescriptor.Level);
	printf(("Opcode: %u\n"), pInfo->EventDescriptor.Opcode);
	printf(("Task: %u\n"), pInfo->EventDescriptor.Task);
	printf(("Keyword: %lu\n"), pInfo->EventDescriptor.Keyword);

	wprintf(L"ProviderName: %s\n", (WCHAR*)pInfo + pInfo->ProviderNameOffset);
	wprintf(L"ChannelName: %s\n", (WCHAR*)pInfo + pInfo->ChannelNameOffset);
	wprintf(L"KeywordsName: %s\n", (WCHAR*)pInfo + pInfo->KeywordsNameOffset);
	wprintf(L"TaskName: %s\n", (WCHAR*)pInfo + pInfo->TaskNameOffset);

	//ShowNameString((LPBYTE)pInfo + pInfo->ProviderNameOffset, pInfo->ProviderNameOffset, L"ProviderName");
	//ShowNameString((LPBYTE)pInfo + pInfo->ChannelNameOffset, pInfo->ChannelNameOffset, L"ChannelName");
	//ShowNameString((LPBYTE)pInfo + pInfo->KeywordsNameOffset, pInfo->KeywordsNameOffset, L"KeywordsName");
	//ShowNameString((LPBYTE)pInfo + pInfo->TaskNameOffset, pInfo->TaskNameOffset, L"TaskName");
}

DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO& pInfo)
{
	DWORD status = ERROR_SUCCESS;
	DWORD BufferSize = 0;

	status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);

	if (ERROR_INSUFFICIENT_BUFFER == status)
	{
		pInfo = (TRACE_EVENT_INFO*)malloc(BufferSize);
		if (pInfo == NULL)
		{
			printf("Failed to allocate memory for event info (size=%lu).\n", BufferSize);
			status = ERROR_OUTOFMEMORY;
			goto cleanup;
		}

		// Retrieve the event metadata.

		status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);
	}

	if (ERROR_SUCCESS != status)
	{
		GetLastErrorEx("TdhGetEventInformation 错误代码", status);
	}

cleanup:

	return status;
}

VOID WINAPI EventRecordCallback(PEVENT_RECORD pEventRecord)
{
	DWORD status = 0;
	PTRACE_EVENT_INFO pInfo = NULL;
	LPWSTR pwsEventGuid = NULL;
	printf("ETW ********************************************************** start\n");
	if (!IsEqualGUID(pEventRecord->EventHeader.ProviderId, PROCESS_PROVIDER_GUID))
	{
		return;
	}
	else
	{
		status = GetEventInformation(pEventRecord, pInfo);

		if (ERROR_SUCCESS != status)
		{
			GetLastErrorEx("GetEventInformation 错误代码", status);
			exit(0);
		}

		// 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))
			{
				GetLastErrorEx("StringFromCLSID 错误代码", hr);
				status = hr;
				exit(0);
			}

			wprintf(L"\nEvent GUID: %s\n", pwsEventGuid);
			CoTaskMemFree(pwsEventGuid);
			pwsEventGuid = NULL;

			wprintf(L"Event version: %d\n", pEventRecord->EventHeader.EventDescriptor.Version);
			wprintf(L"Event type: %d\n", pEventRecord->EventHeader.EventDescriptor.Opcode);
		}
		else if (DecodingSourceXMLFile == pInfo->DecodingSource) // Instrumentation manifest
		{
		}
		else // Not handling the WPP case
		{
			exit(0);
		}
	}


	//打印etw info
	Showinfo(pInfo);

	// 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 == (pEventRecord->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER))
	{
		PointerSize = 4;
	}
	else
	{
		PointerSize = 8;
	}


	for (USHORT i = 0; i < pInfo->TopLevelPropertyCount; i++)
	{
		//ShowPropertyInfo(pEventRecord, pInfo, &pInfo->EventPropertyInfoArray[i], NULL);
		status = PrintProperties(pEventRecord, pInfo, i, NULL, 0);
		if (ERROR_SUCCESS != status)
		{
			wprintf(L"Printing top level properties failed.\n");
		}
	}

	printf("ETW ********************************************************** end\n\n");
	return;
}


static DWORD WINAPI Win32TracingThread(LPVOID Parameter)
{
	printf("processing trace...\n");
	auto ptStatus = ProcessTrace(&traceHandle, 1, NULL, NULL);
	if (ptStatus != ERROR_SUCCESS && ptStatus != ERROR_CANCELLED)
	{
		GetLastErrorEx("ProcessTrace 错误代码", ptStatus);
	}
	return(0);
}

int main(void)
{
	printf("entering main program...\n");

	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->FlushTimer = 0;
	//pSessionProperties->EnableFlags = EVENT_TRACE_FLAG_PROCESS | EVENT_TRACE_FLAG_PROCESS_COUNTERS;
	pSessionProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
	pSessionProperties->LogFileNameOffset = 0;
	pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
	StringCbCopy((STRSAFE_LPWSTR)((char*)pSessionProperties + pSessionProperties->LoggerNameOffset), sizeof(LOGSESSION_NAME), LOGSESSION_NAME);

	// stop any previous session
	auto stopStatus = ControlTrace(0, LOGSESSION_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);

	printf("starting trace...\n");
	auto sTrStatus = StartTrace(static_cast<PTRACEHANDLE>(&sessionHandle), LOGSESSION_NAME, pSessionProperties);

	ENABLE_TRACE_PARAMETERS params{};
	params.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;

	printf("enabling trace...\n");
	auto eTrExstatus = EnableTraceEx2(sessionHandle, &PROCESS_PROVIDER_GUID,
		EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_INFORMATION, 0x10 | 0x40, 0, 0, ¶ms);
	if (eTrExstatus != ERROR_SUCCESS)
	{
		GetLastErrorEx("EnableTraceEx2 错误代码", eTrExstatus);
		ControlTrace(sessionHandle, nullptr, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
		return -1;
	}

	EVENT_TRACE_LOGFILE loggerInfo = { 0 };

	loggerInfo.ProcessTraceMode = EVENT_TRACE_REAL_TIME_MODE | PROCESS_TRACE_MODE_EVENT_RECORD;

	//loggerInfo.BufferCallback = BufferCallback;

	// provide a callback whenever we get an event record
	loggerInfo.EventRecordCallback = (PEVENT_RECORD_CALLBACK)EventRecordCallback;
	loggerInfo.Context = NULL;

	loggerInfo.LoggerName = (WCHAR*)LOGSESSION_NAME;
	loggerInfo.LogFileName = NULL;

	printf("opening trace...\n");
	traceHandle = OpenTrace(&loggerInfo);

	// calling thread will be blocked until BufferCallback returns FALSE or all events are delivered
	// or CloseTrace is called
	DWORD ThreadID;
	HANDLE ThreadHandle = CreateThread(0, 0, Win32TracingThread, 0, 0, &ThreadID);

	bool exit2 = false;
	while (exit2 == false)
	{
		if (GetAsyncKeyState(VK_ESCAPE))
		{
			exit2 = true;
			printf("escape pressed, exiting loop...\n");
		}
	}
	CloseHandle(ThreadHandle);

	if ((TRACEHANDLE)INVALID_HANDLE_VALUE != traceHandle)
	{
		printf("in cleanup...\n");
		printf("closing trace...\n");
		auto ctStatus = CloseTrace(traceHandle);
	}

	auto cTrStatus = ControlTrace(sessionHandle, nullptr, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
	auto eTrStatus = EnableTraceEx2(sessionHandle, &PROCESS_PROVIDER_GUID, EVENT_CONTROL_CODE_DISABLE_PROVIDER, 0, 0, 0, 0, nullptr);

	free(pSessionProperties);
}
#include <iostream>
#include <string>
#include <cstring>
#include <windows.h>
#include <evntrace.h>
#include <psapi.h>
#include <direct.h>
#include <evntcons.h>
using namespace std;

char SESSION_NAME_FILE[] = "Sample_Process";

const UCHAR _Flag[] = { 173, 74, 129, 158, 4, 50, 210, 17, 154, 130, 0, 96, 8, 168, 105, 57 };

EVENT_TRACE_PROPERTIES m_TraceConfig;

UCHAR m_pTraceConfig[2048];

char m_File[256];

BOOL m_DoWhile;

TRACEHANDLE m_hTraceHandle;

ULONG64 m_hTraceHandle_econt[1];

TRACEHANDLE m_hSessionHandle;

string Unicode_To_Ansi(wstring strValue)
{
    static CHAR sBuff[1024] = { 0 };
    int iRet = WideCharToMultiByte(CP_ACP, 0, strValue.c_str(), -1, sBuff, sizeof(sBuff), NULL, NULL);
    if (iRet > 0) {
        return string(sBuff);
    }
    return "";
}

VOID WINAPI MyProcessRecordEvents(PEVENT_RECORD EventRecord)
{
    switch (EventRecord->EventHeader.EventDescriptor.Id)
    {
    case 1://创建进程
        cout << "创建进程!进行创建进行的进程ID:" <<
            EventRecord->EventHeader.ProcessId <<
            ",线程ID:" <<
            EventRecord->EventHeader.ThreadId <<
            ",进程SessionID:" <<
            *(ULONG*)(((PUCHAR)EventRecord->UserData) + 32) <<
            ",创建的进程ID:" <<
            *(ULONG*)(((PUCHAR)EventRecord->UserData) + 0) <<
            ",创建的进程路径:" <<
            Unicode_To_Ansi(wstring((wchar_t*)(((PUCHAR)EventRecord->UserData) + 60)))
            << endl;
        break;
    case 2://进程退出
        cout << "进程退出!进程ID:" <<
            EventRecord->EventHeader.ProcessId <<
            ",线程ID:" <<
            EventRecord->EventHeader.ThreadId <<
            ", 进程名:" <<
            ((LPSTR)EventRecord->UserData) + 84
            << endl;
        break;
        cout << "进程ID:" << EventRecord->EventHeader.ProcessId << ",未知的行为:0x" << hex << EventRecord->EventHeader.EventDescriptor.Id << endl;
    default:

        break;
    }
}

void CloseEtw()
{
    ULONG l_result = StopTraceA(m_hSessionHandle, SESSION_NAME_FILE, (PEVENT_TRACE_PROPERTIES)(m_pTraceConfig + 8));
    if (m_hTraceHandle != NULL)
    {
        CloseTrace(m_hTraceHandle);
    }
}
#pragma warning(disable:4996)
DWORD WINAPI OpenEtw(LPVOID lpThreadParameter)
{
    m_DoWhile = TRUE;
    printf("size is %d\n", sizeof(m_TraceConfig));
    printf("size is %d\n", sizeof(WNODE_HEADER));
    _getcwd(m_File, sizeof(m_File));

    strcat(m_File, "\\MyFile.etl");
    m_TraceConfig.Wnode.BufferSize = 1024;
    m_TraceConfig.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
    m_TraceConfig.Wnode.ClientContext = 3;
    m_TraceConfig.BufferSize = 1;
    m_TraceConfig.MinimumBuffers = 16;
    m_TraceConfig.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;

    m_TraceConfig.LoggerNameOffset = 120;
    m_TraceConfig.FlushTimer = 1;

    RtlMoveMemory(m_pTraceConfig + 8, &m_TraceConfig, 120);
    RtlCopyMemory(m_pTraceConfig + 128, SESSION_NAME_FILE, sizeof(SESSION_NAME_FILE));
    RtlCopyMemory(m_pTraceConfig + 128 + sizeof(SESSION_NAME_FILE), m_File, strlen(m_File));
    RtlCopyMemory(m_pTraceConfig + 28, _Flag, sizeof(_Flag));

    ULONG l_result = StartTraceA(&m_hSessionHandle, SESSION_NAME_FILE, (PEVENT_TRACE_PROPERTIES)(m_pTraceConfig + 8));

    if (m_hSessionHandle == NULL && l_result == ERROR_ACCESS_DENIED)
    {
        cout << "StartTraceA失败!原因:无管理员权限!" << endl;
        return 0;
    }
    else if (m_hSessionHandle == NULL && l_result == ERROR_ALREADY_EXISTS)
    {

        m_hSessionHandle = 44;//输入上一次终止时候的句柄
        CloseEtw();
        //EVENT_TRACE_CONTROL_STOP
        cout << "StartTraceA失败!原因:已经有Etw事件进行数据跟踪!请使用上方屏蔽代码关闭事件或者使用 计算机管理 停用事件:Sample_Process" << endl;
        ControlTraceA(m_hSessionHandle, SESSION_NAME_FILE, (PEVENT_TRACE_PROPERTIES)(m_pTraceConfig + 8), EVENT_TRACE_CONTROL_STOP);
        return 0;
    }
    cout << "hSessionHandle: " << m_hSessionHandle << endl;
    const UCHAR m_ProcessGUID[] = { 214, 44, 251, 34, 123, 14, 43, 66, 160, 199, 47, 173, 31, 208, 231, 22 }; // PsProvGuid
    l_result = EnableTraceEx((LPCGUID)(m_ProcessGUID), 0, m_hSessionHandle, 1, 0, 16, 0, 0, 0);         //这里MatchAnyKeyword的64其实是0x40,表示 #KERNEL_KEYWORDS_IMAGE

    EVENT_TRACE_LOGFILEA m_Logfile;
    ZeroMemory(&m_Logfile, sizeof(m_Logfile));
    m_Logfile.LoggerName = SESSION_NAME_FILE;
    *((ULONG*)((PUCHAR)&m_Logfile + 20)) = 268439808;
    m_Logfile.EventRecordCallback = MyProcessRecordEvents;
    m_Logfile.Context = (PVOID)0x114514;//随便输入一个数就好了
    SetLastError(0);
    m_hTraceHandle = OpenTraceA(&m_Logfile);

    cout << "开始监视!" << endl;
    m_hTraceHandle_econt[0] = m_hTraceHandle;
    ULONG rc = ProcessTrace(m_hTraceHandle_econt, 1, 0, 0);
    return 0;
}

int main()
{
    CreateThread(NULL, NULL, OpenEtw, NULL, NULL, NULL);
    //Sleep(10000);
    system("pause");
    CloseEtw();
    return 0;
}

本文固定链接: https://www.socarates.online/index.php/2024/04/23/etw%e7%9b%91%e6%8e%a7%e8%bf%9b%e7%a8%8b/ | 安全技术研究

avatar
该日志由 Socarates 于2024年04月23日发表在 内核 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: ETW监控进程 | 安全技术研究
关键字: , ,
【上一篇】

ETW监控进程:等您坐沙发呢!

发表评论


快捷键:Ctrl+Enter