【问题标题】:How to get the template for a windows event log message如何获取 Windows 事件日志消息的模板
【发布时间】:2015-09-29 09:58:25
【问题描述】:

我想读取存档的 Windows 事件日志文件 (.evtx),如下例所示:

using System;
using System.Diagnostics.Eventing.Reader;

public static class Program {
    static void Main(string[] args) {
        using (var reader = new EventLogReader(@"C:\tmp\some-log.evtx", PathType.FilePath)) {
            EventRecord record;
            while ((record = reader.ReadEvent()) != null) {
                // do something with record...
            }
        }
    }
}

record 对象有一个 Properties 列表,其中包含事件的替换字符串:

foreach (var property in record.Properties) {
    Console.WriteLine(property.Value);
}

如果我在事件日志查看器中打开 .evtx 文件,我可以看到事件的完整描述,这就像一个基本模板消息(它应该来自与生成事件的应用程序关联的资源文件) 将占位符的值替换为这些值:

有没有办法为某个事件获取这个“消息模板”?

【问题讨论】:

    标签: c# windows event-log


    【解决方案1】:

    我后来发现这些“消息模板”可以读取与某个提供程序(基本上是事件的注册源)关联的事件元数据。

    这是一个例子:

    using System;
    using System.Diagnostics.Eventing.Reader;
    using System.Globalization;
    
    public static class Program {
    
        static void Main(string[] args) {
            foreach (var providerName in EventLogSession.GlobalSession.GetProviderNames()) {
                DumpMetadata(providerName);
            }
        }
    
        private static void DumpMetadata(string providerName) {
            try {
                ProviderMetadata providerMetadata = new ProviderMetadata(providerName, EventLogSession.GlobalSession, CultureInfo.InvariantCulture);
                foreach (var eventMetadata in providerMetadata.Events) {
                    if (!string.IsNullOrEmpty(eventMetadata.Description)) {
                        Console.WriteLine("{0} ({1}): {2}", eventMetadata.Id, eventMetadata.Version, eventMetadata.Description);
                    }
                }
            } catch (EventLogException) {
                Console.WriteLine("Cannot read metadata for provider {0}", providerName);
            } 
        }
    }
    

    【讨论】:

    • 通过任何来源,您知道这些元数据在 Windows 中的保存位置吗?
    • @Vesper 保存在Computer\HKEY_LOCAL_MACHINE\SYSTEM\{controlSet}\Services\EventLog\{eventLogName}\{providerName}
    【解决方案2】:

    如果您在另一台机器上检查事件日志,而不是保存它的机器,那么您将无法享受 EventLogSession.GlobalSession.GetProviderNames() 的好处,但前提是您可以找到并安装机器的 HKEY_LOCAL_MACHINE 注册表配置单元(位于C:\Windows\System32\config\SYSTEM 文件中 - 是的,它是一个无扩展名文件)您可以从此注册表项获取事件模板:

    HKEY_LOCAL_MACHINE\SYSTEM\{controlSet}\Services\EventLog\{eventLogName}\{providerName}
    
    • {controlSet} 通常是“CurrentControlSet”,但如果您正在调查在神秘情况下死机的机器,您可能需要查看其他键,例如 ControlSet001

      • These "control set" names 参与“最后一次正确配置”启动选项、系统还原和 Windows 启动过程的其他部分。如果计算机无法正确启动,Windows 将尝试其他配置变体,这些变体具有自己单独的事件日志配置副本。
    • {eventLogName} 是您正在查看的日志的名称。仅为单个目标日志注册事件源。

    • 其中{providerName} 对应于 Windows 事件日志查看器中“事件源”列中的值。

    查找名为 EventMessageFile 的注册表值,它为您提供了 Win32 PE(*.exe*.dll)的路径,其中包含包含事件日志消息模板的 Win32 资源字符串 - 然后您可以使用标准读取那些用于提取 Win32 资源的 Win32 资源函数或其他一些库。

    注意reading event-logs without the message templates extracted from the EventMessageFile is an exercise in pain

    【讨论】:

    • 这个问题在这一点上已经很老了,但我真的很喜欢这个 Windows 逆向工程 :)
    猜你喜欢
    • 1970-01-01
    • 2016-03-19
    • 2012-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    相关资源
    最近更新 更多