winevt_c 0.7.4 → 0.9.2

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