LATER... ei_kerberos_kdc_session_key ...
[wireshark-sm.git] / extcap / etw_message.c
blob66364b832c41a06791a2176b2657d21296d48003
1 /* etw_message.h
3 * Copyright 2020, Odysseus Yang
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
11 #include "config.h"
12 #define WS_LOG_DOMAIN "etwdump"
14 #include "etw_message.h"
15 #include <wsutil/wslog.h>
16 ULONGLONG g_num_events;
18 VOID format_message(WCHAR* lpszMessage, PROPERTY_KEY_VALUE* propArray, DWORD dwPropertyCount, WCHAR* lpszOutBuffer, DWORD dwOutBufferCount)
20 DWORD startLoc = 0;
21 int percent_loc = 0;
23 for (int i = 0; lpszMessage[i] != L'\0';)
25 if (lpszMessage[i] != L'%')
27 i++;
28 continue;
30 if (lpszMessage[i + 1] == '%')
32 i += 2;
33 continue;
36 percent_loc = i;
37 i++;
39 if (iswdigit(lpszMessage[i]))
41 DWORD dwDigitalCount = 0;
42 WCHAR smallBuffer[MAX_SMALL_BUFFER] = { 0 };
43 while (iswdigit(lpszMessage[i]))
45 if (dwDigitalCount < (MAX_SMALL_BUFFER - 1))
47 smallBuffer[dwDigitalCount] = lpszMessage[i];
49 dwDigitalCount++;
50 i++;
53 /* We are not parsing this */
54 if (dwDigitalCount >= (MAX_SMALL_BUFFER - 1))
56 continue;
58 DWORD num = _wtoi(smallBuffer);
59 /* We are not parsing this */
60 if (num == 0 || num > dwPropertyCount || propArray[num - 1].value[0] == L'\0')
62 continue;
65 if (lpszMessage[i] == L'!' && lpszMessage[i + 1] == L'S' && lpszMessage[i + 2] == L'!')
67 i += 3;
70 /* We have everything */
71 lpszMessage[percent_loc] = L'\0';
72 StringCbCat(lpszOutBuffer, dwOutBufferCount, lpszMessage + startLoc);
73 StringCbCat(lpszOutBuffer, dwOutBufferCount, propArray[num - 1].value);
74 startLoc = i;
75 continue; // for
78 StringCbCat(lpszOutBuffer, dwOutBufferCount, lpszMessage + startLoc);
82 * Get the length of the property data. For MOF-based events, the size is inferred from the data type
83 * of the property. For manifest-based events, the property can specify the size of the property value
84 * using the length attribute. The length attribue can specify the size directly or specify the name
85 * of another property in the event data that contains the size. If the property does not include the
86 * length attribute, the size is inferred from the data type. The length will be zero for variable
87 * length, null-terminated strings and structures.
89 DWORD GetPropertyLength(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT PropertyLength)
91 DWORD status = ERROR_SUCCESS;
92 PROPERTY_DATA_DESCRIPTOR DataDescriptor = { 0 };
93 DWORD PropertySize = 0;
96 * If the property is a binary blob and is defined in a manifest, the property can
97 * specify the blob's size or it can point to another property that defines the
98 * blob's size. The PropertyParamLength flag tells you where the blob's size is defined.
100 if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamLength) == PropertyParamLength)
102 DWORD Length = 0; // Expects the length to be defined by a UINT16 or UINT32
103 DWORD j = pInfo->EventPropertyInfoArray[i].lengthPropertyIndex;
104 DataDescriptor.PropertyName = ((ULONGLONG)(pInfo)+(ULONGLONG)pInfo->EventPropertyInfoArray[j].NameOffset);
105 DataDescriptor.ArrayIndex = ULONG_MAX;
106 status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize);
107 status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Length);
108 *PropertyLength = (USHORT)Length;
110 else
112 if (pInfo->EventPropertyInfoArray[i].length > 0)
114 *PropertyLength = pInfo->EventPropertyInfoArray[i].length;
116 else
119 * If the property is a binary blob and is defined in a MOF class, the extension
120 * qualifier is used to determine the size of the blob. However, if the extension
121 * is IPAddrV6, you must set the PropertyLength variable yourself because the
122 * EVENT_PROPERTY_INFO.length field will be zero.
124 if (TDH_INTYPE_BINARY == pInfo->EventPropertyInfoArray[i].nonStructType.InType &&
125 TDH_OUTTYPE_IPV6 == pInfo->EventPropertyInfoArray[i].nonStructType.OutType)
127 *PropertyLength = (USHORT)sizeof(IN6_ADDR);
129 else if (TDH_INTYPE_UNICODESTRING == pInfo->EventPropertyInfoArray[i].nonStructType.InType ||
130 TDH_INTYPE_ANSISTRING == pInfo->EventPropertyInfoArray[i].nonStructType.InType ||
131 (pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)
133 *PropertyLength = pInfo->EventPropertyInfoArray[i].length;
135 else
137 ws_debug("Event %d Unexpected length of 0 for intype %d and outtype %d", g_num_events,
138 pInfo->EventPropertyInfoArray[i].nonStructType.InType,
139 pInfo->EventPropertyInfoArray[i].nonStructType.OutType);
141 status = ERROR_EVT_INVALID_EVENT_DATA;
142 goto cleanup;
146 cleanup:
147 return status;
150 DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize)
152 DWORD status = ERROR_SUCCESS;
153 PROPERTY_DATA_DESCRIPTOR DataDescriptor = { 0 };
154 DWORD PropertySize = 0;
156 if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamCount) == PropertyParamCount)
158 /* Expects the count to be defined by a UINT16 or UINT32 */
159 DWORD Count = 0;
160 DWORD j = pInfo->EventPropertyInfoArray[i].countPropertyIndex;
161 DataDescriptor.PropertyName = ((ULONGLONG)(pInfo)+(ULONGLONG)(pInfo->EventPropertyInfoArray[j].NameOffset));
162 DataDescriptor.ArrayIndex = ULONG_MAX;
163 status = TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &PropertySize);
164 status = TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, PropertySize, (PBYTE)&Count);
165 *ArraySize = (USHORT)Count;
167 else
169 *ArraySize = pInfo->EventPropertyInfoArray[i].count;
171 return status;
174 DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, PEVENT_MAP_INFO* pMapInfo)
176 DWORD status = ERROR_SUCCESS;
177 DWORD MapSize = 0;
179 /* Retrieve the required buffer size for the map info. */
180 status = TdhGetEventMapInformation(pEvent, pMapName, *pMapInfo, &MapSize);
181 if (ERROR_INSUFFICIENT_BUFFER == status)
183 *pMapInfo = (PEVENT_MAP_INFO)g_malloc(MapSize);
184 if (*pMapInfo == NULL)
186 status = ERROR_OUTOFMEMORY;
187 goto cleanup;
189 /* Retrieve the map info. */
190 status = TdhGetEventMapInformation(pEvent, pMapName, *pMapInfo, &MapSize);
193 if (ERROR_NOT_FOUND == status)
195 /* This case is okay. */
196 status = ERROR_SUCCESS;
199 cleanup:
201 return status;
205 PBYTE extract_properties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, DWORD PointerSize, USHORT i, PBYTE pUserData, PBYTE pEndOfUserData, PROPERTY_KEY_VALUE* pExtract)
207 TDHSTATUS status = ERROR_SUCCESS;
208 USHORT PropertyLength = 0;
209 USHORT UserDataConsumed = 0;
210 /* Last member of a structure */
211 DWORD LastMember = 0;
212 USHORT ArraySize = 0;
213 PEVENT_MAP_INFO pMapInfo = NULL;
214 WCHAR formatted_data[MAX_LOG_LINE_LENGTH];
215 DWORD formatted_data_size = sizeof(formatted_data);
216 LPWSTR oversize_formatted_data = NULL;
220 StringCbCopy(pExtract->key, sizeof(pExtract->key), (PWCHAR)((PBYTE)(pInfo)+pInfo->EventPropertyInfoArray[i].NameOffset));
221 /* Get the length of the property. */
222 status = GetPropertyLength(pEvent, pInfo, i, &PropertyLength);
223 if (ERROR_SUCCESS != status)
225 StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: GetPropertyLength failed 0x%x", pExtract->key, status);
226 break;
229 /* Get the size of the array if the property is an array. */
230 status = GetArraySize(pEvent, pInfo, i, &ArraySize);
231 if (ERROR_SUCCESS != status)
233 StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: GetArraySize failed 0x%x", pExtract->key, status);
234 break;
237 /* Add [] for an array property */
238 if (ArraySize > 1)
240 StringCbCat(pExtract->value, sizeof(pExtract->value), L"[");
243 for (USHORT k = 0; k < ArraySize; k++)
245 /* Add array item separator "," */
246 if (k > 0)
248 StringCbCat(pExtract->value, sizeof(pExtract->value), L",");
250 /* If the property is a structure, print the members of the structure. */
251 if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)
253 /* Add {} for an array property */
254 StringCbCat(pExtract->value, sizeof(pExtract->value), L"{");
255 /* Add struct member separator ";" */
256 if (k > 0)
258 StringCbCat(pExtract->value, sizeof(pExtract->value), L";");
260 LastMember = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex +
261 pInfo->EventPropertyInfoArray[i].structType.NumOfStructMembers;
263 for (USHORT j = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex; j < LastMember; j++)
265 pUserData = extract_properties(pEvent, pInfo, PointerSize, j, pUserData, pEndOfUserData, pExtract);
266 if (NULL == pUserData)
268 StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: extract_properties of member %d failed 0x%x", pExtract->key, j, status);
269 break;
272 StringCbCat(pExtract->value, sizeof(pExtract->value), L"}");
274 else
276 /* Get the name/value mapping only at the first time if the property specifies a value map. */
277 if (pMapInfo == NULL)
279 status = GetMapInfo(pEvent,
280 (PWCHAR)((PBYTE)(pInfo)+pInfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset),
281 &pMapInfo);
283 if (ERROR_SUCCESS != status)
285 StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: GetMapInfo failed 0x%x", pExtract->key, status);
286 break;
290 /* Get the size of the buffer required for the formatted data. */
292 status = TdhFormatProperty(
293 pInfo,
294 pMapInfo,
295 PointerSize,
296 pInfo->EventPropertyInfoArray[i].nonStructType.InType,
297 pInfo->EventPropertyInfoArray[i].nonStructType.OutType,
298 PropertyLength,
299 (USHORT)(pEndOfUserData - pUserData),
300 pUserData,
301 &formatted_data_size,
302 formatted_data,
303 &UserDataConsumed);
305 if (ERROR_INSUFFICIENT_BUFFER == status)
307 if (oversize_formatted_data)
309 g_free(oversize_formatted_data);
310 oversize_formatted_data = NULL;
313 oversize_formatted_data = (LPWSTR)g_malloc(formatted_data_size);
314 if (oversize_formatted_data == NULL)
316 status = ERROR_OUTOFMEMORY;
317 StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: Allocate FormattedData memory (size %d) for array item %d failed 0x%x", pExtract->key, formatted_data_size, k, status);
318 break;
321 /* Retrieve the formatted data. */
322 status = TdhFormatProperty(
323 pInfo,
324 pMapInfo,
325 PointerSize,
326 pInfo->EventPropertyInfoArray[i].nonStructType.InType,
327 pInfo->EventPropertyInfoArray[i].nonStructType.OutType,
328 PropertyLength,
329 (USHORT)(pEndOfUserData - pUserData),
330 pUserData,
331 &formatted_data_size,
332 oversize_formatted_data,
333 &UserDataConsumed);
336 if (ERROR_SUCCESS == status)
338 if (formatted_data_size > sizeof(formatted_data) && oversize_formatted_data != NULL)
340 /* Any oversize FormattedData will be truncated */
341 StringCbCat(pExtract->value, sizeof(pExtract->value), oversize_formatted_data);
343 else
345 StringCbCat(pExtract->value, sizeof(pExtract->value), formatted_data);
347 pUserData += UserDataConsumed;
349 else
351 StringCbPrintf(pExtract->value, sizeof(pExtract->value), L"%s: TdhFormatProperty for array item %d failed 0x%x", pExtract->key, k, status);
352 break;
356 /* Add [] for an array property */
357 if (ArraySize > 1)
359 StringCbCat(pExtract->value, sizeof(pExtract->value), L"]");
361 } while (false);
363 if (oversize_formatted_data)
365 g_free(oversize_formatted_data);
366 oversize_formatted_data = NULL;
368 if (pMapInfo)
370 g_free(pMapInfo);
371 pMapInfo = NULL;
374 return (ERROR_SUCCESS == status) ? pUserData : NULL;
378 BOOL get_event_information(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO* pInfo)
380 BOOL bReturn = false;
381 DWORD status;
382 DWORD BufferSize = 0;
384 /* Retrieve the required buffer size for the event metadata. */
385 status = TdhGetEventInformation(pEvent, 0, NULL, *pInfo, &BufferSize);
386 if (ERROR_INSUFFICIENT_BUFFER == status)
388 *pInfo = (TRACE_EVENT_INFO*)g_malloc(BufferSize);
389 if (*pInfo == NULL)
391 ws_debug("Event %d GetEventInformation Failed to allocate memory for event info (size=%lu).", g_num_events, BufferSize);
392 goto Exit;
394 /* Retrieve the event metadata. */
395 status = TdhGetEventInformation(pEvent, 0, NULL, *pInfo, &BufferSize);
398 if (ERROR_SUCCESS != status)
400 goto Exit;
402 bReturn = true;
403 Exit:
405 return bReturn;
409 * Editor modelines - https://www.wireshark.org/tools/modelines.html
411 * Local variables:
412 * c-basic-offset: 4
413 * tab-width: 8
414 * indent-tabs-mode: nil
415 * End:
417 * vi: set shiftwidth=4 tabstop=8 expandtab:
418 * :indentSize=4:tabSize=8:noTabs=true: