在没有 Windows 机器时读取 .evtx 文件
事件日志总在旅行:从一台被扣押的笔记本上下来,出自一个磁盘镜像,由一位服务器已经重建的客户导出。到达你手里的是一个 .evtx 文件,而打开它的工具——事件查看器——只存在于 Windows 上,并且把你看到的一半内容从写入日志的那台机器上的 DLL 中渲染出来。本指南讲清 .evtx 真正包含什么、如何用浏览器本地的 EVTX 查看器在任何地方对它分诊,以及能回答大多数首要问题的四个事件 ID。
最后更新:
日志从来不在你正坐着的那台机器上
模式总是同一个。出了某件事——一次疑似入侵、一场帐户锁定风暴、一个在凌晨 03:00 死掉的服务——而证据是一份 Windows 事件日志,有人从一台你无法启动、无法登录、或没有许可碰的机器上把它导出、做成镜像或复制了出来。你自己的机器是一台 Mac、一台 Linux 工作站,或一台锁得很死的公司笔记本,眼前连一个 Windows 虚拟机都没有。事件查看器不会来帮忙。
好消息是,.evtx 文件是一种有文档记录、自包含的二进制格式。事件查看器向你展示的关于一条记录的一切——除了下文要讲的一个重要例外——都在文件里面,而一个像样的解析器可以在任何地方读取它。本站的 EVTX 查看器在你的浏览器标签页中运行那个解析器(Rust evtx crate,编译为 WebAssembly),因为事件日志会写明用户、机器和 IP 地址,不该被上传到某个随手找到的转换站点,正如抓包文件不该被上传一样。下文讲的是工作方法,不是工具手册:看什么、按什么顺序看,以及这些字段能告诉你什么、不能告诉你什么。
.evtx 文件里到底有什么
一个 .evtx 文件是一个 4096 字节的文件头,后面跟着一连串 64 KB 的块。每个块装着一批事件记录,每条记录都以二进制 XML(BinXML)存储:一个由操作系统填写的 System 块,加上提供程序自己的有效载荷,即 EventData 或 UserData。打开一条记录,你看到的是字段,不是散文——事件 ID 4625、一个时间戳、一个通道,以及像 IpAddress、TargetUserName 和 LogonType 这样的命名值。那些字段就是证据。它们也是一个在外来机器上的解析器能诚实给你的全部。
例外在这里,它也塑造了本指南的其余部分:事件查看器显示的那句话——“有帐户登录失败”——不在文件中。Windows 在查看时从消息 DLL 中渲染它,那些 DLL 属于每个提供程序,住在写入日志的那台机器上。这正是为什么数据值有时看起来像 %%14592:它们是对文件并不携带的一张消息表的引用。另一台机器上的查看器可以向你展示事件记录的每一个字段,以及按原样存储的原始 XML——但一个为别人的 .evtx 呈现打磨好消息文本的工具,是在从它自己的 DLL 副本中重建它,或者在猜测。先字段、后散文,才是诚实的顺序。
在你引用数字之前,还有一个结构事实值得知道:文件的各个块是相互独立的。从磁盘镜像中雕刻出的、或从一块垂死硬盘上复制出的日志,常常有单个块再也无法解析。一个好的读取器会连同字节偏移报告每个损坏的块,并读取它周围的一切。在这一点上沉默——一个工具返回一份更短的日志却什么都不说——正是记录在调查中悄悄消失的方式。
从 System 块开始
每条记录的 System 块都带着同一副骨架:提供程序(哪个组件写了它)、事件 ID(发生了什么,按那个提供程序的编号)、级别(1 关键到 5 详细,0 表示没有级别的事件)、通道(安全、系统、应用程序,以及 Microsoft-Windows-* 之下数以百计的运行日志)、计算机、一个 UTC 时间戳,以及 EventRecordID。分诊始于把整个日志按这副骨架归类:多少条记录、跨越什么时间范围、来自哪些通道、由哪些事件 ID 主导。一份 80% 是同一个事件 ID 的安全日志,通常讲的就是那一件事——一道防火墙在做决定、一个服务在循环里反复认证——而摘要在你读单条记录之前就把这一点告诉你。
引用一条记录时,请引用 System 块中的 EventRecordID。被雕刻、被选取或被重新导出的文件,其记录头可能被生成它的工具重新编号,而 System 块保留着机器最初分配的 ID——“这份节录的第 7 条记录”与“原始日志中的 EventRecordID 319457858”之间的差别,在有人试图复现你的发现时立刻变得重要。时间戳值得同样的谨慎:文件内部它们是 UTC,永远是。事件查看器会把它们转换为打开日志的那台机器的本地时间,这正是为什么同一条记录的两张截图可以相差数小时。报告里选 UTC,并明说。
四个物有所值的事件 ID
1102——审核日志已被清除。安全日志会记录它自己的擦除,成为新日志中的第一条事件。它的字段写明了清除它的用户。在一起事件中,1102 既是证据,也是一条边界:它之前的那个日志中的一切都已经从你手里的文件中消失,而清除这件事本身是值得在报告里写一行的事实。如果一份日志最早的记录是一条时间戳落在你关注窗口内的 1102,在任何人基于更早事件的缺席构建理论之前,先把这一点说出来。
4624 与 4625——登录,成功与失败。这是帐户调查的主力。要紧的字段是 TargetUserName、IpAddress,尤其是 LogonType:3 是网络登录,10 是远程桌面,2 是交互式控制台登录,7 是解锁。一个暴力破解模式读起来是这样:一串针对同一个帐户、来自同一个地址的 4625,紧接着——要紧的那一刻——一条 4624。单独一条 4625 是打错字;序列的形状才是信号,这正是为什么要筛选和计数,而不是滚动着看。
4688——一个进程已被创建。当审核策略记录它时,每条 4688 都写明新进程(NewProcessName)、启动它的帐户,并且常常还有父进程——这是“这台机器上运行过什么、何时运行”的原材料。两点提醒让你保持诚实:4688 只有在源机器上启用了“审核进程创建”时才存在(它的缺席证明不了运行过什么),而命令行捕获又是另一项单独的设置。把一份丰富的 4688 轨迹当作一份礼物,而不是一项权利。
这四个是一组起点,不是一份教学大纲——4624 的特殊登录兄弟 4672、显式凭据登录 4648,以及系统日志中的服务安装 7045,是通常的下一站。但第一天问题中有相当大的一份——日志是否被抹掉、谁进来了、从哪里进来、他们运行了什么——仅靠 1102、4624、4625 和 4688 就能回答。
字段无法告诉你的事
对缺席保持纪律,是日志工作的大部分。文件无法向你展示源机器从未记录的事件:审核策略决定什么存在,而一台默认配置的机器记录的,远远少于调查者所希望的。它无法展示消息文本,如上所述——一个 %% 引用是指向一台你没有的机器上的字符串的指针。它本身也无法证明篡改的存在或不存在:记录 ID 的缺口既出现在诚实的雕刻文件中,也出现在被清除的文件中,这正是为什么要倚靠明确的 1102 记录、而不是缺口作为信号。
而且日志只是一个证人。时间戳来自源机器的时钟,它可能一直是错的;帐户以机器所知道的名字出现;一次网络登录的 IP 是机器看到的地址,包括 NAT 和 VPN。字段恰恰是机器记录下来的东西——不多,而纪律就是记住,也不少。
一套五分钟分诊流程
第一分钟:在 EVTX 查看器中打开文件,在看任何记录之前先读摘要——总数、时间范围、通道和最常见的事件 ID。记下查看器报告为无法读取的块,连同它们的偏移;这个保留意见从一开始就属于你的笔记,而不是后来的脚注。
第二分钟:查 1102。如果日志被清除过,你处理它的方法全都随之改变,而清除的时间和帐户是你最初的硬事实。第三分钟:筛选 4625 并看它的形状——每个帐户的数量、每个来源地址的数量。一串爆发之后跟着同一地址对同一帐户的一条 4624,就是发现;记下确切的时间戳。第四分钟:把可疑窗口固定下来后,在那个窗口内筛选 4688(如果远程访问是问题所在,再加上 4624 类型 10),列出运行了什么、谁登录了。第五分钟:把筛选出的记录导出为 JSON 或 CSV,趁数字还在眼前写出那一段话——记录 ID、UTC 时间、帐户、地址。导出是你的工作底稿;那一段话,连同关于无法读取的块和消息文本限制的保留意见,是交付物。
这套流程不会终结一项调查。它把一个外来的二进制文件变成五条有出处的事实和一个站得住脚的下一个问题,在你面前恰好是任何机器时都可以——而这正是分诊的大部分内容。
常见问题
我从事件查看器把日志导出为 CSV 或 XML 了。可以改读那个吗?
那些导出是另一种、更次的东西。CSV 导出把每条事件压平为事件查看器当时碰巧展示的几列,并丢掉大部分结构化的 EventData——而分诊真正要用的正是那些字段。如果你还能访问源头,用“将所有事件另存为…”重新导出并选择 .evtx;如果你手里只有 CSV,一张电子表格能告诉你的比任何 .evtx 工具都多,因为它在任何结构意义上都不再是一份事件日志了。
为什么这里的时间戳与一张在事件查看器中截的图不同?
因为事件查看器会转换。.evtx 文件内部的时间戳以 UTC 存储;事件查看器按打开日志的那台机器的本地时间显示它们。同一条记录在两个工具中诚实地相差数小时是完全可能的。本站的查看器保持 UTC 并如此标注那一列,报告的工作规则也一样:引用 UTC、写明时区,绝不在一条时间线里混用两者。
我文件中的记录 ID 有缺口。日志被篡改了吗?
仅凭缺口证明不了这一点。记录丢失有许多平凡的原因——块在一块垂死的磁盘上损坏、文件从未分配空间中雕刻出来、一次导出只选取了一个子集——雕刻出的文件甚至可能被重新编号其记录头,而 System 块保留着原始 ID。蓄意的清除会留下它自己的记录:事件 1102,作为新安全日志的第一条写入,写明清除它的帐户。在从任何缺席得出结论之前,先找它。