winevt_c 0.8.0 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,696 +1,727 @@
1
- #include <winevt_c.h>
2
-
3
- #include <sddl.h>
4
- #include <stdlib.h>
5
- #include <string>
6
- #include <vector>
7
-
8
- VALUE
9
- wstr_to_rb_str(UINT cp, const WCHAR* wstr, int clen)
10
- {
11
- VALUE vstr;
12
- CHAR* ptr;
13
- int len = WideCharToMultiByte(cp, 0, wstr, clen, nullptr, 0, nullptr, nullptr);
14
- ptr = ALLOCV_N(CHAR, vstr, len);
15
- WideCharToMultiByte(cp, 0, wstr, clen, ptr, len, nullptr, nullptr);
16
- VALUE str = rb_utf8_str_new_cstr(ptr);
17
- ALLOCV_END(vstr);
18
-
19
- return str;
20
- }
21
-
22
- void
23
- raise_system_error(VALUE error, DWORD errorCode)
24
- {
25
- WCHAR msgBuf[256] = { 0 };
26
- VALUE errorMessage;
27
-
28
- FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
29
- NULL,
30
- errorCode,
31
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
32
- msgBuf,
33
- _countof(msgBuf),
34
- NULL);
35
- errorMessage = wstr_to_rb_str(CP_UTF8, msgBuf, -1);
36
-
37
- #pragma GCC diagnostic push
38
- #pragma GCC diagnostic ignored "-Wformat="
39
- #pragma GCC diagnostic ignored "-Wformat-extra-args"
40
- rb_raise(error, "ErrorCode: %lu\nError: %" PRIsVALUE "\n", errorCode, errorMessage);
41
- #pragma GCC diagnostic pop
42
- }
43
-
44
- VALUE
45
- render_to_rb_str(EVT_HANDLE handle, DWORD flags)
46
- {
47
- VALUE vbuffer;
48
- WCHAR* buffer;
49
- ULONG bufferSize = 0;
50
- ULONG bufferSizeUsed = 0;
51
- ULONG count;
52
- BOOL succeeded;
53
- VALUE result;
54
-
55
- if (flags != EvtRenderEventXml && flags != EvtRenderBookmark) {
56
- return Qnil;
57
- }
58
-
59
- // Get the size of the buffer
60
- EvtRender(nullptr, handle, flags, 0, NULL, &bufferSize, &count);
61
-
62
- // bufferSize is in bytes, not characters
63
- buffer = (WCHAR*)ALLOCV(vbuffer, bufferSize);
64
-
65
- succeeded =
66
- EvtRender(nullptr, handle, flags, bufferSize, buffer, &bufferSizeUsed, &count);
67
- if (!succeeded) {
68
- DWORD status = GetLastError();
69
- ALLOCV_END(vbuffer);
70
- raise_system_error(rb_eWinevtQueryError, status);
71
- }
72
-
73
- result = wstr_to_rb_str(CP_UTF8, buffer, -1);
74
- ALLOCV_END(vbuffer);
75
-
76
- return result;
77
- }
78
-
79
- static std::wstring
80
- guid_to_wstr(const GUID& guid)
81
- {
82
- LPOLESTR p = nullptr;
83
- if (FAILED(StringFromCLSID(guid, &p))) {
84
- return nullptr;
85
- }
86
- std::wstring s(p);
87
- CoTaskMemFree(p);
88
- return s;
89
- }
90
-
91
- static VALUE
92
- extract_user_evt_variants(PEVT_VARIANT pRenderedValues, DWORD propCount)
93
- {
94
- VALUE userValues = rb_ary_new();
95
- VALUE rbObj;
96
-
97
- for (DWORD i = 0; i < propCount; i++) {
98
- switch (pRenderedValues[i].Type) {
99
- case EvtVarTypeNull:
100
- rb_ary_push(userValues, Qnil);
101
- break;
102
- case EvtVarTypeString:
103
- if (pRenderedValues[i].StringVal == nullptr) {
104
- rb_ary_push(userValues, rb_utf8_str_new_cstr("(NULL)"));
105
- } else {
106
- std::wstring wStr(pRenderedValues[i].StringVal);
107
- rbObj = wstr_to_rb_str(CP_UTF8, &wStr[0], -1);
108
- rb_ary_push(userValues, rbObj);
109
- }
110
- break;
111
- case EvtVarTypeAnsiString:
112
- if (pRenderedValues[i].AnsiStringVal == nullptr) {
113
- rb_ary_push(userValues, rb_utf8_str_new_cstr("(NULL)"));
114
- } else {
115
- rb_ary_push(
116
- userValues,
117
- rb_utf8_str_new_cstr(const_cast<char*>(pRenderedValues[i].AnsiStringVal)));
118
- }
119
- break;
120
- case EvtVarTypeSByte:
121
- rbObj = INT2NUM(static_cast<UINT32>(pRenderedValues[i].SByteVal));
122
- rb_ary_push(userValues, rbObj);
123
- break;
124
- case EvtVarTypeByte:
125
- rbObj = INT2NUM(static_cast<UINT32>(pRenderedValues[i].ByteVal));
126
- rb_ary_push(userValues, rbObj);
127
- break;
128
- case EvtVarTypeInt16:
129
- rbObj = INT2NUM(static_cast<INT32>(pRenderedValues[i].Int16Val));
130
- rb_ary_push(userValues, rbObj);
131
- break;
132
- case EvtVarTypeUInt16:
133
- rbObj = UINT2NUM(static_cast<UINT32>(pRenderedValues[i].UInt16Val));
134
- rb_ary_push(userValues, rbObj);
135
- break;
136
- case EvtVarTypeInt32:
137
- rbObj = INT2NUM(pRenderedValues[i].Int32Val);
138
- rb_ary_push(userValues, rbObj);
139
- break;
140
- case EvtVarTypeUInt32:
141
- rbObj = UINT2NUM(pRenderedValues[i].UInt32Val);
142
- rb_ary_push(userValues, rbObj);
143
- break;
144
- case EvtVarTypeInt64:
145
- rbObj = LONG2NUM(pRenderedValues[i].Int64Val);
146
- rb_ary_push(userValues, rbObj);
147
- break;
148
- case EvtVarTypeUInt64:
149
- rbObj = ULONG2NUM(pRenderedValues[i].UInt64Val);
150
- rb_ary_push(userValues, rbObj);
151
- break;
152
- case EvtVarTypeSingle: {
153
- CHAR sResult[256];
154
- _snprintf_s(
155
- sResult, _countof(sResult), _TRUNCATE, "%f", pRenderedValues[i].SingleVal);
156
- rb_ary_push(userValues, rb_utf8_str_new_cstr(sResult));
157
- break;
158
- }
159
- case EvtVarTypeDouble: {
160
- CHAR sResult[256];
161
- _snprintf_s(
162
- sResult, _countof(sResult), _TRUNCATE, "%lf", pRenderedValues[i].DoubleVal);
163
- rb_ary_push(userValues, rb_utf8_str_new_cstr(sResult));
164
- break;
165
- }
166
- case EvtVarTypeBoolean:
167
- rbObj = pRenderedValues[i].BooleanVal ? Qtrue : Qfalse;
168
- rb_ary_push(userValues, rbObj);
169
- break;
170
- case EvtVarTypeGuid:
171
- if (pRenderedValues[i].GuidVal != nullptr) {
172
- const GUID guid = *pRenderedValues[i].GuidVal;
173
- std::wstring wstr = guid_to_wstr(guid);
174
- rbObj = wstr_to_rb_str(CP_UTF8, wstr.c_str(), -1);
175
- rb_ary_push(userValues, rbObj);
176
- } else {
177
- rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
178
- }
179
- break;
180
- case EvtVarTypeSizeT:
181
- rbObj = SIZET2NUM(pRenderedValues[i].SizeTVal);
182
- rb_ary_push(userValues, rbObj);
183
- break;
184
- case EvtVarTypeFileTime: {
185
- LARGE_INTEGER timestamp;
186
- CHAR strTime[128];
187
- FILETIME ft;
188
- SYSTEMTIME st;
189
- timestamp.QuadPart = pRenderedValues[i].FileTimeVal;
190
- ft.dwHighDateTime = timestamp.HighPart;
191
- ft.dwLowDateTime = timestamp.LowPart;
192
- if (FileTimeToSystemTime(&ft, &st)) {
193
- _snprintf_s(strTime,
194
- _countof(strTime),
195
- _TRUNCATE,
196
- "%04d-%02d-%02d %02d:%02d:%02d.%dZ",
197
- st.wYear,
198
- st.wMonth,
199
- st.wDay,
200
- st.wHour,
201
- st.wMinute,
202
- st.wSecond,
203
- st.wMilliseconds);
204
- rb_ary_push(userValues, rb_utf8_str_new_cstr(strTime));
205
- } else {
206
- rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
207
- }
208
- break;
209
- }
210
- case EvtVarTypeSysTime: {
211
- CHAR strTime[128];
212
- SYSTEMTIME st;
213
- if (pRenderedValues[i].SysTimeVal != nullptr) {
214
- st = *pRenderedValues[i].SysTimeVal;
215
- _snprintf_s(strTime,
216
- _countof(strTime),
217
- _TRUNCATE,
218
- "%04d-%02d-%02d %02d:%02d:%02d.%dZ",
219
- st.wYear,
220
- st.wMonth,
221
- st.wDay,
222
- st.wHour,
223
- st.wMinute,
224
- st.wSecond,
225
- st.wMilliseconds);
226
- rb_ary_push(userValues, rb_utf8_str_new_cstr(strTime));
227
- } else {
228
- rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
229
- }
230
- break;
231
- }
232
- case EvtVarTypeSid: {
233
- WCHAR* tmpWChar = nullptr;
234
- if (ConvertSidToStringSidW(pRenderedValues[i].SidVal, &tmpWChar)) {
235
- rbObj = wstr_to_rb_str(CP_UTF8, tmpWChar, -1);
236
- rb_ary_push(userValues, rbObj);
237
- LocalFree(tmpWChar);
238
- } else {
239
- rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
240
- }
241
- break;
242
- }
243
- case EvtVarTypeHexInt32:
244
- rbObj = rb_sprintf("%#x", pRenderedValues[i].UInt32Val);
245
- rb_ary_push(userValues, rbObj);
246
- break;
247
- case EvtVarTypeHexInt64:
248
- rbObj = rb_sprintf("%#I64x", pRenderedValues[i].UInt64Val);
249
- rb_ary_push(userValues, rbObj);
250
- break;
251
- case EvtVarTypeEvtXml:
252
- if (pRenderedValues[i].XmlVal == nullptr) {
253
- rb_ary_push(userValues, rb_utf8_str_new_cstr("(NULL)"));
254
- } else {
255
- rbObj = wstr_to_rb_str(CP_UTF8, pRenderedValues[i].XmlVal, -1);
256
- rb_ary_push(userValues, rbObj);
257
- }
258
- break;
259
- default:
260
- rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
261
- break;
262
- }
263
- }
264
-
265
- return userValues;
266
- }
267
-
268
- VALUE
269
- get_values(EVT_HANDLE handle)
270
- {
271
- VALUE vbuffer;
272
- PEVT_VARIANT pRenderedValues;
273
- ULONG bufferSize = 0;
274
- ULONG bufferSizeUsed = 0;
275
- DWORD propCount = 0;
276
- BOOL succeeded;
277
- VALUE userValues = Qnil;
278
-
279
- EVT_HANDLE renderContext = EvtCreateRenderContext(0, nullptr, EvtRenderContextUser);
280
- if (renderContext == nullptr) {
281
- rb_raise(rb_eWinevtQueryError, "Failed to create renderContext");
282
- }
283
-
284
- // Get the size of the buffer
285
- EvtRender(
286
- renderContext, handle, EvtRenderEventValues, 0, NULL, &bufferSize, &propCount);
287
-
288
- // bufferSize is in bytes, not array size
289
- pRenderedValues = (PEVT_VARIANT)ALLOCV(vbuffer, bufferSize);
290
-
291
- succeeded = EvtRender(renderContext,
292
- handle,
293
- EvtRenderEventValues,
294
- bufferSize,
295
- pRenderedValues,
296
- &bufferSizeUsed,
297
- &propCount);
298
- if (!succeeded) {
299
- DWORD status = GetLastError();
300
- ALLOCV_END(vbuffer);
301
- EvtClose(renderContext);
302
- raise_system_error(rb_eWinevtQueryError, status);
303
- }
304
-
305
- userValues = extract_user_evt_variants(pRenderedValues, propCount);
306
-
307
- ALLOCV_END(vbuffer);
308
- EvtClose(renderContext);
309
-
310
- return userValues;
311
- }
312
-
313
- static std::vector<WCHAR>
314
- get_message(EVT_HANDLE hMetadata, EVT_HANDLE handle)
315
- {
316
- #define BUFSIZE 4096
317
- std::vector<WCHAR> result;
318
- ULONG status;
319
- ULONG bufferSizeNeeded = 0;
320
- LPVOID lpMsgBuf;
321
- std::vector<WCHAR> message(BUFSIZE);
322
-
323
- if (!EvtFormatMessage(hMetadata,
324
- handle,
325
- 0xffffffff,
326
- 0,
327
- nullptr,
328
- EvtFormatMessageEvent,
329
- message.size(),
330
- &message[0],
331
- &bufferSizeNeeded)) {
332
- status = GetLastError();
333
-
334
- if (status != ERROR_EVT_UNRESOLVED_VALUE_INSERT) {
335
- switch (status) {
336
- case ERROR_EVT_MESSAGE_NOT_FOUND:
337
- case ERROR_EVT_MESSAGE_ID_NOT_FOUND:
338
- case ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND:
339
- case ERROR_RESOURCE_LANG_NOT_FOUND:
340
- case ERROR_MUI_FILE_NOT_FOUND:
341
- case ERROR_EVT_UNRESOLVED_PARAMETER_INSERT: {
342
- if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
343
- FORMAT_MESSAGE_IGNORE_INSERTS,
344
- nullptr,
345
- status,
346
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
347
- reinterpret_cast<WCHAR*>(&lpMsgBuf),
348
- 0,
349
- nullptr) == 0)
350
- FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
351
- FORMAT_MESSAGE_IGNORE_INSERTS,
352
- nullptr,
353
- status,
354
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
355
- reinterpret_cast<WCHAR*>(&lpMsgBuf),
356
- 0,
357
- nullptr);
358
-
359
- std::wstring ret(reinterpret_cast<WCHAR*>(lpMsgBuf));
360
- std::copy(ret.begin(), ret.end(), std::back_inserter(result));
361
- LocalFree(lpMsgBuf);
362
-
363
- goto cleanup;
364
- }
365
- }
366
-
367
- if (status != ERROR_INSUFFICIENT_BUFFER)
368
- rb_raise(rb_eWinevtQueryError, "ErrorCode: %lu", status);
369
- }
370
-
371
- if (status == ERROR_INSUFFICIENT_BUFFER) {
372
- message.resize(bufferSizeNeeded);
373
- message.shrink_to_fit();
374
-
375
- if (!EvtFormatMessage(hMetadata,
376
- handle,
377
- 0xffffffff,
378
- 0,
379
- nullptr,
380
- EvtFormatMessageEvent,
381
- message.size(),
382
- &message.front(),
383
- &bufferSizeNeeded)) {
384
- status = GetLastError();
385
-
386
- if (status != ERROR_EVT_UNRESOLVED_VALUE_INSERT) {
387
- switch (status) {
388
- case ERROR_EVT_MESSAGE_NOT_FOUND:
389
- case ERROR_EVT_MESSAGE_ID_NOT_FOUND:
390
- case ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND:
391
- case ERROR_RESOURCE_LANG_NOT_FOUND:
392
- case ERROR_MUI_FILE_NOT_FOUND:
393
- case ERROR_EVT_UNRESOLVED_PARAMETER_INSERT:
394
- if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
395
- FORMAT_MESSAGE_FROM_SYSTEM |
396
- FORMAT_MESSAGE_IGNORE_INSERTS,
397
- nullptr,
398
- status,
399
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
400
- reinterpret_cast<WCHAR*>(&lpMsgBuf),
401
- 0,
402
- nullptr) == 0)
403
- FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
404
- FORMAT_MESSAGE_FROM_SYSTEM |
405
- FORMAT_MESSAGE_IGNORE_INSERTS,
406
- nullptr,
407
- status,
408
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
409
- reinterpret_cast<WCHAR*>(&lpMsgBuf),
410
- 0,
411
- nullptr);
412
-
413
- std::wstring ret(reinterpret_cast<WCHAR*>(lpMsgBuf));
414
- std::copy(ret.begin(), ret.end(), std::back_inserter(result));
415
- LocalFree(lpMsgBuf);
416
-
417
- goto cleanup;
418
- }
419
-
420
- rb_raise(rb_eWinevtQueryError, "ErrorCode: %lu", status);
421
- }
422
- }
423
- }
424
- }
425
-
426
- result = message;
427
-
428
- cleanup:
429
-
430
- return result;
431
-
432
- #undef BUFSIZE
433
- }
434
-
435
- WCHAR*
436
- get_description(EVT_HANDLE handle, LANGID langID)
437
- {
438
- #define BUFSIZE 4096
439
- std::vector<WCHAR> buffer(BUFSIZE);
440
- ULONG bufferSizeNeeded = 0;
441
- ULONG status, count;
442
- std::vector<WCHAR> result;
443
- EVT_HANDLE hMetadata = nullptr;
444
-
445
- static PCWSTR eventProperties[] = { L"Event/System/Provider/@Name" };
446
- EVT_HANDLE renderContext =
447
- EvtCreateRenderContext(1, eventProperties, EvtRenderContextValues);
448
- if (renderContext == nullptr) {
449
- rb_raise(rb_eWinevtQueryError, "Failed to create renderContext");
450
- }
451
-
452
- if (EvtRender(renderContext,
453
- handle,
454
- EvtRenderEventValues,
455
- buffer.size(),
456
- &buffer.front(),
457
- &bufferSizeNeeded,
458
- &count) != FALSE) {
459
- status = ERROR_SUCCESS;
460
- } else {
461
- status = GetLastError();
462
- }
463
-
464
- if (status != ERROR_SUCCESS) {
465
- raise_system_error(rb_eWinevtQueryError, status);
466
- }
467
-
468
- // Obtain buffer as EVT_VARIANT pointer. To avoid ErrorCide 87 in EvtRender.
469
- const PEVT_VARIANT values = reinterpret_cast<PEVT_VARIANT>(&buffer.front());
470
-
471
- // Open publisher metadata
472
- hMetadata = EvtOpenPublisherMetadata(
473
- nullptr,
474
- values[0].StringVal,
475
- nullptr,
476
- MAKELCID(langID, SORT_DEFAULT),
477
- 0);
478
- if (hMetadata == nullptr) {
479
- // When winevt_c cannot open metadata, then give up to obtain
480
- // message file and clean up immediately.
481
- goto cleanup;
482
- }
483
-
484
- result = get_message(hMetadata, handle);
485
-
486
- #undef BUFSIZE
487
-
488
- cleanup:
489
-
490
- if (renderContext)
491
- EvtClose(renderContext);
492
-
493
- if (hMetadata)
494
- EvtClose(hMetadata);
495
-
496
- return _wcsdup(result.data());
497
- }
498
-
499
- VALUE
500
- render_system_event(EVT_HANDLE hEvent, BOOL preserve_qualifiers)
501
- {
502
- DWORD status = ERROR_SUCCESS;
503
- EVT_HANDLE hContext = NULL;
504
- DWORD dwBufferSize = 0;
505
- DWORD dwBufferUsed = 0;
506
- DWORD dwPropertyCount = 0;
507
- VALUE vRenderedValues;
508
- PEVT_VARIANT pRenderedValues = NULL;
509
- WCHAR wsGuid[50];
510
- LPSTR pwsSid = NULL;
511
- ULONGLONG ullTimeStamp = 0;
512
- ULONGLONG ullNanoseconds = 0;
513
- SYSTEMTIME st;
514
- FILETIME ft;
515
- CHAR buffer[32];
516
- VALUE rbstr;
517
- DWORD EventID;
518
- VALUE hash = rb_hash_new();
519
-
520
- hContext = EvtCreateRenderContext(0, NULL, EvtRenderContextSystem);
521
- if (NULL == hContext) {
522
- rb_raise(
523
- rb_eWinevtQueryError, "Failed to create renderContext with %lu\n", GetLastError());
524
- }
525
-
526
- if (!EvtRender(hContext,
527
- hEvent,
528
- EvtRenderEventValues,
529
- dwBufferSize,
530
- pRenderedValues,
531
- &dwBufferUsed,
532
- &dwPropertyCount)) {
533
- status = GetLastError();
534
- if (ERROR_INSUFFICIENT_BUFFER == status) {
535
- dwBufferSize = dwBufferUsed;
536
- pRenderedValues = (PEVT_VARIANT)ALLOCV(vRenderedValues, dwBufferSize);
537
- if (pRenderedValues) {
538
- EvtRender(hContext,
539
- hEvent,
540
- EvtRenderEventValues,
541
- dwBufferSize,
542
- pRenderedValues,
543
- &dwBufferUsed,
544
- &dwPropertyCount);
545
- } else {
546
- EvtClose(hContext);
547
- rb_raise(rb_eRuntimeError, "Failed to malloc memory with %lu\n", status);
548
- }
549
- }
550
-
551
- status = GetLastError();
552
- if (ERROR_SUCCESS != status) {
553
- EvtClose(hContext);
554
- ALLOCV_END(vRenderedValues);
555
-
556
- rb_raise(rb_eWinevtQueryError, "EvtRender failed with %lu\n", status);
557
- }
558
- }
559
-
560
- // EVT_VARIANT value with EvtRenderContextSystem will be decomposed
561
- // as the following enum definition:
562
- // https://docs.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_system_property_id
563
- rbstr = wstr_to_rb_str(CP_UTF8, pRenderedValues[EvtSystemProviderName].StringVal, -1);
564
- rb_hash_aset(hash, rb_str_new2("ProviderName"), rbstr);
565
- if (NULL != pRenderedValues[EvtSystemProviderGuid].GuidVal) {
566
- const GUID* Guid = pRenderedValues[EvtSystemProviderGuid].GuidVal;
567
- StringFromGUID2(*Guid, wsGuid, _countof(wsGuid));
568
- rbstr = wstr_to_rb_str(CP_UTF8, wsGuid, -1);
569
- rb_hash_aset(hash, rb_str_new2("ProviderGuid"), rbstr);
570
- } else {
571
- rb_hash_aset(hash, rb_str_new2("ProviderGuid"), Qnil);
572
- }
573
-
574
- EventID = pRenderedValues[EvtSystemEventID].UInt16Val;
575
- if (preserve_qualifiers) {
576
- if (EvtVarTypeNull != pRenderedValues[EvtSystemQualifiers].Type) {
577
- rb_hash_aset(hash, rb_str_new2("Qualifiers"),
578
- INT2NUM(pRenderedValues[EvtSystemQualifiers].UInt16Val));
579
- } else {
580
- rb_hash_aset(hash, rb_str_new2("Qualifiers"), rb_str_new2(""));
581
- }
582
-
583
- rb_hash_aset(hash, rb_str_new2("EventID"), INT2NUM(EventID));
584
- } else {
585
- if (EvtVarTypeNull != pRenderedValues[EvtSystemQualifiers].Type) {
586
- EventID = MAKELONG(pRenderedValues[EvtSystemEventID].UInt16Val,
587
- pRenderedValues[EvtSystemQualifiers].UInt16Val);
588
- }
589
-
590
- rb_hash_aset(hash, rb_str_new2("EventID"), ULONG2NUM(EventID));
591
- }
592
-
593
- rb_hash_aset(hash,
594
- rb_str_new2("Version"),
595
- (EvtVarTypeNull == pRenderedValues[EvtSystemVersion].Type)
596
- ? INT2NUM(0)
597
- : INT2NUM(pRenderedValues[EvtSystemVersion].ByteVal));
598
- rb_hash_aset(hash,
599
- rb_str_new2("Level"),
600
- (EvtVarTypeNull == pRenderedValues[EvtSystemLevel].Type)
601
- ? INT2NUM(0)
602
- : INT2NUM(pRenderedValues[EvtSystemLevel].ByteVal));
603
- rb_hash_aset(hash,
604
- rb_str_new2("Task"),
605
- (EvtVarTypeNull == pRenderedValues[EvtSystemTask].Type)
606
- ? INT2NUM(0)
607
- : INT2NUM(pRenderedValues[EvtSystemTask].UInt16Val));
608
- rb_hash_aset(hash,
609
- rb_str_new2("Opcode"),
610
- (EvtVarTypeNull == pRenderedValues[EvtSystemOpcode].Type)
611
- ? INT2NUM(0)
612
- : INT2NUM(pRenderedValues[EvtSystemOpcode].ByteVal));
613
- _snprintf_s(buffer,
614
- _countof(buffer),
615
- _TRUNCATE,
616
- "0x%llx",
617
- pRenderedValues[EvtSystemKeywords].UInt64Val);
618
- rb_hash_aset(hash,
619
- rb_str_new2("Keywords"),
620
- (EvtVarTypeNull == pRenderedValues[EvtSystemKeywords].Type)
621
- ? Qnil
622
- : rb_str_new2(buffer));
623
-
624
- ullTimeStamp = pRenderedValues[EvtSystemTimeCreated].FileTimeVal;
625
- ft.dwHighDateTime = (DWORD)((ullTimeStamp >> 32) & 0xFFFFFFFF);
626
- ft.dwLowDateTime = (DWORD)(ullTimeStamp & 0xFFFFFFFF);
627
-
628
- FileTimeToSystemTime(&ft, &st);
629
- ullNanoseconds =
630
- (ullTimeStamp % 10000000) *
631
- 100; // Display nanoseconds instead of milliseconds for higher resolution
632
- _snprintf_s(buffer,
633
- _countof(buffer),
634
- _TRUNCATE,
635
- "%02d/%02d/%02d %02d:%02d:%02d.%llu",
636
- st.wYear,
637
- st.wMonth,
638
- st.wDay,
639
- st.wHour,
640
- st.wMinute,
641
- st.wSecond,
642
- ullNanoseconds);
643
- rb_hash_aset(hash,
644
- rb_str_new2("TimeCreated"),
645
- (EvtVarTypeNull == pRenderedValues[EvtSystemKeywords].Type)
646
- ? Qnil
647
- : rb_str_new2(buffer));
648
- _snprintf_s(buffer,
649
- _countof(buffer),
650
- _TRUNCATE,
651
- "%llu",
652
- pRenderedValues[EvtSystemEventRecordId].UInt64Val);
653
- rb_hash_aset(hash,
654
- rb_str_new2("EventRecordID"),
655
- (EvtVarTypeNull == pRenderedValues[EvtSystemEventRecordId].UInt64Val)
656
- ? Qnil
657
- : rb_str_new2(buffer));
658
-
659
- if (EvtVarTypeNull != pRenderedValues[EvtSystemActivityID].Type) {
660
- const GUID* Guid = pRenderedValues[EvtSystemActivityID].GuidVal;
661
- StringFromGUID2(*Guid, wsGuid, _countof(wsGuid));
662
- rbstr = wstr_to_rb_str(CP_UTF8, wsGuid, -1);
663
- rb_hash_aset(hash, rb_str_new2("ActivityID"), rbstr);
664
- }
665
-
666
- if (EvtVarTypeNull != pRenderedValues[EvtSystemRelatedActivityID].Type) {
667
- const GUID* Guid = pRenderedValues[EvtSystemRelatedActivityID].GuidVal;
668
- StringFromGUID2(*Guid, wsGuid, _countof(wsGuid));
669
- rbstr = wstr_to_rb_str(CP_UTF8, wsGuid, -1);
670
- rb_hash_aset(hash, rb_str_new2("RelatedActivityID"), rbstr);
671
- }
672
-
673
- rb_hash_aset(hash,
674
- rb_str_new2("ProcessID"),
675
- UINT2NUM(pRenderedValues[EvtSystemProcessID].UInt32Val));
676
- rb_hash_aset(hash,
677
- rb_str_new2("ThreadID"),
678
- UINT2NUM(pRenderedValues[EvtSystemThreadID].UInt32Val));
679
- rbstr = wstr_to_rb_str(CP_UTF8, pRenderedValues[EvtSystemChannel].StringVal, -1);
680
- rb_hash_aset(hash, rb_str_new2("Channel"), rbstr);
681
- rbstr = wstr_to_rb_str(CP_UTF8, pRenderedValues[EvtSystemComputer].StringVal, -1);
682
- rb_hash_aset(hash, rb_str_new2("Computer"), rbstr);
683
-
684
- if (EvtVarTypeNull != pRenderedValues[EvtSystemUserID].Type) {
685
- if (ConvertSidToStringSid(pRenderedValues[EvtSystemUserID].SidVal, &pwsSid)) {
686
- rbstr = rb_utf8_str_new_cstr(pwsSid);
687
- rb_hash_aset(hash, rb_str_new2("UserID"), rbstr);
688
- LocalFree(pwsSid);
689
- }
690
- }
691
-
692
- EvtClose(hContext);
693
- ALLOCV_END(vRenderedValues);
694
-
695
- return hash;
696
- }
1
+ #include <winevt_c.h>
2
+
3
+ #include <sddl.h>
4
+ #include <stdlib.h>
5
+ #include <string>
6
+ #include <vector>
7
+
8
+ VALUE
9
+ wstr_to_rb_str(UINT cp, const WCHAR* wstr, int clen)
10
+ {
11
+ VALUE vstr;
12
+ CHAR* ptr;
13
+ int len = WideCharToMultiByte(cp, 0, wstr, clen, nullptr, 0, nullptr, nullptr);
14
+ ptr = ALLOCV_N(CHAR, vstr, len);
15
+ WideCharToMultiByte(cp, 0, wstr, clen, ptr, len, nullptr, nullptr);
16
+ VALUE str = rb_utf8_str_new_cstr(ptr);
17
+ ALLOCV_END(vstr);
18
+
19
+ return str;
20
+ }
21
+
22
+ void
23
+ raise_system_error(VALUE error, DWORD errorCode)
24
+ {
25
+ WCHAR msgBuf[256] = { 0 };
26
+ VALUE errorMessage;
27
+
28
+ FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
29
+ NULL,
30
+ errorCode,
31
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
32
+ msgBuf,
33
+ _countof(msgBuf),
34
+ NULL);
35
+ errorMessage = wstr_to_rb_str(CP_UTF8, msgBuf, -1);
36
+
37
+ #pragma GCC diagnostic push
38
+ #pragma GCC diagnostic ignored "-Wformat="
39
+ #pragma GCC diagnostic ignored "-Wformat-extra-args"
40
+ rb_raise(error, "ErrorCode: %lu\nError: %" PRIsVALUE "\n", errorCode, errorMessage);
41
+ #pragma GCC diagnostic pop
42
+ }
43
+
44
+ VALUE
45
+ render_to_rb_str(EVT_HANDLE handle, DWORD flags)
46
+ {
47
+ VALUE vbuffer;
48
+ WCHAR* buffer;
49
+ ULONG bufferSize = 0;
50
+ ULONG bufferSizeUsed = 0;
51
+ ULONG count;
52
+ BOOL succeeded;
53
+ VALUE result;
54
+
55
+ if (flags != EvtRenderEventXml && flags != EvtRenderBookmark) {
56
+ return Qnil;
57
+ }
58
+
59
+ // Get the size of the buffer
60
+ EvtRender(nullptr, handle, flags, 0, NULL, &bufferSize, &count);
61
+
62
+ // bufferSize is in bytes, not characters
63
+ buffer = (WCHAR*)ALLOCV(vbuffer, bufferSize);
64
+
65
+ succeeded =
66
+ EvtRender(nullptr, handle, flags, bufferSize, buffer, &bufferSizeUsed, &count);
67
+ if (!succeeded) {
68
+ DWORD status = GetLastError();
69
+ ALLOCV_END(vbuffer);
70
+ raise_system_error(rb_eWinevtQueryError, status);
71
+ }
72
+
73
+ result = wstr_to_rb_str(CP_UTF8, buffer, -1);
74
+ ALLOCV_END(vbuffer);
75
+
76
+ return result;
77
+ }
78
+
79
+ EVT_HANDLE
80
+ connect_to_remote(LPWSTR computerName, LPWSTR domain, LPWSTR username, LPWSTR password,
81
+ EVT_RPC_LOGIN_FLAGS flags, DWORD *error_code)
82
+ {
83
+ EVT_HANDLE hRemote = NULL;
84
+ EVT_RPC_LOGIN Credentials;
85
+
86
+ RtlZeroMemory(&Credentials, sizeof(EVT_RPC_LOGIN));
87
+
88
+ Credentials.Server = computerName;
89
+ Credentials.Domain = domain;
90
+ Credentials.User = username;
91
+ Credentials.Password = password;
92
+ Credentials.Flags = flags;
93
+
94
+ hRemote = EvtOpenSession(EvtRpcLogin, &Credentials, 0, 0);
95
+ if (!hRemote) {
96
+ *error_code = GetLastError();
97
+ return hRemote;
98
+ }
99
+
100
+ SecureZeroMemory(&Credentials, sizeof(EVT_RPC_LOGIN));
101
+
102
+ return hRemote;
103
+ }
104
+
105
+ static std::wstring
106
+ guid_to_wstr(const GUID& guid)
107
+ {
108
+ LPOLESTR p = nullptr;
109
+ if (FAILED(StringFromCLSID(guid, &p))) {
110
+ return nullptr;
111
+ }
112
+ std::wstring s(p);
113
+ CoTaskMemFree(p);
114
+ return s;
115
+ }
116
+
117
+ static VALUE
118
+ extract_user_evt_variants(PEVT_VARIANT pRenderedValues, DWORD propCount)
119
+ {
120
+ VALUE userValues = rb_ary_new();
121
+ VALUE rbObj;
122
+
123
+ for (DWORD i = 0; i < propCount; i++) {
124
+ switch (pRenderedValues[i].Type) {
125
+ case EvtVarTypeNull:
126
+ rb_ary_push(userValues, Qnil);
127
+ break;
128
+ case EvtVarTypeString:
129
+ if (pRenderedValues[i].StringVal == nullptr) {
130
+ rb_ary_push(userValues, rb_utf8_str_new_cstr("(NULL)"));
131
+ } else {
132
+ std::wstring wStr(pRenderedValues[i].StringVal);
133
+ rbObj = wstr_to_rb_str(CP_UTF8, &wStr[0], -1);
134
+ rb_ary_push(userValues, rbObj);
135
+ }
136
+ break;
137
+ case EvtVarTypeAnsiString:
138
+ if (pRenderedValues[i].AnsiStringVal == nullptr) {
139
+ rb_ary_push(userValues, rb_utf8_str_new_cstr("(NULL)"));
140
+ } else {
141
+ rb_ary_push(
142
+ userValues,
143
+ rb_utf8_str_new_cstr(const_cast<char*>(pRenderedValues[i].AnsiStringVal)));
144
+ }
145
+ break;
146
+ case EvtVarTypeSByte:
147
+ rbObj = INT2NUM(static_cast<UINT32>(pRenderedValues[i].SByteVal));
148
+ rb_ary_push(userValues, rbObj);
149
+ break;
150
+ case EvtVarTypeByte:
151
+ rbObj = INT2NUM(static_cast<UINT32>(pRenderedValues[i].ByteVal));
152
+ rb_ary_push(userValues, rbObj);
153
+ break;
154
+ case EvtVarTypeInt16:
155
+ rbObj = INT2NUM(static_cast<INT32>(pRenderedValues[i].Int16Val));
156
+ rb_ary_push(userValues, rbObj);
157
+ break;
158
+ case EvtVarTypeUInt16:
159
+ rbObj = UINT2NUM(static_cast<UINT32>(pRenderedValues[i].UInt16Val));
160
+ rb_ary_push(userValues, rbObj);
161
+ break;
162
+ case EvtVarTypeInt32:
163
+ rbObj = INT2NUM(pRenderedValues[i].Int32Val);
164
+ rb_ary_push(userValues, rbObj);
165
+ break;
166
+ case EvtVarTypeUInt32:
167
+ rbObj = UINT2NUM(pRenderedValues[i].UInt32Val);
168
+ rb_ary_push(userValues, rbObj);
169
+ break;
170
+ case EvtVarTypeInt64:
171
+ rbObj = LONG2NUM(pRenderedValues[i].Int64Val);
172
+ rb_ary_push(userValues, rbObj);
173
+ break;
174
+ case EvtVarTypeUInt64:
175
+ rbObj = ULONG2NUM(pRenderedValues[i].UInt64Val);
176
+ rb_ary_push(userValues, rbObj);
177
+ break;
178
+ case EvtVarTypeSingle: {
179
+ CHAR sResult[256];
180
+ _snprintf_s(
181
+ sResult, _countof(sResult), _TRUNCATE, "%f", pRenderedValues[i].SingleVal);
182
+ rb_ary_push(userValues, rb_utf8_str_new_cstr(sResult));
183
+ break;
184
+ }
185
+ case EvtVarTypeDouble: {
186
+ CHAR sResult[256];
187
+ _snprintf_s(
188
+ sResult, _countof(sResult), _TRUNCATE, "%lf", pRenderedValues[i].DoubleVal);
189
+ rb_ary_push(userValues, rb_utf8_str_new_cstr(sResult));
190
+ break;
191
+ }
192
+ case EvtVarTypeBoolean:
193
+ rbObj = pRenderedValues[i].BooleanVal ? Qtrue : Qfalse;
194
+ rb_ary_push(userValues, rbObj);
195
+ break;
196
+ case EvtVarTypeGuid:
197
+ if (pRenderedValues[i].GuidVal != nullptr) {
198
+ const GUID guid = *pRenderedValues[i].GuidVal;
199
+ std::wstring wstr = guid_to_wstr(guid);
200
+ rbObj = wstr_to_rb_str(CP_UTF8, wstr.c_str(), -1);
201
+ rb_ary_push(userValues, rbObj);
202
+ } else {
203
+ rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
204
+ }
205
+ break;
206
+ case EvtVarTypeSizeT:
207
+ rbObj = SIZET2NUM(pRenderedValues[i].SizeTVal);
208
+ rb_ary_push(userValues, rbObj);
209
+ break;
210
+ case EvtVarTypeFileTime: {
211
+ LARGE_INTEGER timestamp;
212
+ CHAR strTime[128];
213
+ FILETIME ft;
214
+ SYSTEMTIME st;
215
+ timestamp.QuadPart = pRenderedValues[i].FileTimeVal;
216
+ ft.dwHighDateTime = timestamp.HighPart;
217
+ ft.dwLowDateTime = timestamp.LowPart;
218
+ if (FileTimeToSystemTime(&ft, &st)) {
219
+ _snprintf_s(strTime,
220
+ _countof(strTime),
221
+ _TRUNCATE,
222
+ "%04d-%02d-%02d %02d:%02d:%02d.%dZ",
223
+ st.wYear,
224
+ st.wMonth,
225
+ st.wDay,
226
+ st.wHour,
227
+ st.wMinute,
228
+ st.wSecond,
229
+ st.wMilliseconds);
230
+ rb_ary_push(userValues, rb_utf8_str_new_cstr(strTime));
231
+ } else {
232
+ rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
233
+ }
234
+ break;
235
+ }
236
+ case EvtVarTypeSysTime: {
237
+ CHAR strTime[128];
238
+ SYSTEMTIME st;
239
+ if (pRenderedValues[i].SysTimeVal != nullptr) {
240
+ st = *pRenderedValues[i].SysTimeVal;
241
+ _snprintf_s(strTime,
242
+ _countof(strTime),
243
+ _TRUNCATE,
244
+ "%04d-%02d-%02d %02d:%02d:%02d.%dZ",
245
+ st.wYear,
246
+ st.wMonth,
247
+ st.wDay,
248
+ st.wHour,
249
+ st.wMinute,
250
+ st.wSecond,
251
+ st.wMilliseconds);
252
+ rb_ary_push(userValues, rb_utf8_str_new_cstr(strTime));
253
+ } else {
254
+ rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
255
+ }
256
+ break;
257
+ }
258
+ case EvtVarTypeSid: {
259
+ WCHAR* tmpWChar = nullptr;
260
+ if (ConvertSidToStringSidW(pRenderedValues[i].SidVal, &tmpWChar)) {
261
+ rbObj = wstr_to_rb_str(CP_UTF8, tmpWChar, -1);
262
+ rb_ary_push(userValues, rbObj);
263
+ LocalFree(tmpWChar);
264
+ } else {
265
+ rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
266
+ }
267
+ break;
268
+ }
269
+ case EvtVarTypeHexInt32:
270
+ rbObj = rb_sprintf("%#x", pRenderedValues[i].UInt32Val);
271
+ rb_ary_push(userValues, rbObj);
272
+ break;
273
+ case EvtVarTypeHexInt64:
274
+ uint32_t high;
275
+ uint32_t low;
276
+
277
+ high = pRenderedValues[i].UInt64Val >> 32;
278
+ low = pRenderedValues[i].UInt64Val & 0x00000000FFFFFFFF;
279
+ rbObj = rb_sprintf("0x%08x%08x", high, low);
280
+ rb_ary_push(userValues, rbObj);
281
+ break;
282
+ case EvtVarTypeEvtXml:
283
+ if (pRenderedValues[i].XmlVal == nullptr) {
284
+ rb_ary_push(userValues, rb_utf8_str_new_cstr("(NULL)"));
285
+ } else {
286
+ rbObj = wstr_to_rb_str(CP_UTF8, pRenderedValues[i].XmlVal, -1);
287
+ rb_ary_push(userValues, rbObj);
288
+ }
289
+ break;
290
+ default:
291
+ rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
292
+ break;
293
+ }
294
+ }
295
+
296
+ return userValues;
297
+ }
298
+
299
+ VALUE
300
+ get_values(EVT_HANDLE handle)
301
+ {
302
+ VALUE vbuffer;
303
+ PEVT_VARIANT pRenderedValues;
304
+ ULONG bufferSize = 0;
305
+ ULONG bufferSizeUsed = 0;
306
+ DWORD propCount = 0;
307
+ BOOL succeeded;
308
+ VALUE userValues = Qnil;
309
+
310
+ EVT_HANDLE renderContext = EvtCreateRenderContext(0, nullptr, EvtRenderContextUser);
311
+ if (renderContext == nullptr) {
312
+ rb_raise(rb_eWinevtQueryError, "Failed to create renderContext");
313
+ }
314
+
315
+ // Get the size of the buffer
316
+ EvtRender(
317
+ renderContext, handle, EvtRenderEventValues, 0, NULL, &bufferSize, &propCount);
318
+
319
+ // bufferSize is in bytes, not array size
320
+ pRenderedValues = (PEVT_VARIANT)ALLOCV(vbuffer, bufferSize);
321
+
322
+ succeeded = EvtRender(renderContext,
323
+ handle,
324
+ EvtRenderEventValues,
325
+ bufferSize,
326
+ pRenderedValues,
327
+ &bufferSizeUsed,
328
+ &propCount);
329
+ if (!succeeded) {
330
+ DWORD status = GetLastError();
331
+ ALLOCV_END(vbuffer);
332
+ EvtClose(renderContext);
333
+ raise_system_error(rb_eWinevtQueryError, status);
334
+ }
335
+
336
+ userValues = extract_user_evt_variants(pRenderedValues, propCount);
337
+
338
+ ALLOCV_END(vbuffer);
339
+ EvtClose(renderContext);
340
+
341
+ return userValues;
342
+ }
343
+
344
+ static std::vector<WCHAR>
345
+ get_message(EVT_HANDLE hMetadata, EVT_HANDLE handle)
346
+ {
347
+ #define BUFSIZE 4096
348
+ std::vector<WCHAR> result;
349
+ ULONG status;
350
+ ULONG bufferSizeNeeded = 0;
351
+ LPVOID lpMsgBuf;
352
+ std::vector<WCHAR> message(BUFSIZE);
353
+
354
+ if (!EvtFormatMessage(hMetadata,
355
+ handle,
356
+ 0xffffffff,
357
+ 0,
358
+ nullptr,
359
+ EvtFormatMessageEvent,
360
+ message.size(),
361
+ &message[0],
362
+ &bufferSizeNeeded)) {
363
+ status = GetLastError();
364
+
365
+ if (status != ERROR_EVT_UNRESOLVED_VALUE_INSERT) {
366
+ switch (status) {
367
+ case ERROR_EVT_MESSAGE_NOT_FOUND:
368
+ case ERROR_EVT_MESSAGE_ID_NOT_FOUND:
369
+ case ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND:
370
+ case ERROR_RESOURCE_LANG_NOT_FOUND:
371
+ case ERROR_MUI_FILE_NOT_FOUND:
372
+ case ERROR_EVT_UNRESOLVED_PARAMETER_INSERT: {
373
+ if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
374
+ FORMAT_MESSAGE_IGNORE_INSERTS,
375
+ nullptr,
376
+ status,
377
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
378
+ reinterpret_cast<WCHAR*>(&lpMsgBuf),
379
+ 0,
380
+ nullptr) == 0)
381
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
382
+ FORMAT_MESSAGE_IGNORE_INSERTS,
383
+ nullptr,
384
+ status,
385
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
386
+ reinterpret_cast<WCHAR*>(&lpMsgBuf),
387
+ 0,
388
+ nullptr);
389
+
390
+ std::wstring ret(reinterpret_cast<WCHAR*>(lpMsgBuf));
391
+ std::copy(ret.begin(), ret.end(), std::back_inserter(result));
392
+ LocalFree(lpMsgBuf);
393
+
394
+ goto cleanup;
395
+ }
396
+ }
397
+
398
+ if (status != ERROR_INSUFFICIENT_BUFFER)
399
+ rb_raise(rb_eWinevtQueryError, "ErrorCode: %lu", status);
400
+ }
401
+
402
+ if (status == ERROR_INSUFFICIENT_BUFFER) {
403
+ message.resize(bufferSizeNeeded);
404
+ message.shrink_to_fit();
405
+
406
+ if (!EvtFormatMessage(hMetadata,
407
+ handle,
408
+ 0xffffffff,
409
+ 0,
410
+ nullptr,
411
+ EvtFormatMessageEvent,
412
+ message.size(),
413
+ &message.front(),
414
+ &bufferSizeNeeded)) {
415
+ status = GetLastError();
416
+
417
+ if (status != ERROR_EVT_UNRESOLVED_VALUE_INSERT) {
418
+ switch (status) {
419
+ case ERROR_EVT_MESSAGE_NOT_FOUND:
420
+ case ERROR_EVT_MESSAGE_ID_NOT_FOUND:
421
+ case ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND:
422
+ case ERROR_RESOURCE_LANG_NOT_FOUND:
423
+ case ERROR_MUI_FILE_NOT_FOUND:
424
+ case ERROR_EVT_UNRESOLVED_PARAMETER_INSERT:
425
+ if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
426
+ FORMAT_MESSAGE_FROM_SYSTEM |
427
+ FORMAT_MESSAGE_IGNORE_INSERTS,
428
+ nullptr,
429
+ status,
430
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
431
+ reinterpret_cast<WCHAR*>(&lpMsgBuf),
432
+ 0,
433
+ nullptr) == 0)
434
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
435
+ FORMAT_MESSAGE_FROM_SYSTEM |
436
+ FORMAT_MESSAGE_IGNORE_INSERTS,
437
+ nullptr,
438
+ status,
439
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
440
+ reinterpret_cast<WCHAR*>(&lpMsgBuf),
441
+ 0,
442
+ nullptr);
443
+
444
+ std::wstring ret(reinterpret_cast<WCHAR*>(lpMsgBuf));
445
+ std::copy(ret.begin(), ret.end(), std::back_inserter(result));
446
+ LocalFree(lpMsgBuf);
447
+
448
+ goto cleanup;
449
+ }
450
+
451
+ rb_raise(rb_eWinevtQueryError, "ErrorCode: %lu", status);
452
+ }
453
+ }
454
+ }
455
+ }
456
+
457
+ result = message;
458
+
459
+ cleanup:
460
+
461
+ return result;
462
+
463
+ #undef BUFSIZE
464
+ }
465
+
466
+ WCHAR*
467
+ get_description(EVT_HANDLE handle, LANGID langID, EVT_HANDLE hRemote)
468
+ {
469
+ #define BUFSIZE 4096
470
+ std::vector<WCHAR> buffer(BUFSIZE);
471
+ ULONG bufferSizeNeeded = 0;
472
+ ULONG status, count;
473
+ std::vector<WCHAR> result;
474
+ EVT_HANDLE hMetadata = nullptr;
475
+
476
+ static PCWSTR eventProperties[] = { L"Event/System/Provider/@Name" };
477
+ EVT_HANDLE renderContext =
478
+ EvtCreateRenderContext(1, eventProperties, EvtRenderContextValues);
479
+ if (renderContext == nullptr) {
480
+ rb_raise(rb_eWinevtQueryError, "Failed to create renderContext");
481
+ }
482
+
483
+ if (EvtRender(renderContext,
484
+ handle,
485
+ EvtRenderEventValues,
486
+ buffer.size(),
487
+ &buffer.front(),
488
+ &bufferSizeNeeded,
489
+ &count) != FALSE) {
490
+ status = ERROR_SUCCESS;
491
+ } else {
492
+ status = GetLastError();
493
+ }
494
+
495
+ if (status != ERROR_SUCCESS) {
496
+ raise_system_error(rb_eWinevtQueryError, status);
497
+ }
498
+
499
+ // Obtain buffer as EVT_VARIANT pointer. To avoid ErrorCide 87 in EvtRender.
500
+ const PEVT_VARIANT values = reinterpret_cast<PEVT_VARIANT>(&buffer.front());
501
+
502
+ // Open publisher metadata
503
+ hMetadata = EvtOpenPublisherMetadata(
504
+ hRemote,
505
+ values[0].StringVal,
506
+ nullptr,
507
+ MAKELCID(langID, SORT_DEFAULT),
508
+ 0);
509
+ if (hMetadata == nullptr) {
510
+ // When winevt_c cannot open metadata, then give up to obtain
511
+ // message file and clean up immediately.
512
+ goto cleanup;
513
+ }
514
+
515
+ result = get_message(hMetadata, handle);
516
+
517
+ #undef BUFSIZE
518
+
519
+ cleanup:
520
+
521
+ if (renderContext)
522
+ EvtClose(renderContext);
523
+
524
+ if (hMetadata)
525
+ EvtClose(hMetadata);
526
+
527
+ return _wcsdup(result.data());
528
+ }
529
+
530
+ VALUE
531
+ render_system_event(EVT_HANDLE hEvent, BOOL preserve_qualifiers)
532
+ {
533
+ DWORD status = ERROR_SUCCESS;
534
+ EVT_HANDLE hContext = NULL;
535
+ DWORD dwBufferSize = 0;
536
+ DWORD dwBufferUsed = 0;
537
+ DWORD dwPropertyCount = 0;
538
+ VALUE vRenderedValues;
539
+ PEVT_VARIANT pRenderedValues = NULL;
540
+ WCHAR wsGuid[50];
541
+ LPSTR pwsSid = NULL;
542
+ ULONGLONG ullTimeStamp = 0;
543
+ ULONGLONG ullNanoseconds = 0;
544
+ SYSTEMTIME st;
545
+ FILETIME ft;
546
+ CHAR buffer[32];
547
+ VALUE rbstr;
548
+ DWORD EventID;
549
+ VALUE hash = rb_hash_new();
550
+
551
+ hContext = EvtCreateRenderContext(0, NULL, EvtRenderContextSystem);
552
+ if (NULL == hContext) {
553
+ rb_raise(
554
+ rb_eWinevtQueryError, "Failed to create renderContext with %lu\n", GetLastError());
555
+ }
556
+
557
+ if (!EvtRender(hContext,
558
+ hEvent,
559
+ EvtRenderEventValues,
560
+ dwBufferSize,
561
+ pRenderedValues,
562
+ &dwBufferUsed,
563
+ &dwPropertyCount)) {
564
+ status = GetLastError();
565
+ if (ERROR_INSUFFICIENT_BUFFER == status) {
566
+ dwBufferSize = dwBufferUsed;
567
+ pRenderedValues = (PEVT_VARIANT)ALLOCV(vRenderedValues, dwBufferSize);
568
+ if (pRenderedValues) {
569
+ EvtRender(hContext,
570
+ hEvent,
571
+ EvtRenderEventValues,
572
+ dwBufferSize,
573
+ pRenderedValues,
574
+ &dwBufferUsed,
575
+ &dwPropertyCount);
576
+ status = GetLastError();
577
+ } else {
578
+ EvtClose(hContext);
579
+ rb_raise(rb_eRuntimeError, "Failed to malloc memory with %lu\n", status);
580
+ }
581
+ }
582
+
583
+ if (ERROR_SUCCESS != status) {
584
+ EvtClose(hContext);
585
+ ALLOCV_END(vRenderedValues);
586
+
587
+ rb_raise(rb_eWinevtQueryError, "EvtRender failed with %lu\n", status);
588
+ }
589
+ }
590
+
591
+ // EVT_VARIANT value with EvtRenderContextSystem will be decomposed
592
+ // as the following enum definition:
593
+ // https://docs.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_system_property_id
594
+ rbstr = wstr_to_rb_str(CP_UTF8, pRenderedValues[EvtSystemProviderName].StringVal, -1);
595
+ rb_hash_aset(hash, rb_str_new2("ProviderName"), rbstr);
596
+ if (NULL != pRenderedValues[EvtSystemProviderGuid].GuidVal) {
597
+ const GUID* Guid = pRenderedValues[EvtSystemProviderGuid].GuidVal;
598
+ StringFromGUID2(*Guid, wsGuid, _countof(wsGuid));
599
+ rbstr = wstr_to_rb_str(CP_UTF8, wsGuid, -1);
600
+ rb_hash_aset(hash, rb_str_new2("ProviderGuid"), rbstr);
601
+ } else {
602
+ rb_hash_aset(hash, rb_str_new2("ProviderGuid"), Qnil);
603
+ }
604
+
605
+ EventID = pRenderedValues[EvtSystemEventID].UInt16Val;
606
+ if (preserve_qualifiers) {
607
+ if (EvtVarTypeNull != pRenderedValues[EvtSystemQualifiers].Type) {
608
+ rb_hash_aset(hash, rb_str_new2("Qualifiers"),
609
+ INT2NUM(pRenderedValues[EvtSystemQualifiers].UInt16Val));
610
+ } else {
611
+ rb_hash_aset(hash, rb_str_new2("Qualifiers"), rb_str_new2(""));
612
+ }
613
+
614
+ rb_hash_aset(hash, rb_str_new2("EventID"), INT2NUM(EventID));
615
+ } else {
616
+ if (EvtVarTypeNull != pRenderedValues[EvtSystemQualifiers].Type) {
617
+ EventID = MAKELONG(pRenderedValues[EvtSystemEventID].UInt16Val,
618
+ pRenderedValues[EvtSystemQualifiers].UInt16Val);
619
+ }
620
+
621
+ rb_hash_aset(hash, rb_str_new2("EventID"), ULONG2NUM(EventID));
622
+ }
623
+
624
+ rb_hash_aset(hash,
625
+ rb_str_new2("Version"),
626
+ (EvtVarTypeNull == pRenderedValues[EvtSystemVersion].Type)
627
+ ? INT2NUM(0)
628
+ : INT2NUM(pRenderedValues[EvtSystemVersion].ByteVal));
629
+ rb_hash_aset(hash,
630
+ rb_str_new2("Level"),
631
+ (EvtVarTypeNull == pRenderedValues[EvtSystemLevel].Type)
632
+ ? INT2NUM(0)
633
+ : INT2NUM(pRenderedValues[EvtSystemLevel].ByteVal));
634
+ rb_hash_aset(hash,
635
+ rb_str_new2("Task"),
636
+ (EvtVarTypeNull == pRenderedValues[EvtSystemTask].Type)
637
+ ? INT2NUM(0)
638
+ : INT2NUM(pRenderedValues[EvtSystemTask].UInt16Val));
639
+ rb_hash_aset(hash,
640
+ rb_str_new2("Opcode"),
641
+ (EvtVarTypeNull == pRenderedValues[EvtSystemOpcode].Type)
642
+ ? INT2NUM(0)
643
+ : INT2NUM(pRenderedValues[EvtSystemOpcode].ByteVal));
644
+ _snprintf_s(buffer,
645
+ _countof(buffer),
646
+ _TRUNCATE,
647
+ "0x%llx",
648
+ pRenderedValues[EvtSystemKeywords].UInt64Val);
649
+ rb_hash_aset(hash,
650
+ rb_str_new2("Keywords"),
651
+ (EvtVarTypeNull == pRenderedValues[EvtSystemKeywords].Type)
652
+ ? Qnil
653
+ : rb_str_new2(buffer));
654
+
655
+ ullTimeStamp = pRenderedValues[EvtSystemTimeCreated].FileTimeVal;
656
+ ft.dwHighDateTime = (DWORD)((ullTimeStamp >> 32) & 0xFFFFFFFF);
657
+ ft.dwLowDateTime = (DWORD)(ullTimeStamp & 0xFFFFFFFF);
658
+
659
+ FileTimeToSystemTime(&ft, &st);
660
+ ullNanoseconds =
661
+ (ullTimeStamp % 10000000) *
662
+ 100; // Display nanoseconds instead of milliseconds for higher resolution
663
+ _snprintf_s(buffer,
664
+ _countof(buffer),
665
+ _TRUNCATE,
666
+ "%02d/%02d/%02d %02d:%02d:%02d.%llu",
667
+ st.wYear,
668
+ st.wMonth,
669
+ st.wDay,
670
+ st.wHour,
671
+ st.wMinute,
672
+ st.wSecond,
673
+ ullNanoseconds);
674
+ rb_hash_aset(hash,
675
+ rb_str_new2("TimeCreated"),
676
+ (EvtVarTypeNull == pRenderedValues[EvtSystemKeywords].Type)
677
+ ? Qnil
678
+ : rb_str_new2(buffer));
679
+ _snprintf_s(buffer,
680
+ _countof(buffer),
681
+ _TRUNCATE,
682
+ "%llu",
683
+ pRenderedValues[EvtSystemEventRecordId].UInt64Val);
684
+ rb_hash_aset(hash,
685
+ rb_str_new2("EventRecordID"),
686
+ (EvtVarTypeNull == pRenderedValues[EvtSystemEventRecordId].UInt64Val)
687
+ ? Qnil
688
+ : rb_str_new2(buffer));
689
+
690
+ if (EvtVarTypeNull != pRenderedValues[EvtSystemActivityID].Type) {
691
+ const GUID* Guid = pRenderedValues[EvtSystemActivityID].GuidVal;
692
+ StringFromGUID2(*Guid, wsGuid, _countof(wsGuid));
693
+ rbstr = wstr_to_rb_str(CP_UTF8, wsGuid, -1);
694
+ rb_hash_aset(hash, rb_str_new2("ActivityID"), rbstr);
695
+ }
696
+
697
+ if (EvtVarTypeNull != pRenderedValues[EvtSystemRelatedActivityID].Type) {
698
+ const GUID* Guid = pRenderedValues[EvtSystemRelatedActivityID].GuidVal;
699
+ StringFromGUID2(*Guid, wsGuid, _countof(wsGuid));
700
+ rbstr = wstr_to_rb_str(CP_UTF8, wsGuid, -1);
701
+ rb_hash_aset(hash, rb_str_new2("RelatedActivityID"), rbstr);
702
+ }
703
+
704
+ rb_hash_aset(hash,
705
+ rb_str_new2("ProcessID"),
706
+ UINT2NUM(pRenderedValues[EvtSystemProcessID].UInt32Val));
707
+ rb_hash_aset(hash,
708
+ rb_str_new2("ThreadID"),
709
+ UINT2NUM(pRenderedValues[EvtSystemThreadID].UInt32Val));
710
+ rbstr = wstr_to_rb_str(CP_UTF8, pRenderedValues[EvtSystemChannel].StringVal, -1);
711
+ rb_hash_aset(hash, rb_str_new2("Channel"), rbstr);
712
+ rbstr = wstr_to_rb_str(CP_UTF8, pRenderedValues[EvtSystemComputer].StringVal, -1);
713
+ rb_hash_aset(hash, rb_str_new2("Computer"), rbstr);
714
+
715
+ if (EvtVarTypeNull != pRenderedValues[EvtSystemUserID].Type) {
716
+ if (ConvertSidToStringSid(pRenderedValues[EvtSystemUserID].SidVal, &pwsSid)) {
717
+ rbstr = rb_utf8_str_new_cstr(pwsSid);
718
+ rb_hash_aset(hash, rb_str_new2("UserID"), rbstr);
719
+ LocalFree(pwsSid);
720
+ }
721
+ }
722
+
723
+ EvtClose(hContext);
724
+ ALLOCV_END(vRenderedValues);
725
+
726
+ return hash;
727
+ }