0x00 Preface

---

The second article in the Windows XML Event Log (EVTX) single log deletion series introduces methods for deleting single log entries from specified EVTX files, addresses multiple design considerations in programming, and provides open-source implementation code.

0x01 Introduction

---

This article will cover the following topics:

  • Approach for deleting single log entries from specified EVTX files
  • Program implementation details
  • Open-source code

0x02 Approach for Deleting Single Log Entries from Specified EVTX Files

---

The previous article, 'Windows XML Event Log (EVTX) Single Log Deletion (Part 1) – Deletion Approach and Examples', explained the principles and an example of deleting single log entries from EVTX files by modifying log lengths.

The implementation approach is illustrated below:

Alt text

Note:

Image from https://blog.fox-it.com/2017/12/08/detection-and-recovery-of-nsas-covered-up-tracks/

This method is relatively simple to implement, but multiple different scenarios need to be considered:

  1. Delete intermediate log
  2. Delete the last log
  3. Delete the first log

0x03 Delete intermediate log

---

Method as follows:

  1. Decrease the Next record identifier value in the File header by 1
  2. Recalculate the Checksum in the File header
  3. Recalculate the previous log length, involving 2 positions (offset 4 and the last 4 bytes of the current log)
  4. Decrease the Event record identifier of subsequent logs by 1 sequentially
  5. Decrease the Last event record number in ElfChuk by 1
  6. Decrease the Last event record identifier in ElfChuk by 1
  7. Recalculate checksum of Event records in ElfChuk
  8. Recalculate checksum in ElfChuk

In program implementation, the specific details are as follows:

1. Decrement the Next record identifier value in File header by 1

Read log file content

Define log file format structure and parse the log file format

Decrement Next record identifier value by 1:

FileHeader->NextRecordIdentifier = FileHeader->NextRecordIdentifier-1

2. Recalculate the Checksum in File header

C code for calculating CRC checksum:

unsigned int CRC32[256];
static void init_table()
{
int i, j;
unsigned int crc;
for (i = 0; i < 256; i++)
{
crc = i;
for (j = 0; j < 8; j++)
{
if (crc & 1)
crc = (crc >> 1) ^ 0xEDB88320;
else
crc = crc >> 1;
}
CRC32[i] = crc;
}
}

unsigned int GetCRC32(unsigned char *buf, int len)
{
unsigned int ret = 0xFFFFFFFF;
int i;
static char init = 0;
if (!init)
{
init_table();
init = 1;
}
for (i = 0; i < len; i++)
{
ret = CRC32[((ret & 0xFF) ^ buf[i])] ^ (ret >> 8);
}
ret = ~ret;
return ret;
}

Calculate the checksum of the first 120 bytes of the File header

Code is as follows:

unsigned char *ChecksumBuf = new unsigned char[120];
memcpy(ChecksumBuf, (PBYTE)elfFilePtr, 120);
crc32 = GetCRC32(ChecksumBuf, 120);

3. Recalculate the length of the previous log, involving 2 positions (offset 4 and the last 4 bytes of the current log)

Locate Event Records one by one by searching for the magic string 0x2A 0x2A 0x00 0x00

(1) Locate the log to be deleted: CurrentRecord

Read the length, i.e., CurrentRecord->Size

(2) Locate the previous log: PrevRecord

Read the length, i.e., PrevRecord->Size

Calculate the merged length:

NewSize = CurrentRecord->Size + PrevRecord->Size

Update the length:

PrevRecord->Size = NewSize

(3) Locate the next log record NextRecord

Replace the 4 bytes before the starting point of NextRecord with NewSize:

*(PULONG)((PBYTE)NextRecord-4) = NewSize

4. Decrement the Event record identifier of subsequent logs by 1 sequentially

Traverse subsequent logs, decrementing the Event record identifier by 1 sequentially

Two locations need to be modified:

CurrentRecord->EventRecordIdentifier = CurrentRecord->EventRecordIdentifier-1
CurrentRecord->Template->EventRecordIdentifier = CurrentRecord->Template->EventRecordIdentifier-1

5. Decrement the Last event record number in ElfChuk by 1

ElfChuk->LastEventRecordNumber = ElfChuk->LastEventRecordNumber-1

6. Decrement the Last event record identifier in ElfChuk by 1

ElfChuk->LastEventRecordIdentifier = ElfChuk->LastEventRecordIdentifier-1

7. Recalculate the Event records checksum in ElfChuk

unsigned char *ChecksumBuf = new unsigned char[currentChunk->FreeSpaceOffset - 512];
memcpy(ChecksumBuf, (PBYTE)currentChunk+512, currentChunk->FreeSpaceOffset - 512);
crc32 = GetCRC32(ChecksumBuf, currentChunk->FreeSpaceOffset - 512);

8. Recalculate the Checksum in ElfChuk

unsigned char *ChecksumBuf = new unsigned char[504];
memcpy(ChecksumBuf, (PBYTE)currentChunk, 120);
memcpy(ChecksumBuf+120, (PBYTE)currentChunk+128, 384);
crc32 = GetCRC32(ChecksumBuf, 504);

0x04 Delete the last log entry

---

Deleting the last log entry was demonstrated in the previous article 'Windows XML Event Log (EVTX) Single Log Entry Deletion (Part 1) – Deletion Approach and Example'. The method is essentially the same as deleting a middle log entry.

The differences are as follows:

  1. The Event record identifier of subsequent logs does not need to be decremented by 1, as there are no subsequent logs.
  2. The Last event record data offset in ElfChuk needs to be recalculated.

The program details are as follows:

1. Recalculate the Last event record data offset in ElfChuk

ElfChuk->LastEventRecordDataOffset = ElfChuk->LastEventRecordDataOffset - LastRecord->Size

0x05 Delete the first log

---

The method of modifying log length is not applicable for deleting the first log, because there is no previous log to overwrite the current one

If you still want to achieve this using the overwrite length method, further analysis of the log file format is required

We know that the content of Event Records is stored in Binary XML format

For reference on Binary XML format:

https://github.com/libyal/libevtx/blob/master/documentation/Windows%20XML%20Event%20Log%20(EVTX).asciidoc#4-binary-xml

To merge logs by modifying the Binary XML format content, the following items need to be modified:

  • Written date and time
  • Template definition Data size
  • Next template definition offset

Note:

This method is also applicable for modifying middle logs and the last log, so understanding the log format means deletion methods are not unique

For other implementation details, refer to the open-source code at the following address:

`An open-source project

The code implements reading the specified log file c:\\test\\Setup.evtx, deleting a single log entry (EventRecordID=14), and saving it as a new log file c:\\test\\SetupNew.evtx

Note:

In the implementation details of the code, I referred to the demo code on KanXue, with the address as follows:

https://bbs.pediy.com/thread-219313.htm

0x06 Summary

---

This article introduces the approach and program implementation details for deleting a single log entry from an evtx file, with open-source code. The method for deleting a single log entry is not unique. Next, multiple methods for deleting a single log entry from the current system will be introduced.