JNA 从 windows 事件日志记录中解析描述字符串

JNA parse description strings from windows event log record

我正在使用 JNA 读取我的应用程序传送的一些事件日志。我最感兴趣的是描述字符串数据。

我正在使用以下代码:

private static void readLog() {
        Advapi32Util.EventLogIterator iter = new Advapi32Util.EventLogIterator("Application");
        while (iter.hasNext()) {
            Advapi32Util.EventLogRecord record = iter.next();

            System.out.println("------------------------------------------------------------");
            System.out.println(record.getRecordNumber()
                    + ": Event ID: " + record.getInstanceId()
                    + ", Event Type: " + record.getType()
                    + ", Event Strings: " + Arrays.toString(record.getStrings())
                    + ", Data: " + record.getRecord().toString());
            System.out.println();
        }
    }

我的应用程序产生的示例事件:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
    <System>
        <Provider Name="Microsoft-Windows-MyApp" Guid="{4d5ae6a1-c7c8-4e6d-b840-4d8080b42e1b}" />
        <EventID>201</EventID>
        <Version>0</Version>
        <Level>2</Level>
        <Task>2</Task>
        <Opcode>30</Opcode>
        <Keywords>0x4010000001000000</Keywords>
        <TimeCreated SystemTime="2021-02-19T15:16:03.675690900Z" />
        <EventRecordID>3622</EventRecordID>
        <Correlation ActivityID="{e6ee2b3b-9b9a-4c9d-b39b-6c2bf2550000}" />
        <Execution ProcessID="2108" ThreadID="8908" />
        <Channel>Microsoft-Windows-MyApp/Operational</Channel>
        <Computer>computer</Computer>
        <Security UserID="S-1-5-20" />
    </System>
    <UserData>
        <EventInfo xmlns="aag">
            <Username>username</Username>
            <IpAddress>127.0.0.1</IpAddress>
            <AuthType>NTLM</AuthType>
            <Resource />
            <ConnectionProtocol>HTTP</ConnectionProtocol>
            <ErrorCode>23003</ErrorCode>
        </EventInfo>
    </UserData>
</Event>

其他事件用户数据:

<UserData>
    <EventInfo xmlns="aag">
        <Username>otherUserName</Username>
        <IpAddress>10.235.163.52:50427</IpAddress>
    </EventInfo>
</UserData>

JNA 在EVENTLOGRECORD class 中提供事件日志记录,其中仅包含仅获取描述字符串值的方法。如果我能得到 XML 格式的记录,我的问题就会消失。 UserData 中的数据并不总是相同的,它包含不同的值,具体取决于事件类型。我想将 UserData 部分的数据解析为 POJO(它可以只是一个包含所有可用字段的 POJO)。我不想使用字段顺序,因为有些事件的字段与其他事件不同(如示例所示)。

有什么方法可以使用 xml 标签名来做到这一点吗?我什至会考虑切换到其他语言。

正如我在评论中指出的,您需要 render the event to get to the XML. Matthias Bläsing 还指出一些示例代码在 JNA 的 WevtapiTest 测试 class 中可用。

使用该测试 class,我创建了以下程序,它从系统日志的最新 50 个事件中读取 XML。将事件过滤为您想要的内容留作 reader.

的练习。
    public static void main(String[] args) {
        EVT_HANDLE queryHandle = null;
        // Requires elevation or shared access to the log.
        String path = "C:\Windows\System32\Winevt\Logs\System.evtx";

        try {
            queryHandle = Wevtapi.INSTANCE.EvtQuery(null, path, null, Winevt.EVT_QUERY_FLAGS.EvtQueryFilePath);

            // Read 10 events at a time
            int eventArraySize = 10;
            int evtNextTimeout = 1000;
            int arrayIndex = 0;
            EVT_HANDLE[] eventArray = new EVT_HANDLE[eventArraySize];
            IntByReference returned = new IntByReference();

            while (Wevtapi.INSTANCE.EvtNext(queryHandle, eventArraySize, eventArray, evtNextTimeout, 0, returned)) {

                Memory buff;
                // This just needs to be 0. Kept same name from test sample
                IntByReference propertyCount = new IntByReference();
                Winevt.EVT_VARIANT evtVariant = new Winevt.EVT_VARIANT();
                for (int i = 0; i < returned.getValue(); i++) {
                    buff = WevtapiUtil.EvtRender(null, eventArray[i], Winevt.EVT_RENDER_FLAGS.EvtRenderEventXml,
                            propertyCount);
                    // Output the XML!
                    System.out.println(buff.getWideString(0));
                }
                arrayIndex++;
                // Quit after 5 x 10 events
                if (arrayIndex >= 5) {
                    break;
                }
            }
            if (Kernel32.INSTANCE.GetLastError() != WinError.ERROR_SUCCESS
                    && Kernel32.INSTANCE.GetLastError() != WinError.ERROR_NO_MORE_ITEMS) {
                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
            }
        } finally {
            if (queryHandle != null) {
                Wevtapi.INSTANCE.EvtClose(queryHandle);
            }
        }
    }