0x00 Preface

---

The second article in the Windows Event Viewer Log (EVT) Single Log Deletion series. It introduces the approach for deleting log records within a specified time range from an EVT file, addresses multiple design considerations in the program implementation, and provides open-source code.

0x01 Introduction

---

This article will cover the following topics:

  • Approach for deleting log records within a specified time range from a given EVT file
  • Program implementation details
  • Open-source code

0x02 Approach for Deleting Log Records within a Specified Time Range from an EVT File

---

Compared to the single log deletion method for EVTX files mentioned in previous articles, the same approach cannot be applied to EVT files.

This is because the EVT file structure does not include a unique value like EventRecordID, making it impossible to locate a specific log entry.

Through analysis, it was found that the log creation time can be used as an input parameter. By specifying a start date and an end date, the log content within that time range can be deleted.

The format of the log creation time is of type time_t, requiring consideration of the conversion between the time_t type and Greenwich Mean Time (GMT).

In terms of program implementation, the approach is as follows:

  • Traverse all logs, filter out those meeting deletion criteria, and save the remaining log content.
  • After filtering, subtract the number of deleted log entries from the Record numbers of subsequent logs.
  • Update the End of file record offset, Last (newest) record number, and Maximum file size in the file header.
  • Update the End of file record offset and Last (newest) record number in the end of file record.

0x03 Conversion between time_t type and Greenwich Mean Time (GMT).

---

Calendar Time

Calendar time, represented by the time_t data type.

Represents 'relative time,' which avoids being affected by time zones; calendar time is the same across different time zones.

time_t type:

Essentially a long integer, representing the number of seconds from 1970-01-01 00:00:00 to the current time.

Defined as follows:

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
};

Note that the year is relative to 1900

Coordinated Universal Time (UTC)

Coordinated Universal Time, also known as World Standard Time, i.e., Greenwich Mean Time (GMT)

There are time zone differences; calculating local time requires considering the time difference

Example C code for type conversion:

Convert Calendar Time to GMT:

#include
#include
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;
}

Convert Calendar Time to local time (considering time difference):

#include
#include
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;
}

Convert time to Calendar Time:

#include
#include
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 Program Implementation Details

---

1. Structure Definitions

File header definition can be referenced at:

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

Event records definition can be referenced at:

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

End of file record definition can be referenced at:

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

Note:

In the program implementation, to avoid redefinition, I modified the structure name of 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. Filter Conditions

The TimeGenerated field of the end of file record has a fixed structure with the value 0x33333333

During traversal, if TimeGenerated equals 0x33333333, it indicates the end of file record has been located and traversal should terminate

3. Traversal Method

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

4. Log Preservation

Obtain the complete content of the log file by reading the file and save it in an array

If deleting intermediate log content, it is necessary to remove a certain segment from the middle of the array

Here, the approach is to define a new array and, during traversal, only copy logs that meet the conditions

I chose to use memcpy; its advantage is that the first parameter can specify the starting address

5. Deleted Log Count

Count the total number of deleted logs, and subtract the total number of deleted logs from the Record number of subsequent logs

Subtract the total number of deleted logs from the Last (newest) record number of event records and the end of file record

The complete code has been open-sourced, download address:

`An open-source project

sys1.evt download address:

`An open-source project

The program reads the file sys1.evt, deletes logs within the specified time range from 2018-7-16 17:46:17 to 2018-7-16 17:46:40, totaling 4 entries

Generates files sys2.evt and sys3.evt

sys2.evt does not remove trailing empty values

sys3.evt removes trailing empty values

0x05 Summary

---

This article introduces the approach and implementation details for deleting log records within a specified time range in evt files, with open-source code, which differs significantly from the deletion methods for evtx files

Moreover, the method for deleting evt log records within a specified time range on the current system also differs greatly from that for evtx, which will be detailed in the next article