我试图通过订阅“安全”通道来捕获旧的和将来的Windows事件日志。但是我只有旧的活动,所有未来的活动都丢失了。
当前正在处理Windows事件日志。 我想要特定事件记录ID和所有将来事件中的旧事件。 为此,我订阅了特定的频道,例如“安全性”并尝试捕获我想要的事件。 但是在订阅安全通道的情况下,我使用“ EvtSubscribeStartAtOldestRecord”标志,以便所有旧事件和将来的事件都将被订阅,但是我仅得到旧事件,而将来的事件丢失。
EvtSubscribe (
NULL,
arrWaitHandle[1],
pwszChannel,
wsQuery,
NULL,
NULL,
NULL,
EvtSubscribeStartAtOldestRecord
);
用于订阅频道我使用上面的API和EvtSubscribeStartAtOldestRecord标志,因为我想要旧的事件以及将来的事件,但是在“安全性”频道的情况下,我只有旧的事件和未捕获的未来事件。
我观察到,在其他渠道(例如“应用程序”或“系统”)的情况下,我既遇到了旧事件,也遇到了未来事件。 但是对于“安全”频道,我只有旧的活动。
答案 0 :(得分:0)
我可以使用域管理员帐户捕获旧事件和将来的事件,并使用以下代码,这是Subscribing to Events上的示例,而我仅更改了其中一些:
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
#define ARRAY_SIZE 10
DWORD EnumerateResults(EVT_HANDLE hResults);
DWORD PrintEvent(EVT_HANDLE hEvent);
BOOL IsKeyEvent(HANDLE hStdIn);
void __cdecl wmain()
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hSubscription = NULL;
HANDLE aWaitHandles[2];
DWORD dwWait = 0;
// Get a handle for console input, so you can break out of the loop.
aWaitHandles[0] = GetStdHandle(STD_INPUT_HANDLE);
if (INVALID_HANDLE_VALUE == aWaitHandles[0])
{
wprintf(L"GetStdHandle failed with %lu.\n", GetLastError());
goto cleanup;
}
// Get a handle to a manual reset event object that the subscription will signal
// when events become available that match your query criteria.
aWaitHandles[1] = CreateEvent(NULL, TRUE, TRUE, NULL);
if (NULL == aWaitHandles[1])
{
wprintf(L"CreateEvent failed with %lu.\n", GetLastError());
goto cleanup;
}
// Subscribe to events.
hSubscription = EvtSubscribe(NULL, aWaitHandles[1], L"Security", NULL, NULL, NULL, NULL, EvtSubscribeStartAtOldestRecord);
if (NULL == hSubscription)
{
status = GetLastError();
if (ERROR_EVT_CHANNEL_NOT_FOUND == status)
wprintf(L"Channel was not found.\n");
else if (ERROR_EVT_INVALID_QUERY == status)
wprintf(L"The query was not found.\n");
else
wprintf(L"EvtSubscribe failed with %lu.\n", status);
goto cleanup;
}
wprintf(L"Press any key to quit.\n");
// Loop until the user presses a key or there is an error.
while (true)
{
dwWait = WaitForMultipleObjects(sizeof(aWaitHandles) / sizeof(HANDLE), aWaitHandles, FALSE, INFINITE);
if (0 == dwWait - WAIT_OBJECT_0) // Console input
{
if (IsKeyEvent(aWaitHandles[0]))
break;
}
else if (1 == dwWait - WAIT_OBJECT_0) // Query results
{
if (ERROR_NO_MORE_ITEMS != (status = EnumerateResults(hSubscription)))
{
break;
}
ResetEvent(aWaitHandles[1]);
}
else
{
if (WAIT_FAILED == dwWait)
{
wprintf(L"WaitForSingleObject failed with %lu\n", GetLastError());
}
break;
}
}
cleanup:
if (hSubscription)
EvtClose(hSubscription);
if (aWaitHandles[0])
CloseHandle(aWaitHandles[0]);
if (aWaitHandles[1])
CloseHandle(aWaitHandles[1]);
}
// Enumerate the events in the result set.
DWORD EnumerateResults(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hEvents[ARRAY_SIZE];
DWORD dwReturned = 0;
while (true)
{
// Get a block of events from the result set.
if (!EvtNext(hResults, ARRAY_SIZE, hEvents, INFINITE, 0, &dwReturned))
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
wprintf(L"EvtNext failed with %lu\n", status);
}
goto cleanup;
}
// For each event, call the PrintEvent function which renders the
// event for display.
for (DWORD i = 0; i < dwReturned; i++)
{
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[i])))
{
EvtClose(hEvents[i]);
hEvents[i] = NULL;
}
else
{
goto cleanup;
}
}
}
cleanup:
// Closes any events in case an error occurred above.
for (DWORD i = 0; i < dwReturned; i++)
{
if (NULL != hEvents[i])
EvtClose(hEvents[i]);
}
return status;
}
// Render the event as an XML string and print it.
DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
LPWSTR pRenderedContent = NULL;
// The EvtRenderEventXml flag tells EvtRender to render the event as an XML string.
if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pRenderedContent = (LPWSTR)malloc(dwBufferSize);
if (pRenderedContent)
{
EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", GetLastError());
goto cleanup;
}
}
wprintf(L"\n\n%s", pRenderedContent);
cleanup:
if (pRenderedContent)
free(pRenderedContent);
return status;
}
// Determines whether the console input was a key event.
BOOL IsKeyEvent(HANDLE hStdIn)
{
INPUT_RECORD Record[128];
DWORD dwRecordsRead = 0;
BOOL fKeyPress = FALSE;
if (ReadConsoleInput(hStdIn, Record, 128, &dwRecordsRead))
{
for (DWORD i = 0; i < dwRecordsRead; i++)
{
if (KEY_EVENT == Record[i].EventType)
{
fKeyPress = TRUE;
break;
}
}
}
return fKeyPress;
}
普通用户无权读取安全日志。安全日志旨在供系统使用。但是,如果用户已被授予SE_SECURITY_NAME
特权(“管理审核和安全日志”用户权限),则可以读取和清除安全日志。
更新:
当我在事件回调中设置断点时,也会捕获将来的事件,但是不会更新任何控制台输出。按任意键退出后,控制台中的某些输入会闪烁。因此,我刷新了控制台输出缓冲区,然后解决了问题。
在功能DWORD PrintEvent(EVT_HANDLE hEvent)
中:
{
...
wprintf(L"\n\n%s", pRenderedContent);
fflush(stdout);
...
}