Task 194: .EVT File Format

Task 194: .EVT File Format

File Format Specifications for the .EVT File Format

The .EVT file format refers to the Windows Event Log format used in older versions of Windows operating systems (Windows 2000, XP, and 2003). It is a binary format for storing system, application, and security events. The file structure consists of a fixed-size header followed by variable-length event records. The specifications are derived from documented sources, including Kaitai Struct definitions and Microsoft documentation. The format uses little-endian byte ordering.

  1. List of all the properties of this file format intrinsic to its file system:

The properties are the fields in the file's header, which define the overall structure and state of the log file. These are intrinsic to the format and include:

  • Header Size (unsigned 4 bytes): The size of the header structure (fixed at 0x30).
  • Signature (string, 4 bytes): Magic identifier, must be "LfLe".
  • Major Version (unsigned 4 bytes): Major version of the log format.
  • Minor Version (unsigned 4 bytes): Minor version of the log format.
  • Start Offset (unsigned 4 bytes): Offset to the oldest record in the file.
  • End Offset (unsigned 4 bytes): Offset to the end-of-file record.
  • Current Record Number (unsigned 4 bytes): Index of the next record to be written.
  • Oldest Record Number (unsigned 4 bytes): Index of the oldest record in the file.
  • Max Size (unsigned 4 bytes): Maximum allowed size of the log file.
  • Flags (unsigned 4 bytes): Bit flags indicating file state, with sub-properties:
  • Dirty (bit 0): Indicates if the file was not properly closed.
  • Wrap (bit 1): Indicates if the log has wrapped (circular buffer mode).
  • Log Full (bit 2): Indicates if the last write failed due to the log being full.
  • Archive (bit 3): Indicates if the archive attribute is set.
  • Reserved (bits 4-31): Reserved for future use.
  • Retention (unsigned 4 bytes): Retention period for events in seconds.
  • End Header Size (unsigned 4 bytes): Repeated header size for verification (fixed at 0x30).

These properties are contained in the 48-byte header at the beginning of the file. Event records follow the header but are not considered "intrinsic" properties of the file system level; they are variable content.

  1. Two direct download links for files of format .EVT:

Upon thorough search, reliable direct download links for sample .EVT files are not readily available in public repositories or websites, as the format is outdated and samples are scarce. However, .EVT files can be obtained from legacy Windows systems (e.g., Windows XP virtual machines) by copying files such as SysEvent.evt from the %WINDIR%\system32\config directory. For illustrative purposes, parsers and tools that handle .EVT files can be found at the following repositories, which may include embedded test data:

  1. Ghost blog embedded HTML JavaScript for drag and drop .EVT file dump:

The following is a self-contained HTML page with embedded JavaScript that can be embedded in a Ghost blog post. It allows users to drag and drop a .EVT file, parses the header, and displays the properties on the screen.

.EVT File Parser
Drag and drop a .EVT file here
  1. Python class for .EVT file handling:

The following Python class can open a .EVT file, decode the header, read and print the properties to console, and write a new file with the same header (for demonstration; full write would require handling records).

import struct

class EvtFile:
    def __init__(self, filename=None):
        self.filename = filename
        self.properties = {}
        if filename:
            self.read()

    def read(self):
        with open(self.filename, 'rb') as f:
            header = f.read(48)
            self.properties = {
                'Header Size': struct.unpack('<I', header[0:4])[0],
                'Signature': header[4:8].decode('ascii'),
                'Major Version': struct.unpack('<I', header[8:12])[0],
                'Minor Version': struct.unpack('<I', header[12:16])[0],
                'Start Offset': struct.unpack('<I', header[16:20])[0],
                'End Offset': struct.unpack('<I', header[20:24])[0],
                'Current Record Number': struct.unpack('<I', header[24:28])[0],
                'Oldest Record Number': struct.unpack('<I', header[28:32])[0],
                'Max Size': struct.unpack('<I', header[32:36])[0],
                'Flags': struct.unpack('<I', header[36:40])[0],
                'Retention': struct.unpack('<I', header[40:44])[0],
                'End Header Size': struct.unpack('<I', header[44:48])[0]
            }

    def print_properties(self):
        for key, value in self.properties.items():
            print(f"{key}: {value}")
        print("Flags Details:")
        print(f" - Dirty: {bool(self.properties['Flags'] & 1)}")
        print(f" - Wrap: {bool(self.properties['Flags'] & 2)}")
        print(f" - Log Full: {bool(self.properties['Flags'] & 4)}")
        print(f" - Archive: {bool(self.properties['Flags'] & 8)}")

    def write(self, new_filename):
        with open(new_filename, 'wb') as f:
            header = struct.pack('<I', self.properties['Header Size']) + \
                     self.properties['Signature'].encode('ascii') + \
                     struct.pack('<I', self.properties['Major Version']) + \
                     struct.pack('<I', self.properties['Minor Version']) + \
                     struct.pack('<I', self.properties['Start Offset']) + \
                     struct.pack('<I', self.properties['End Offset']) + \
                     struct.pack('<I', self.properties['Current Record Number']) + \
                     struct.pack('<I', self.properties['Oldest Record Number']) + \
                     struct.pack('<I', self.properties['Max Size']) + \
                     struct.pack('<I', self.properties['Flags']) + \
                     struct.pack('<I', self.properties['Retention']) + \
                     struct.pack('<I', self.properties['End Header Size'])
            f.write(header)
            # Note: This writes only the header; full implementation would append records.

# Example usage:
# evt = EvtFile('sample.evt')
# evt.print_properties()
# evt.write('new.evt')
  1. Java class for .EVT file handling:

The following Java class can open a .EVT file, decode the header, read and print the properties to console, and write a new file with the same header.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class EvtFile {
    private String filename;
    private int headerSize;
    private String signature;
    private int majorVersion;
    private int minorVersion;
    private int startOffset;
    private int endOffset;
    private int currentRecordNumber;
    private int oldestRecordNumber;
    private int maxSize;
    private int flags;
    private int retention;
    private int endHeaderSize;

    public EvtFile(String filename) throws IOException {
        this.filename = filename;
        read();
    }

    private void read() throws IOException {
        try (FileInputStream fis = new FileInputStream(filename)) {
            byte[] header = new byte[48];
            fis.read(header);
            ByteBuffer bb = ByteBuffer.wrap(header).order(ByteOrder.LITTLE_ENDIAN);
            headerSize = bb.getInt(0);
            signature = new String(header, 4, 4);
            majorVersion = bb.getInt(8);
            minorVersion = bb.getInt(12);
            startOffset = bb.getInt(16);
            endOffset = bb.getInt(20);
            currentRecordNumber = bb.getInt(24);
            oldestRecordNumber = bb.getInt(28);
            maxSize = bb.getInt(32);
            flags = bb.getInt(36);
            retention = bb.getInt(40);
            endHeaderSize = bb.getInt(44);
        }
    }

    public void printProperties() {
        System.out.println("Header Size: " + headerSize);
        System.out.println("Signature: " + signature);
        System.out.println("Major Version: " + majorVersion);
        System.out.println("Minor Version: " + minorVersion);
        System.out.println("Start Offset: " + startOffset);
        System.out.println("End Offset: " + endOffset);
        System.out.println("Current Record Number: " + currentRecordNumber);
        System.out.println("Oldest Record Number: " + oldestRecordNumber);
        System.out.println("Max Size: " + maxSize);
        System.out.println("Flags: " + flags);
        System.out.println("Retention: " + retention);
        System.out.println("End Header Size: " + endHeaderSize);
        System.out.println("Flags Details:");
        System.out.println(" - Dirty: " + ((flags & 1) != 0));
        System.out.println(" - Wrap: " + ((flags & 2) != 0));
        System.out.println(" - Log Full: " + ((flags & 4) != 0));
        System.out.println(" - Archive: " + ((flags & 8) != 0));
    }

    public void write(String newFilename) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(newFilename)) {
            ByteBuffer bb = ByteBuffer.allocate(48).order(ByteOrder.LITTLE_ENDIAN);
            bb.putInt(headerSize);
            bb.position(4);
            bb.put(signature.getBytes());
            bb.putInt(majorVersion);
            bb.putInt(minorVersion);
            bb.putInt(startOffset);
            bb.putInt(endOffset);
            bb.putInt(currentRecordNumber);
            bb.putInt(oldestRecordNumber);
            bb.putInt(maxSize);
            bb.putInt(flags);
            bb.putInt(retention);
            bb.putInt(endHeaderSize);
            fos.write(bb.array());
            // Note: This writes only the header; full implementation would append records.
        }
    }

    // Example usage:
    // public static void main(String[] args) throws IOException {
    //     EvtFile evt = new EvtFile("sample.evt");
    //     evt.printProperties();
    //     evt.write("new.evt");
    // }
}
  1. JavaScript class for .EVT file handling:

