APP下载

Windows操作系统下日志文件格式分析与修改

2023-01-16冯贤菊李巧君

现代计算机 2022年22期
关键词:数组字节日志

杨 伟,冯贤菊,李巧君

(河南工业职业技术学院电子信息工程学院,南阳 473000)

0 引言

微软从Windows NT 6.0 操作系统开始,采用了基于XML 技术的二进制XML日志文件格式。日志文件详细记录了系统、用户、应用程序等各种操作[1],如合法用户对系统的使用情况,系统中的异常事件等[2]。通过这些日志数据,可以监视系统运行情况,检测和分析异常事件和错误发生的原因,识别各种安全事件和威胁等[3]。但目前关于系统日志仅是对格式的说明,并没有对记录内部二进制XML 如何转化为文本形式做详细的介绍。因此,本文将对日志文件格式、元素及其记录内部二进制XML 编码转化文本等内容详细介绍,并在此基础上分析如何从日志文件中删除或修改数据。

1 Windows日志格式

Windows日志文件分System.evtx 系统日志、Application.evtx 应用程序日志、Security.evtx 安全日志三种[4],存放路径默认为:%System-Root%System32WinevtLogs(不同Windows 系统,日志文件位置可能不同)[5]。文件大小默认为20 MB,当文件大小超出20 MB时,采用“先生成先覆盖”的原则覆盖替换先成的日志记录[6]。通过事件查看器可浏览和管理日志,通过注册表表项可对其大小和路径进行配置。

日志文件结构包括:文件头、若干数据块、尾部空数据三个部分,如图1所示。

图1 日志文件结构示意图

1.1 文件头

文件头位于日志文件开始,大小为4KB,记录日志文件的基本信息,常驻内存中。实际有用的仅前面128 字节,结构如表1所示。在日志中先低位后高位,如0x80 00 00 00为128的十六进制。

表1 文件头结构

文件头前8 字节是魔字符串ElfFilex00,文件头的开始标记。0x08 处开始的8 字节为第一块的块号,块号从0 开始,常为0。0x10 处开始的8 字节为当前使用数据块的块号。0x18 处开始的8 字节为下一条记录的记录号。新增记录时,会根据当前使用的块号和下一条记录的记录号来确定新增记录的记录号,以及记录写入的位置。

从0x78 处开始的4 字节是标志,若标志为0x00 00 00 00,表示正常日志文件;若标志为0x00 00 00 01,表示脏日志文件,意味着日志文件被打开修改过,文件和块头可能不能正确反映该文件的状态,校验和也可能是错的。当脏文件被重新打开时,日志服务会扫描整个文件,清空该标志位,重新计算校验和,更新文件头相应字段[7]。若标志为0x00 00 00 02,表示满日志文件,如果保留策略不允许覆盖旧记录,则新记录将不会被记录到日志文件中,潜在的某些有价值的记录就会丢失。从0x7c 开始的4 字节为校验和,校验文件头中前0x78字节内容。

1.2 数据块

数据块大小为64 KB,由块头、日志记录、未使用空间三部分组成[8]。当日志记录长度大于当前块的剩余大小时,会写入新数据块,因此数据块中存在未使用空间。正因如此,日志文件中虽有许多数据块,却只有当前使用数据块才会被调入内存中,这大大降低了日志服务对系统资源的占用和开销。

1.2.1 块头

块头记录数据块的基本信息,大小为512B,结构如表2所示。块头中含两类记录编号方式:基于日志和基于文件。在自动维护模式下,当日志文件到达最大值时,系统会重命名该文件,以原文件名创建一个新日志文件[9]。新文件中基于日志的编号以原文件中编号为开始,而基于文件的编号则从零开始。当清空日志时,基于日志的编号才被清零[9]。记录校验和校验块内所有记录,范围从0x200到最后记录末尾。块头校验和校验块头前128 字节以及从129 到512字节的内容。字符串哈希表,共64 个表项,存储的是XML 模板中常用字符串在数据块中的偏移。在XML 中,会为每个字符串计算一个16 位的哈希值,该哈希值对64 求余的余数指向一个表项,该表项存储字符串在数据块中的偏移,冲突时采用单链表法解决。哈希表后面是XML模板表,共32 个表项。这两个表主要用于避免同一数据块内的某些字符串和XML 结构的冗余声明。此外日志文件中所有的偏移都基于当前块头开始计算。

