winevt_c 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,718 +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
- 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
- rbObj = rb_sprintf("%#I64x", pRenderedValues[i].UInt64Val);
271
- rb_ary_push(userValues, rbObj);
272
- break;
273
- case EvtVarTypeEvtXml:
274
- if (pRenderedValues[i].XmlVal == nullptr) {
275
- rb_ary_push(userValues, rb_utf8_str_new_cstr("(NULL)"));
276
- } else {
277
- rbObj = wstr_to_rb_str(CP_UTF8, pRenderedValues[i].XmlVal, -1);
278
- rb_ary_push(userValues, rbObj);
279
- }
280
- break;
281
- default:
282
- rb_ary_push(userValues, rb_utf8_str_new_cstr("?"));
283
- break;
284
- }
285
- }
286
-
287
- return userValues;
288
- }
289
-
290
- VALUE
291
- get_values(EVT_HANDLE handle)
292
- {
293
- VALUE vbuffer;
294
- PEVT_VARIANT pRenderedValues;
295
- ULONG bufferSize = 0;
296
- ULONG bufferSizeUsed = 0;
297
- DWORD propCount = 0;
298
- BOOL succeeded;
299
- VALUE userValues = Qnil;
300
-
301
- EVT_HANDLE renderContext = EvtCreateRenderContext(0, nullptr, EvtRenderContextUser);
302
- if (renderContext == nullptr) {
303
- rb_raise(rb_eWinevtQueryError, "Failed to create renderContext");
304
- }
305
-
306
- // Get the size of the buffer
307
- EvtRender(
308
- renderContext, handle, EvtRenderEventValues, 0, NULL, &bufferSize, &propCount);
309
-
310
- // bufferSize is in bytes, not array size
311
- pRenderedValues = (PEVT_VARIANT)ALLOCV(vbuffer, bufferSize);
312
-
313
- succeeded = EvtRender(renderContext,
314
- handle,
315
- EvtRenderEventValues,
316
- bufferSize,
317
- pRenderedValues,
318
- &bufferSizeUsed,
319
- &propCount);
320
- if (!succeeded) {
321
- DWORD status = GetLastError();
322
- ALLOCV_END(vbuffer);
323
- EvtClose(renderContext);
324
- raise_system_error(rb_eWinevtQueryError, status);
325
- }
326
-
327
- userValues = extract_user_evt_variants(pRenderedValues, propCount);
328
-
329
- ALLOCV_END(vbuffer);
330
- EvtClose(renderContext);
331
-
332
- return userValues;
333
- }
334
-
335
- static std::vector<WCHAR>
336
- get_message(EVT_HANDLE hMetadata, EVT_HANDLE handle)
337
- {
338
- #define BUFSIZE 4096
339
- std::vector<WCHAR> result;
340
- ULONG status;
341
- ULONG bufferSizeNeeded = 0;
342
- LPVOID lpMsgBuf;
343
- std::vector<WCHAR> message(BUFSIZE);
344
-
345
- if (!EvtFormatMessage(hMetadata,
346
- handle,
347
- 0xffffffff,
348
- 0,
349
- nullptr,
350
- EvtFormatMessageEvent,
351
- message.size(),
352
- &message[0],
353
- &bufferSizeNeeded)) {
354
- status = GetLastError();
355
-
356
- if (status != ERROR_EVT_UNRESOLVED_VALUE_INSERT) {
357
- switch (status) {
358
- case ERROR_EVT_MESSAGE_NOT_FOUND:
359
- case ERROR_EVT_MESSAGE_ID_NOT_FOUND:
360
- case ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND:
361
- case ERROR_RESOURCE_LANG_NOT_FOUND:
362
- case ERROR_MUI_FILE_NOT_FOUND:
363
- case ERROR_EVT_UNRESOLVED_PARAMETER_INSERT: {
364
- if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
365
- FORMAT_MESSAGE_IGNORE_INSERTS,
366
- nullptr,
367
- status,
368
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
369
- reinterpret_cast<WCHAR*>(&lpMsgBuf),
370
- 0,
371
- nullptr) == 0)
372
- FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
373
- FORMAT_MESSAGE_IGNORE_INSERTS,
374
- nullptr,
375
- status,
376
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
377
- reinterpret_cast<WCHAR*>(&lpMsgBuf),
378
- 0,
379
- nullptr);
380
-
381
- std::wstring ret(reinterpret_cast<WCHAR*>(lpMsgBuf));
382
- std::copy(ret.begin(), ret.end(), std::back_inserter(result));
383
- LocalFree(lpMsgBuf);
384
-
385
- goto cleanup;
386
- }
387
- }
388
-
389
- if (status != ERROR_INSUFFICIENT_BUFFER)
390
- rb_raise(rb_eWinevtQueryError, "ErrorCode: %lu", status);
391
- }
392
-
393
- if (status == ERROR_INSUFFICIENT_BUFFER) {
394
- message.resize(bufferSizeNeeded);
395
- message.shrink_to_fit();
396
-
397
- if (!EvtFormatMessage(hMetadata,
398
- handle,
399
- 0xffffffff,
400
- 0,
401
- nullptr,
402
- EvtFormatMessageEvent,
403
- message.size(),
404
- &message.front(),
405
- &bufferSizeNeeded)) {
406
- status = GetLastError();
407
-
408
- if (status != ERROR_EVT_UNRESOLVED_VALUE_INSERT) {
409
- switch (status) {
410
- case ERROR_EVT_MESSAGE_NOT_FOUND:
411
- case ERROR_EVT_MESSAGE_ID_NOT_FOUND:
412
- case ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND:
413
- case ERROR_RESOURCE_LANG_NOT_FOUND:
414
- case ERROR_MUI_FILE_NOT_FOUND:
415
- case ERROR_EVT_UNRESOLVED_PARAMETER_INSERT:
416
- if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
417
- FORMAT_MESSAGE_FROM_SYSTEM |
418
- FORMAT_MESSAGE_IGNORE_INSERTS,
419
- nullptr,
420
- status,
421
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
422
- reinterpret_cast<WCHAR*>(&lpMsgBuf),
423
- 0,
424
- nullptr) == 0)
425
- FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
426
- FORMAT_MESSAGE_FROM_SYSTEM |
427
- FORMAT_MESSAGE_IGNORE_INSERTS,
428
- nullptr,
429
- status,
430
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
431
- reinterpret_cast<WCHAR*>(&lpMsgBuf),
432
- 0,
433
- nullptr);
434
-
435
- std::wstring ret(reinterpret_cast<WCHAR*>(lpMsgBuf));
436
- std::copy(ret.begin(), ret.end(), std::back_inserter(result));
437
- LocalFree(lpMsgBuf);
438
-
439
- goto cleanup;
440
- }
441
-
442
- rb_raise(rb_eWinevtQueryError, "ErrorCode: %lu", status);
443
- }
444
- }
445
- }
446
- }
447
-
448
- result = message;
449
-
450
- cleanup:
451
-
452
- return result;
453
-
454
- #undef BUFSIZE
455
- }
456
-
457
- WCHAR*
458
- get_description(EVT_HANDLE handle, LANGID langID, EVT_HANDLE hRemote)
459
- {
460
- #define BUFSIZE 4096
461
- std::vector<WCHAR> buffer(BUFSIZE);
462
- ULONG bufferSizeNeeded = 0;
463
- ULONG status, count;
464
- std::vector<WCHAR> result;
465
- EVT_HANDLE hMetadata = nullptr;
466
-
467
- static PCWSTR eventProperties[] = { L"Event/System/Provider/@Name" };
468
- EVT_HANDLE renderContext =
469
- EvtCreateRenderContext(1, eventProperties, EvtRenderContextValues);
470
- if (renderContext == nullptr) {
471
- rb_raise(rb_eWinevtQueryError, "Failed to create renderContext");
472
- }
473
-
474
- if (EvtRender(renderContext,
475
- handle,
476
- EvtRenderEventValues,
477
- buffer.size(),
478
- &buffer.front(),
479
- &bufferSizeNeeded,
480
- &count) != FALSE) {
481
- status = ERROR_SUCCESS;
482
- } else {
483
- status = GetLastError();
484
- }
485
-
486
- if (status != ERROR_SUCCESS) {
487
- raise_system_error(rb_eWinevtQueryError, status);
488
- }
489
-
490
- // Obtain buffer as EVT_VARIANT pointer. To avoid ErrorCide 87 in EvtRender.
491
- const PEVT_VARIANT values = reinterpret_cast<PEVT_VARIANT>(&buffer.front());
492
-
493
- // Open publisher metadata
494
- hMetadata = EvtOpenPublisherMetadata(
495
- hRemote,
496
- values[0].StringVal,
497
- nullptr,
498
- MAKELCID(langID, SORT_DEFAULT),
499
- 0);
500
- if (hMetadata == nullptr) {
501
- // When winevt_c cannot open metadata, then give up to obtain
502
- // message file and clean up immediately.
503
- goto cleanup;
504
- }
505
-
506
- result = get_message(hMetadata, handle);
507
-
508
- #undef BUFSIZE
509
-
510
- cleanup:
511
-
512
- if (renderContext)
513
- EvtClose(renderContext);
514
-
515
- if (hMetadata)
516
- EvtClose(hMetadata);
517
-
518
- return _wcsdup(result.data());
519
- }
520
-
521
- VALUE
522
- render_system_event(EVT_HANDLE hEvent, BOOL preserve_qualifiers)
523
- {
524
- DWORD status = ERROR_SUCCESS;
525
- EVT_HANDLE hContext = NULL;
526
- DWORD dwBufferSize = 0;
527
- DWORD dwBufferUsed = 0;
528
- DWORD dwPropertyCount = 0;
529
- VALUE vRenderedValues;
530
- PEVT_VARIANT pRenderedValues = NULL;
531
- WCHAR wsGuid[50];
532
- LPSTR pwsSid = NULL;
533
- ULONGLONG ullTimeStamp = 0;
534
- ULONGLONG ullNanoseconds = 0;
535
- SYSTEMTIME st;
536
- FILETIME ft;
537
- CHAR buffer[32];
538
- VALUE rbstr;
539
- DWORD EventID;
540
- VALUE hash = rb_hash_new();
541
-
542
- hContext = EvtCreateRenderContext(0, NULL, EvtRenderContextSystem);
543
- if (NULL == hContext) {
544
- rb_raise(
545
- rb_eWinevtQueryError, "Failed to create renderContext with %lu\n", GetLastError());
546
- }
547
-
548
- if (!EvtRender(hContext,
549
- hEvent,
550
- EvtRenderEventValues,
551
- dwBufferSize,
552
- pRenderedValues,
553
- &dwBufferUsed,
554
- &dwPropertyCount)) {
555
- status = GetLastError();
556
- if (ERROR_INSUFFICIENT_BUFFER == status) {
557
- dwBufferSize = dwBufferUsed;
558
- pRenderedValues = (PEVT_VARIANT)ALLOCV(vRenderedValues, dwBufferSize);
559
- if (pRenderedValues) {
560
- EvtRender(hContext,
561
- hEvent,
562
- EvtRenderEventValues,
563
- dwBufferSize,
564
- pRenderedValues,
565
- &dwBufferUsed,
566
- &dwPropertyCount);
567
- } else {
568
- EvtClose(hContext);
569
- rb_raise(rb_eRuntimeError, "Failed to malloc memory with %lu\n", status);
570
- }
571
- }
572
-
573
- status = GetLastError();
574
- if (ERROR_SUCCESS != status) {
575
- EvtClose(hContext);
576
- ALLOCV_END(vRenderedValues);
577
-
578
- rb_raise(rb_eWinevtQueryError, "EvtRender failed with %lu\n", status);
579
- }
580
- }
581
-
582
- // EVT_VARIANT value with EvtRenderContextSystem will be decomposed
583
- // as the following enum definition:
584
- // https://docs.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_system_property_id
585
- rbstr = wstr_to_rb_str(CP_UTF8, pRenderedValues[EvtSystemProviderName].StringVal, -1);
586
- rb_hash_aset(hash, rb_str_new2("ProviderName"), rbstr);
587
- if (NULL != pRenderedValues[EvtSystemProviderGuid].GuidVal) {
588
- const GUID* Guid = pRenderedValues[EvtSystemProviderGuid].GuidVal;
589
- StringFromGUID2(*Guid, wsGuid, _countof(wsGuid));
590
- rbstr = wstr_to_rb_str(CP_UTF8, wsGuid, -1);
591
- rb_hash_aset(hash, rb_str_new2("ProviderGuid"), rbstr);
592
- } else {
593
- rb_hash_aset(hash, rb_str_new2("ProviderGuid"), Qnil);
594
- }
595
-
596
- EventID = pRenderedValues[EvtSystemEventID].UInt16Val;
597
- if (preserve_qualifiers) {
598
- if (EvtVarTypeNull != pRenderedValues[EvtSystemQualifiers].Type) {
599
- rb_hash_aset(hash, rb_str_new2("Qualifiers"),
600
- INT2NUM(pRenderedValues[EvtSystemQualifiers].UInt16Val));
601
- } else {
602
- rb_hash_aset(hash, rb_str_new2("Qualifiers"), rb_str_new2(""));
603
- }
604
-
605
- rb_hash_aset(hash, rb_str_new2("EventID"), INT2NUM(EventID));
606
- } else {
607
- if (EvtVarTypeNull != pRenderedValues[EvtSystemQualifiers].Type) {
608
- EventID = MAKELONG(pRenderedValues[EvtSystemEventID].UInt16Val,
609
- pRenderedValues[EvtSystemQualifiers].UInt16Val);
610
- }
611
-
612
- rb_hash_aset(hash, rb_str_new2("EventID"), ULONG2NUM(EventID));
613
- }
614
-
615
- rb_hash_aset(hash,
616
- rb_str_new2("Version"),
617
- (EvtVarTypeNull == pRenderedValues[EvtSystemVersion].Type)
618
- ? INT2NUM(0)
619
- : INT2NUM(pRenderedValues[EvtSystemVersion].ByteVal));
620
- rb_hash_aset(hash,
621
- rb_str_new2("Level"),
622
- (EvtVarTypeNull == pRenderedValues[EvtSystemLevel].Type)
623
- ? INT2NUM(0)
624
- : INT2NUM(pRenderedValues[EvtSystemLevel].ByteVal));
625
- rb_hash_aset(hash,
626
- rb_str_new2("Task"),
627
- (EvtVarTypeNull == pRenderedValues[EvtSystemTask].Type)
628
- ? INT2NUM(0)
629
- : INT2NUM(pRenderedValues[EvtSystemTask].UInt16Val));
630
- rb_hash_aset(hash,
631
- rb_str_new2("Opcode"),
632
- (EvtVarTypeNull == pRenderedValues[EvtSystemOpcode].Type)
633
- ? INT2NUM(0)
634
- : INT2NUM(pRenderedValues[EvtSystemOpcode].ByteVal));
635
- _snprintf_s(buffer,
636
- _countof(buffer),
637
- _TRUNCATE,
638
- "0x%llx",
639
- pRenderedValues[EvtSystemKeywords].UInt64Val);
640
- rb_hash_aset(hash,
641
- rb_str_new2("Keywords"),
642
- (EvtVarTypeNull == pRenderedValues[EvtSystemKeywords].Type)
643
- ? Qnil
644
- : rb_str_new2(buffer));
645
-
646
- ullTimeStamp = pRenderedValues[EvtSystemTimeCreated].FileTimeVal;
647
- ft.dwHighDateTime = (DWORD)((ullTimeStamp >> 32) & 0xFFFFFFFF);
648
- ft.dwLowDateTime = (DWORD)(ullTimeStamp & 0xFFFFFFFF);
649
-
650
- FileTimeToSystemTime(&ft, &st);
651
- ullNanoseconds =
652
- (ullTimeStamp % 10000000) *
653
- 100; // Display nanoseconds instead of milliseconds for higher resolution
654
- _snprintf_s(buffer,
655
- _countof(buffer),
656
- _TRUNCATE,
657
- "%02d/%02d/%02d %02d:%02d:%02d.%llu",
658
- st.wYear,
659
- st.wMonth,
660
- st.wDay,
661
- st.wHour,
662
- st.wMinute,
663
- st.wSecond,
664
- ullNanoseconds);
665
- rb_hash_aset(hash,
666
- rb_str_new2("TimeCreated"),
667
- (EvtVarTypeNull == pRenderedValues[EvtSystemKeywords].Type)
668
- ? Qnil
669
- : rb_str_new2(buffer));
670
- _snprintf_s(buffer,
671
- _countof(buffer),
672
- _TRUNCATE,
673
- "%llu",
674
- pRenderedValues[EvtSystemEventRecordId].UInt64Val);
675
- rb_hash_aset(hash,
676
- rb_str_new2("EventRecordID"),
677
- (EvtVarTypeNull == pRenderedValues[EvtSystemEventRecordId].UInt64Val)
678
- ? Qnil
679
- : rb_str_new2(buffer));
680
-
681
- if (EvtVarTypeNull != pRenderedValues[EvtSystemActivityID].Type) {
682
- const GUID* Guid = pRenderedValues[EvtSystemActivityID].GuidVal;
683
- StringFromGUID2(*Guid, wsGuid, _countof(wsGuid));
684
- rbstr = wstr_to_rb_str(CP_UTF8, wsGuid, -1);
685
- rb_hash_aset(hash, rb_str_new2("ActivityID"), rbstr);
686
- }
687
-
688
- if (EvtVarTypeNull != pRenderedValues[EvtSystemRelatedActivityID].Type) {
689
- const GUID* Guid = pRenderedValues[EvtSystemRelatedActivityID].GuidVal;
690
- StringFromGUID2(*Guid, wsGuid, _countof(wsGuid));
691
- rbstr = wstr_to_rb_str(CP_UTF8, wsGuid, -1);
692
- rb_hash_aset(hash, rb_str_new2("RelatedActivityID"), rbstr);
693
- }
694
-
695
- rb_hash_aset(hash,
696
- rb_str_new2("ProcessID"),
697
- UINT2NUM(pRenderedValues[EvtSystemProcessID].UInt32Val));
698
- rb_hash_aset(hash,
699
- rb_str_new2("ThreadID"),
700
- UINT2NUM(pRenderedValues[EvtSystemThreadID].UInt32Val));
701
- rbstr = wstr_to_rb_str(CP_UTF8, pRenderedValues[EvtSystemChannel].StringVal, -1);
702
- rb_hash_aset(hash, rb_str_new2("Channel"), rbstr);
703
- rbstr = wstr_to_rb_str(CP_UTF8, pRenderedValues[EvtSystemComputer].StringVal, -1);
704
- rb_hash_aset(hash, rb_str_new2("Computer"), rbstr);
705
-
706
- if (EvtVarTypeNull != pRenderedValues[EvtSystemUserID].Type) {
707
- if (ConvertSidToStringSid(pRenderedValues[EvtSystemUserID].SidVal, &pwsSid)) {
708
- rbstr = rb_utf8_str_new_cstr(pwsSid);
709
- rb_hash_aset(hash, rb_str_new2("UserID"), rbstr);
710
- LocalFree(pwsSid);
711
- }
712
- }
713
-
714
- EvtClose(hContext);
715
- ALLOCV_END(vRenderedValues);
716
-
717
- return hash;
718
- }
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
+ }