windows event logging

This article documents a recent part-time curiosity of mine; the Event Logging facility as implemented on the Windows platform. It is based on the many notes that I have made while exploring the subject and should give you a good understanding of the whole facility that provides the logging service.

Once we've gained an understanding of the facility we will be able to examine it from other more interesting viewpoints. I wrote this article with the interactive reader in mind and you will get the most out of it if you read it that way. Some of what i've written may not apply to all versions of windows (especially XP Home) and this article does not pretend to address issues faced by larger domain-based networks or even anything beyond the local computer.

Event logging, and more specifically the ability to perform security auditing is an integral part of a secure computing environment. It is also a part that windows users tend to neglect as security auditing is not enabled by default. In the following section I will quickly walk you through the steps to enable security logging on your box. So, for you guys who already know, please allow me a moment to help our friends secure their machines.

Using the run command run secpol.msc, double click Local Policies >> Audit Policy. Finally, select the Audit policies you want to enable or disable. You may want to look at logon attempts (Audit Logon Events - success / fail), changes in accounts (Audit account management - success / fail), unsuccessful use of privileges (Audit Privilege Use - fail), attempts to alter security privileges (audit Policy Change - success / fail) and attempts to shut down your computer (Audit System Events - success / fail). You may also want to monitor specific or critical files on your system (Audit object access).

To monitor a specific files right click on the file or folder you want to monitor, choose properties >> Security >> Advanced >> Auditing >> Add. Here you will choose who u want to watch and what you want to watch for.

At this point it is necessary for me to give a word of caution. Do not audit everything. Only audit the minimum requirements to see what you want to see. Experiment with this and research before you implement an auditing policy on a system to avoid flooding yourself with useless events.

Your next step is to set a retention policy on the machine - Using the run command run 'eventvwr', Right click Security Log, choose properties. You will see that the default retention policy is to overwrite events older than seven days. You will also see the default location of the log %SystemRoot%\System32\config\SecEvent.Evt and the maximum log size of 512 kb. You can choose to either use one of the provided policies or choose to automagically backup your logs once they've reached the defined maximum size. To do this you should add and use the AutoBackupLogFiles registry key by following the instructions provided in MSKB article 312571.

Now that we've seen how to turn on the Security Auditing feature of the Logs we will turn our attention to the more interesting aspect of this article - what is the Event Log and how does it do what it does?

We begin by examining our service closely with psservice:

D:\Program Files\Support Tools>psservice config eventlog

PsService v2.13 - Service information and configuration utility
Copyright (C) 2001-2004 Mark Russinovich
Sysinternals -

Logs event messages issued by programs and Windows.  Event Log reports
contain information that can be useful in diagnosing problems.  Reports
are viewed in Event Viewer.
        TYPE              : 20 WIN32_SHARE_PROCESS
        START_TYPE        : 2  AUTO_START
        ERROR_CONTROL     : 1  NORMAL
        BINARY_PATH_NAME  : C:\WINNT\system32\services.exe
        LOAD_ORDER_GROUP  : Event log
        TAG               : 0
        DISPLAY_NAME      : Event Log
        DEPENDENCIES      :
        SERVICE_START_NAME: LocalSystem

What do we learn here? Well, by looking at the service this way we begin to see how the event logging service works on Windows. To start with we see that the service shares process space with other services, we see that the application file that provides this service is "services.exe" (the Service Control Manager). We also see that this service runs under the LocalSystem account.

Because the Service Control Manager (services.exe) shares process space with other services (WIN32_SHARE_PROCESS) some limitations are imposed on the event log service. Under the current scheme all of the files running under this process share memory space and have a shared upward limit of one gig. In practical terms this means that you should limit the size of your logs to 300 megabytes each.

Why would the size of your logs affect the process space? The SCM (Service Control Manager) opens several files and keeps them open during it's operation. We can demonstrate this and see what files are loaded by services.exe with the program handle:

D:\tools>handle -p serv

Handle v3.11
Copyright (C) 1997-2005 Mark Russinovich
Sysinternals -

   18: File          C:\WINNT\system32
  290: File          C:\WINNT\system32\config\AppEvent.Evt
  2A0: File          C:\WINNT\system32\config\SecEvent.Evt
  2B0: File          C:\WINNT\system32\config\SysEvent.Evt
  3EC: File          C:\WINNT\system32\drivers\etc
  638: File          C:\$Extend\$ObjId
  64C: File          D:\System Volume Information\tracking.log
  6A8: File          D:
  6B0: File          D:\$Extend\$ObjId
  838: File          C:\System Volume Information\tracking.log
  868: File          C:

We see that services.exe has a few files open, which includes our event logs. This is one of the reasons you can't edit the event logs directly; they are already opened and locked by Services.exe.

Now, often when I look at windows I wonder where the actual code is that performs this function. I mean, it can't all be in the SCM can it? As it turns out, services.exe loads several dlls that are responsible for it's functionality. We'll use the tool listdlls to see this:

D:\tools>listdlls services.exe

ListDLLs v2.25 - DLL lister for Win9x/NT
Copyright (C) 1997-2004 Mark Russinovich
Sysinternals -

Command line: C:\WINNT\system32\services.exe

  Base        Size      Version         Path
  0x01000000  0x19000   5.00.2195.7035  C:\WINNT\system32\services.exe
  0x77f80000  0x7c000   5.00.2195.7006  C:\WINNT\system32\ntdll.dll
  0x7c2d0000  0x65000   5.00.2195.7038  C:\WINNT\system32\ADVAPI32.dll
  0x7c570000  0xb3000   5.00.2195.7006  C:\WINNT\system32\KERNEL32.dll
  0x77d30000  0x78000   5.00.2195.7020  C:\WINNT\system32\RPCRT4.dll
  0x76890000  0xf000    5.00.2195.7036  C:\WINNT\system32\eventlog.dll

We catch the obvious; the code that provides for the event logging service resides in eventlog.dll.

Can you picture what's happening here? It's the Service Control Manager (services.exe) who appears to be responsible for the event logging service. To provide for this functionality the SCM opens our event logs and loads eventlog.dll into memory so that it can receive the reports we send it and write them directly to the logs.

This simple picture applies to apps from userland. Apps that run in kernel mode do not report via the eventog api. Instead, they report via the NT I/O manager, which in turn reports to the event logging service.

How does windows know to start our service? The SCM (services.exe) maintains a database of services in your registry (this includes the eventlog). It uses this database to start each service according to its group. To find the Eventlog service entry in this database run regedit and navigate to HKLM \ SYSTEM \ CurrentControlSet \ Services \ Eventlog.

The information that is stored in this entry determines how the eventlog will function. You see, the event log service doesn't hold the messages the service receives, nor does it hold localized information. This information is held inside different dll's that are referenced from this entry and it's subentries. This makes the messages and localization information in the eventlog different from machine to machine and application specific. This is also one of the frustrations that make reconstruction of a binary EVT file so difficult. You can see this by examining the subkeys in this entry. Pay attention to EventMessageFile and CategoryMessageFile.

Now that we are done taking a look at how the process works, let's look at the way we can interact with the process so that we can learn a bit more about it. The easiest way to do this is by using the EventLog Class in .NET and in managed C++ (old syntax) this would involve:

    EventLog* review = new EventLog();
    review->Log = "Security";
    review->MachineName = ".";
    EventLogEntryCollection* reviewEntries = review->Entries;

You have to love .NET don't you? In five lines of code we can now work with the entries from the security event log. Unfortunately, those five lines do little to help our understanding of what's involved in opening the event log. To better understand this we should look at this process in terms of the API.

The first task windows does is open the event log and read it. It does this first by securing access to the event log with the OpenEventLog function. Then the handle to the eventlog (hEventLog in API speak) is passed to ReadEventLog. ReadEventLog must now sort out some details in the reading of the log (these are passed as parameters in the WinAPI). These details will include: how you want to read the log (sequentially from front to back or back to front or even starting from a certain record), what buffer you are going to write the log into and how many logs will fit into that buffer.

Each EventLog will be returned in its complete form. With the following structure which is defined in WINNT.H:

typedef struct _EVENTLOGRECORD {
    DWORD  Length;        // Length of full record
    DWORD  Reserved;      // Used by the service
    DWORD  RecordNumber;  // Absolute record number
    DWORD  TimeGenerated; // Seconds since 1-1-1970
    DWORD  TimeWritten;   // Seconds since 1-1-1970
    DWORD  EventID;
    WORD   EventType;
    WORD   NumStrings;
    WORD   EventCategory;
    WORD   ReservedFlags; // For use with paired events (auditing)
    DWORD  ClosingRecordNumber; // For use with paired events (auditing)
    DWORD  StringOffset;  // Offset from beginning of record
    DWORD  UserSidLength;
    DWORD  UserSidOffset;
    DWORD  DataLength;
    DWORD  DataOffset;    // Offset from beginning of record
    // Then follow:
    // WCHAR SourceName[]
    // WCHAR Computername[]
    // SID   UserSid
    // WCHAR Strings[]
    // BYTE  Data[]
    // CHAR  Pad[]
    // DWORD Length;

If everything in windows programming made sense we would think that this would be all we had to do to read the event log (and that's about the process in .NET). Just open it and read it. But it's not that simple when dealing with the API, you still have to calculate each event logs size, then you have to check the event log's external message files that may contain pertinent data. This data here:

    // Then follow:
    // WCHAR SourceName[]
    // WCHAR Computername[]
    // SID   UserSid
    // WCHAR Strings[]
    // BYTE  Data[]
    // CHAR  Pad[]
    // DWORD Length;

is not included in the eventlog structure. To get at this data we've got to go back to the registry (RegOpenKey) and look up (RegQueryValueEx) where our message file is located (you did take a look at EventMessageFile and CategoryMessageFile right?) and finally close the registry (RegCloseKey). Once we have the location of our EventMessageFile we've got to load it (LoadLibraryEx), format it so we can read it (FormatMessage) and close the .dll (FreeLibrary). As you can see retrieving the correct message file becomes quite a complicated process.

It's this complicated process that has those in forensics frustrated at this design. Remember, one of the primary rules in forensics is not to disturb the evidence. That means if you are investigating a system from a *nix platform you do not have the use of the Windows API, much less the abstraction of .NET. This complication of what could be a simple mechanism (think *nix syslog here) has researchers frustrated. This point was brought out in my correspondence with Tim from the GrokEvt project:

Microsoft can make even the simplest of tasks incredibly complex, and this holds true for the Windows logging architecture. The shameful effect of this complexity manifests itself in loss of reliability and integrity which a simpler system could easily achieve.
*The GrokEvt project is probably the best source of independent documentation on the windows event log binary format.

This entire process is pretty much encapsulated and made painless by the EventLogEntry Class and the EventLogEntryCollection Class in .NET. We see that the EventLogEntry Class takes care of everything, including getting the external message file and reconciling the associated User SID. The EventLogEntryCollection Class also provides a painless way to iterate through each entry or to copy all of the entries into an array. To illustrate we will extend our example:

for (i = reviewEntries->Count - 1; i >= 0; i--)
    if ((reviewEntries->Item[i]->EventID > 528 ) &&
		    (reviewEntries->Item[i]->EventID < 540) ||
		    (reviewEntries->Item[i]->EventID == 681))
        Console::WriteLine("EventID: {0} FAILED Login Attempt at {1}\n{2}",
                        reviewEntries->Item[i]->Message );
        Console::WriteLine("Viewing Entry No. {0} of {1}",
                        __box(i), __box(reviewEntries->Count));
*full example available here

Now, whenever I investigate a windows component I always like to think about any possible security issues or apparent weaknesses. There are a few obvious ways one could go about attacking the event log mechanism such as clearing the logs or flooding them with useless entries but both of these lack finesse and are sure to raise suspicion. I think it would be much smoother to try to infect the process (services.exe) then edit the logs directly.

You could also attack the event log mechanism indirectly. One might do this by switching their default location in the registry, phishing the logs. Another possiblity would be to crash the whole service, halting the event logging mechanism. This is easy to do if you have access. The method, originally described here and later pointed out in the neworder forums by even_a_monkey, only requires closing the smss.exe process and killing the Winlogon process tree (Process Explorer can do this easily and it encompasses the three tools I mentioned earlier). With services.exe shutdown there is no event logging service to record activities and the logs are no longer locked, you should be able to edit them directly.

Well, I think that's about all I have to write on the subject. It was my intention to demonstrate how the system works using methods and tools that would be useful in your own investigations. I hope you've enjoyed my ramblings and learned something in the process.

Tools and Links of Interest:

feedback? comment on livejournal