表2 块头结构

1.2.2 日志记录

日志记录位于块头之后,结构如表3所示。前4 字节是开始标记0x2a 2a 00 00,其后4 字节是记录长度,之后8 字节为记录的创建日期时间,0x18 之后是长度不确定的二进制XML 流,格式在第3 小节介绍。最后4 字节为重复的记录长度,以便快速有效遍历日志记录。

表3 日志记录结构

2 二进制XML

为减少XML 文本数据冗余,微软采用专有的二进制XML 编码将日志记录从文本形式转换成二进制形式,减少了日志文件占用的存储空间和处理时间。转换过程分三步:①XML 元素标记化;②通过替换机制将结构、内容分离;③为重复XML结构定义模板[10]。

XML模板如图2所示,Events元素包括所有Event 元素。Event 元素描述日志记录,包含两个元素:一个是System 元素,提供记录的大部分基本信息;另一个是EventData、BinaryEvent-Data 等元素中的一个,其中EventData 使用较多。

图2 XML结构图

2.1 XML语言元素标记化

为减少计算资源和存储空间,被频繁读取的XML 消息被转换为标记。标记分为系统标记和应用程序标记,其中系统标记被硬编码进生成和解析二进制XML 的程序中,提供编号和相应功能的静态映射,如表4所示;应用程序标记主要表示元素、属性名和XML模板。

表4 系统标记

其中0x41 表示元素中包含属性列表,0x01表示不包含属性;0x46 表示该属性之后有其它属性,0x06 表示当前属性为最后一个属性。以<EventID>7036</EventID>为例,根据以上规则,标记化后为:0x01 EventID 0x02 1234 0x04。这里只是简单地介绍元素如何被标记,在实际的XML 流中,元素名和属性名会被标记为应用程序标记,属性和元素的值被转化存储在替换数组中。

2.2 模板和替换机制

替换机制的目的是将结构与内容分离。日志记录都以<System>元素开始,<System>里面包含的元素和属性相同,不同的只是元素内容和属性值。Windows 将XML 中相同结构的二进制序列制成模板;不同的部分用替换记号替代,元素内容和属性值存储在替换数组中,替换记号指向数组中相对应位置。通过模板实例、系统和应用标记可实例化一个模板,二者通过一个ID 联系起来。这样,在同一个数据块中具有相同XML 结构的记录使用同一个XML 模板,只有出现不同的XML结构时才会出现模板的定义,极大减少了文件的存储空间。

替换记号分为正常替换记号和可选替换记号,均为4字节。第1字节是替换标记,0x0d或0x0e;接下来2字节是替换标识符,指示模板中的值在替换数组中的下标,下标从0开始;最后1字节是数据类型。两者替换原则不同,前者在任何条件下都是将替换数组中的数据插入到XML 结构中,而后者是替换数组中记号指向的元素不为空时,与前者一样直接插入;指向为空时,则隐藏相应元素或属性。对于上面的例子,可完善为:0x01 EventID 0x02 0x0e 0x0003 0x06 0x04。其中0x0e 表示可选替换标记,0x0003 为2 字节的标识,标识该元素的值在替换数组中的下标为3,数据类型为6。

2.3 二进制XML格式分析

二进制XML 的格式如表5所示,其中模板定义偏移量,指向的位置可能位于偏移值之后,也可能指向该记录之前的某一位置。前者说明该记录中声明了XML模板,包含模板定义数据。后者说明此记录中无XML 模板,使用的XML 模板在该记录之前已经定义,紧跟着偏移后面的内容为替换数组。模板定义数据中的数据大小计算的是fragment header、元素以及结束标记的大小。

表5 二进制流

元素的结构如表6所示,其中元素大小包括偏移、属性列表、关闭标记、元素值、元素的结束标记,即除前7个字节之外的字节数。根据偏移可找到元素名,如图30x1249 处的0x4D 02 00 00为元素名偏移,由此找到0x124D处的元素名,前4字节未知,其后2字节0x BA 0C 为字符串哈希,0x 05 00为元素名中字符个数,接下来0x 45 00 76 00 65 00 6E 00 74 00 为元素名Event的Utf-16字符串。