The following JavaScript class can open a .EVT file (using Node.js File System), decode the header, read and print the properties to console, and write a new file with the same header.

const fs = require('fs');

class EvtFile {
    constructor(filename) {
        this.filename = filename;
        this.properties = {};
        if (filename) {
            this.read();
        }
    }

    read() {
        const buffer = fs.readSync(fs.openSync(this.filename, 'r'), Buffer.alloc(48), 0, 48, 0);
        const dataView = new DataView(buffer.buffer);
        this.properties = {
            'Header Size': dataView.getUint32(0, true),
            'Signature': String.fromCharCode(buffer[4], buffer[5], buffer[6], buffer[7]),
            'Major Version': dataView.getUint32(8, true),
            'Minor Version': dataView.getUint32(12, true),
            'Start Offset': dataView.getUint32(16, true),
            'End Offset': dataView.getUint32(20, true),
            'Current Record Number': dataView.getUint32(24, true),
            'Oldest Record Number': dataView.getUint32(28, true),
            'Max Size': dataView.getUint32(32, true),
            'Flags': dataView.getUint32(36, true),
            'Retention': dataView.getUint32(40, true),
            'End Header Size': dataView.getUint32(44, true)
        };
    }

    printProperties() {
        console.log(this.properties);
        console.log('Flags Details:');
        console.log(' - Dirty: ' + !!(this.properties.Flags & 1));
        console.log(' - Wrap: ' + !!(this.properties.Flags & 2));
        console.log(' - Log Full: ' + !!(this.properties.Flags & 4));
        console.log(' - Archive: ' + !!(this.properties.Flags & 8));
    }

    write(newFilename) {
        const buffer = Buffer.alloc(48);
        const dataView = new DataView(buffer.buffer);
        dataView.setUint32(0, this.properties['Header Size'], true);
        buffer.write(this.properties['Signature'], 4, 4, 'ascii');
        dataView.setUint32(8, this.properties['Major Version'], true);
        dataView.setUint32(12, this.properties['Minor Version'], true);
        dataView.setUint32(16, this.properties['Start Offset'], true);
        dataView.setUint32(20, this.properties['End Offset'], true);
        dataView.setUint32(24, this.properties['Current Record Number'], true);
        dataView.setUint32(28, this.properties['Oldest Record Number'], true);
        dataView.setUint32(32, this.properties['Max Size'], true);
        dataView.setUint32(36, this.properties['Flags'], true);
        dataView.setUint32(40, this.properties['Retention'], true);
        dataView.setUint32(44, this.properties['End Header Size'], true);
        fs.writeFileSync(newFilename, buffer);
        // Note: This writes only the header; full implementation would append records.
    }
}

// Example usage:
// const evt = new EvtFile('sample.evt');
// evt.printProperties();
// evt.write('new.evt');
  1. C class for .EVT file handling:

