0x00 前言

Windows Event Viewer Log (EVT)单条日志清除系列文章的第二篇,介绍删除evt文件指定时间段日志记录的思路,解决在程序设计上需要考虑的多个问题,开源实现代码。


0x01 简介

本文将要介绍以下内容:

  • 对指定evt文件指定时间段日志记录的删除思路

  • 程序实现细节

  • 开源代码



0x02 删除evt文件指定时间段日志记录的思路














对比之前文章中提到的evtx文件单条日志删除方法,evt文件无法使用相同的思路

这是因为evt的文件结构中不包括唯一值EventRecordID,也就无法定位到指定的日志

经过分析,发现可以选择日志的创建时间作为输入项,指定起始日期和结束日期,删除这个时间段内的日志内容

而日志创建时间的格式为time_t类型,这里需要做一个考虑time_t类型和格林威治标准时间(Greenwich Mean Time,GMT)之间的转换

在程序实现上,思路如下:

  • 遍历所有日志,过滤掉符合删除条件的日志,保存剩下的日志内容

  • 筛选完成后,后续日志的Record number作减法,减去删除的日志条数

  • 更新file header中的End of file record offset,Last (newest) record number和Maximum file size

  • 更新end of file record中的End of file record offset和Last (newest) record number


0x03 time_t类型和格林威治标准时间(Greenwich Mean Time,GMT)之间的转换

Calendar Time

日历时间,通过time_t数据类型表示

表示的是“相对时间”,能够避免受到时区的影响,不同时区的日历时间都相同

time_t类型:

本质上是一个长整数,表示从1970-01-01 00:00:00到目前计时时间的秒数

定义如下:

struct tm
{
   int tm_sec;   // seconds after the minute - [0, 60] including leap second
   int tm_min;   // minutes after the hour - [0, 59]
   int tm_hour;  // hours since midnight - [0, 23]
   int tm_mday;  // day of the month - [1, 31]
   int tm_mon;   // months since January - [0, 11]
   int tm_year;  // years since 1900
   int tm_wday;  // days since Sunday - [0, 6]
   int tm_yday;  // days since January 1 - [0, 365]
   int tm_isdst; // daylight savings time flag
};

注意年份是相对于1900年

Coordinated Universal Time(UTC)

协调世界时,又称为世界标准时间,即格林威治标准时间(Greenwich Mean Time,GMT)

存在时区的差别,计算本地时间需要考虑时差

类型转换的c代码实例如下:

Calendar Time转换成GMT:

#include <stdio.h>
#include <time.h>
int main()
{
   __int64 CalTime = 1531788377;
   struct tm GmTime;
   char GmBuf[26];
   _gmtime64_s(&GmTime, &CalTime);
   strftime(GmBuf, 26, "%m/%d/%Y %r", &GmTime);
   printf("GmTime   :%s\n", GmBuf);
   return 0;
}

Calendar Time转换成本地时间(考虑时差):

#include <stdio.h>
#include <time.h>
int main()
{
   __int64 CalTime = 1531788377;
   struct tm LocalTime;
   char LocalBuf[26];
   _localtime64_s(&LocalTime, &CalTime);
   strftime(LocalBuf, 26, "%m/%d/%Y %r", &LocalTime);
   printf("LocalTime:%s\n",LocalBuf);
   return 0;
}

时间转换成Calendar Time:

#include <stdio.h>
#include <time.h>
time_t StringToDatetime(char *str)
{
   tm tm_;
   int year, month, day, hour, minute, second;
   sscanf_s(str, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);
   tm_.tm_year = year - 1900;
   tm_.tm_mon = month - 1;
   tm_.tm_mday = day;
   tm_.tm_hour = hour-1;
   tm_.tm_min = minute;
   tm_.tm_sec = second;
   tm_.tm_isdst = 0;
   time_t t_ = mktime(&tm_);
   return t_;
}
int main()
{
   time_t sec = StringToDatetime("2018-7-16 17:46:17");
   printf("\n%ld\n", sec);
   return 0;
}


0x04 程序实现细节

1、结构体定义

file header的定义可参考:

https://technet.microsoft.com/zh-cn/library/bb309024

event records的定义可参考:

https://technet.microsoft.com/zh-cn/library/aa363646

end of file record的定义可参考:

https://technet.microsoft.com/zh-cn/library/bb309022

注:

在程序实现上,为了避免重定义,我修改了event records的结构名

typedef struct _EVTLOGRECORD {
   DWORD Length;
   DWORD Reserved;
   DWORD RecordNumber;
   DWORD TimeGenerated;
   DWORD TimeWritten;
   DWORD EventID;
   WORD  EventType;
   WORD  NumStrings;
   WORD  EventCategory;
   WORD  ReservedFlags;
   DWORD ClosingRecordNumber;
   DWORD StringOffset;
   DWORD UserSidLength;
   DWORD UserSidOffset;
   DWORD DataLength;
   DWORD DataOffset;
} EVTLOGRECORD, *PEVTLOGRECORD;


2、筛选条件

end of file record的TimeGenerated为固定结构,值为0x33333333

在遍历过程中,如何遇到TimeGenerated为0x33333333,那么代表已经定位到end of file record,遍历结束


3、遍历方法

while (currentRecordPtr->TimeGenerated != 0x33333333)
{
       if (currentRecordPtr->TimeGenerated<StartTimeNum || currentRecordPtr->TimeGenerated>EndTimeNum)
       {      
           //not selected evt record,copy it
       }
       else
       {
           //delete record
       }
       currentRecordPtr = nextRecordPtr;
       nextRecordPtr = (PEVTLOGRECORD)((PBYTE)nextRecordPtr + nextRecordPtr->Length);
}


4、日志保存

通过读文件获得日志文件的完整内容,保存在数组中

如果删除中间的日志内容,需要删除数组中间某一段的内容

这里选择新定义一个数组,在遍历过程中,只复制满足条件的日志

我选择了使用memcpy优点是第一个参数可以指定起始地址


5、删除日志计数

统计删除日志的总数,后续日志的Record number作减法,减去已删除日志的总数

event records和end of file record的Last (newest) record number作减法,减去已删除日志的总数

完整代码已开源,下载地址:

https://github.com/3gstudent/Eventlogedit-evt--General/blob/master/evtDeleteRecordofFile.cpp

sys1.evt下载地址:

https://github.com/3gstudent/Eventlogedit-evt--General/blob/master/sys1.evt

程序读取文件sys1.evt,删除指定时间2018-7-16 17:46:17至2018-7-16 17:46:40之间的日志,共4条

生成文件sys2.evt和sys3.evt

sys2.evt未去掉trailing empty values

sys3.evt去掉trailing empty values


0x05 小结

本文介绍了删除evt文件指定时间段日志记录的思路和程序实现细节,开源代码,同evtx文件的删除方法存在很大区别

并且,删除当前系统指定指定时间段evt日志记录的方法同evtx也有很大区别,下篇将会详细介绍


源链接

Hacking more

...