表6 元素的结构

属性列表含属性列表大小和属性数组,如图3中0x1261 到0x12eb 处内容。属性数组中含多个属性。属性的第1 字节为属性标记,为0x06 或0x46,接下来4 字节为属性名偏移,最后为属性数据。属性数据常见的为属性值和替换,替换标记格式已在上面介绍,属性值格式如图3中127e 处内容,第1 字节为属性值标记0x05,其后1字节为数据类型,最后为长度不确定的属性值。

图3 元素数据

二进制XML 的最后为替换数组,结构如图4所示。前4 字节为数组元素个数,其后为每个数组元素的大小以及数据类型,最后为各个数组元素的实际数据。

图4 替换数组

XML 结构中变量元素在替换数组中的位置是固定的,它们之间的映射关系如图5所示。

图5 XML和替换数组映射关系

根据上面的格式分析,结合替换数组的结构,可对日志记录中的二进制XML 数据进行内容还原,将二进制数据转化为文本形式。

3 删除修改事件记录的方法

基于上述日志格式分析,可以对日志文件进行修改、删除操作。但由于Windows 系统中事件日志服务运行在svchost.exe进程中,该进程是关键系统进程,自启动且不可停止,若强行中止系统检测到后会自动关机。因此,在事件服务启动的情况下,由于系统对日志文件的保护,无法修改或删除日志文件。但我们可以备份日志文件,对备份文件中的日志记录修改或删除,然后用修改后的日志文件覆盖原有日志文件来达到日志内容修改的目的。

.NET 提供了许多操作事件日志的类,如EventLog、EventLogQuery、EventLogReader、Event-Record 等。根据上述思路,利用.NET 提供的日志操作类删除和修改日志记录的步骤为:

(1)在注册表EventLog下注册一个新日志文件,文件名与要修改的日志文件名长度一致。

(2)通过指定查询目标和事件查询初始化EventLogQuery 类的新实例。查询目标为要修改的日志文件;事件查询语句可根据规则过滤一些要删除的事件记录。

(3)初始化EventLogReader 类的实例,利用ReadEvent方法,遍历查询到的事件记录。

(4)EventRecord 提供了事件记录的绝大部分信息,利用这些信息以及EventLog 提供的日志写入方法,可以将事件记录写入新注册的日志文件中。写入时日志的分类、来源、用户等信息可以指定,只需要修改相应内容就可保持新、旧日志信息一致。

(5)日志写入完成后,备份新注册的日志信息。

(6)由于无法指定事件记录的写入时间、事件源,且新注册的日志文件名与原日志文件名不同,因此需要对备份文件中每条记录的上述信息进行修改,同时也可根据规则修改事件记录中的其他数据。

(7)对涉及到校验和的地方重新生成。

(8)用修改后的文件覆盖原有的日志文件。

在写入新注册的日志文件时,由于事件源已经在要修改的日志中注册,导致不能用原来的事件源在新注册的日志中创建事件源。为了不改动数据偏移,我们用一个新的事件源来代替原来的事件源,但其长度要与原来的事件源相同。另外新产生的日志文件中元素Provider 中不存在属性Guid,为了与原日志文件保存一致,在创建完事件源之后,需要修改注册表中事件源的ProviderGuid 属性值为原来日志文件中相应事件源的ProviderGuid 值。通过上述步骤,可以实现事件记录的删除、修改操作。

4 结语

本文详尽描述了Windows 系统日志文件的结构、校验机制等,并在此基础上介绍了基于.NET 框架对日志事件记录进行删除及修改的具体方法,能够自由删除、修改日志记录。

猜你喜欢

数组字节日志
JAVA稀疏矩阵算法
一名老党员的工作日志
No.8 字节跳动将推出独立出口电商APP
扶贫日志
JAVA玩转数学之二维数组排序
No.10 “字节跳动手机”要来了?
雅皮的心情日志
基于MSP430的四旋翼飞行器的S-BUS通信协议的设计与实现
雅皮的心情日志
更高效用好 Excel的数组公式