The following C code uses a struct (since C does not have classes in the same way) with functions to open a .EVT file, decode the header, read and print the properties to console, and write a new file with the same header.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

struct EvtProperties {
    uint32_t header_size;
    char signature[5]; // 4 bytes + null terminator
    uint32_t major_version;
    uint32_t minor_version;
    uint32_t start_offset;
    uint32_t end_offset;
    uint32_t current_record_number;
    uint32_t oldest_record_number;
    uint32_t max_size;
    uint32_t flags;
    uint32_t retention;
    uint32_t end_header_size;
};

void read_evt(const char* filename, struct EvtProperties* props) {
    FILE* f = fopen(filename, "rb");
    if (!f) {
        perror("Error opening file");
        exit(1);
    }
    uint8_t header[48];
    fread(header, 1, 48, f);
    fclose(f);

    props->header_size = *(uint32_t*)(header + 0);
    strncpy(props->signature, (char*)(header + 4), 4);
    props->signature[4] = '\0';
    props->major_version = *(uint32_t*)(header + 8);
    props->minor_version = *(uint32_t*)(header + 12);
    props->start_offset = *(uint32_t*)(header + 16);
    props->end_offset = *(uint32_t*)(header + 20);
    props->current_record_number = *(uint32_t*)(header + 24);
    props->oldest_record_number = *(uint32_t*)(header + 28);
    props->max_size = *(uint32_t*)(header + 32);
    props->flags = *(uint32_t*)(header + 36);
    props->retention = *(uint32_t*)(header + 40);
    props->end_header_size = *(uint32_t*)(header + 44);
}

void print_properties(const struct EvtProperties* props) {
    printf("Header Size: %u\n", props->header_size);
    printf("Signature: %s\n", props->signature);
    printf("Major Version: %u\n", props->major_version);
    printf("Minor Version: %u\n", props->minor_version);
    printf("Start Offset: %u\n", props->start_offset);
    printf("End Offset: %u\n", props->end_offset);
    printf("Current Record Number: %u\n", props->current_record_number);
    printf("Oldest Record Number: %u\n", props->oldest_record_number);
    printf("Max Size: %u\n", props->max_size);
    printf("Flags: %u\n", props->flags);
    printf("Retention: %u\n", props->retention);
    printf("End Header Size: %u\n", props->end_header_size);
    printf("Flags Details:\n");
    printf(" - Dirty: %d\n", (props->flags & 1) != 0);
    printf(" - Wrap: %d\n", (props->flags & 2) != 0);
    printf(" - Log Full: %d\n", (props->flags & 4) != 0);
    printf(" - Archive: %d\n", (props->flags & 8) != 0);
}

void write_evt(const char* new_filename, const struct EvtProperties* props) {
    FILE* f = fopen(new_filename, "wb");
    if (!f) {
        perror("Error opening file for writing");
        exit(1);
    }
    uint8_t header[48] = {0};
    *(uint32_t*)(header + 0) = props->header_size;
    strncpy((char*)(header + 4), props->signature, 4);
    *(uint32_t*)(header + 8) = props->major_version;
    *(uint32_t*)(header + 12) = props->minor_version;
    *(uint32_t*)(header + 16) = props->start_offset;
    *(uint32_t*)(header + 20) = props->end_offset;
    *(uint32_t*)(header + 24) = props->current_record_number;
    *(uint32_t*)(header + 28) = props->oldest_record_number;
    *(uint32_t*)(header + 32) = props->max_size;
    *(uint32_t*)(header + 36) = props->flags;
    *(uint32_t*)(header + 40) = props->retention;
    *(uint32_t*)(header + 44) = props->end_header_size;
    fwrite(header, 1, 48, f);
    fclose(f);
    // Note: This writes only the header; full implementation would append records.
}

// Example usage:
// int main() {
//     struct EvtProperties props;
//     read_evt("sample.evt", &props);
//     print_properties(&props);
//     write_evt("new.evt", &props);
//     return 0;
// }