Microsoft Windows timer objects provide a means to execute code at a certain time or in a periodic interval. From analyzing timers we can make some assumptions about a system's future.
A couple of weeks ago Jamie Levy had presented Timeliner, a set of Volatility plugins that builds a timeline of past events from volatile data. Michael Hale Ligh recently published another plugin for Volatility, that enumerates Windows kernel timer objects. He uses timers to locate hidden kernel modules. I'd like to extend and combine their work by decoding the DueTime member of the KTIMER structure. This could help in extending a timeline into the system's future.
If you look closely at the output of Michael's plugin, and also at Mattieu Suiche's debugger script, you will notice the timer's 64bit DueTime, formatted as a pair of two 32bit integers. A correlation between DueTime and time of the real world may not be obvious.
When we deal with timed events, two time scales are important: SystemTime reflects the date and time of the outside world, or the wall clock. However, most internal activity refers to InterruptTime, which starts at boot up and hence reflects the system's uptime. Both scales measure the time in units of 100 ns and express them as 64bit integers (see FILETIME). The current value of both time scales can be found in SharedUserData:
kd> ? SharedUserData Evaluate expression: 2147352576 = 7ffe0000 kd> dt -r _KUSER_SHARED_DATA 7ffe0000 nt!_KUSER_SHARED_DATA +0x000 TickCountLow : 0x19c7a +0x004 TickCountMultiplier : 0xfa00000 +0x008 InterruptTime : _KSYSTEM_TIME 0x3`d76bb6e4 +0x000 LowPart : 0xd76bb6e4 +0x004 High1Time : 0n3 +0x008 High2Time : 0n3 +0x014 SystemTime : _KSYSTEM_TIME 0x1C6846E`81004d6c +0x020 TimeZoneBias : _KSYSTEM_TIME 0xffffffef`3c773000 ...
It is easy to convert SystemTime into a human-readable format
kd> !filetime 0x1C6846E`81004d6c 5/31/2006 04:55:57.218 (UTC)
Now let's have a look at some kernel timers. Here is a simple example to start with:
kd> dt -r _KTIMER 80e30498 ntdll!_KTIMER +0x000 Header : _DISPATCHER_HEADER +0x000 Type : 0x8 '' +0x001 Absolute : 0 '' +0x002 Size : 0xa '' +0x003 Inserted : 0x1 '' +0x004 SignalState : 0n0 +0x008 WaitListHead : _LIST_ENTRY [ 0x80e30460 - 0x80e30460 ] +0x010 DueTime : _ULARGE_INTEGER 0x3`db256384 +0x000 LowPart : 0xdb256384 +0x004 HighPart : 3 +0x000 QuadPart : 0x3`db256384 +0x018 TimerListEntry : _LIST_ENTRY [ 0x80e26a10 - 0x80542690 ] +0x020 Dpc : (null) +0x024 Period : 0n0
Kernel Timers are waitable objects, hence the KTIMER structure starts with a DISPATCHER_HEADER. A Type of 8 identifies a notification timer. The timer has been inserted into the list of timers, so it is active. DueTime refers to the InterruptTime scale. In order to convert it into a human-readable time stamp, we subtract the current InterruptTime as shown in shared user data, and then add the corresponding SystemTime from the same structure. Finally, we interpret the resulting value as a FILETIME.
kd> !filetime (0x3`db256384 - 0x3`d76bb6e4 + 0x1C6846E`81004d6c) 5/31/2006 04:56:03.468 (UTC)
This timer was set to expire May 31st, 2006 at 04:56 UTC.
During an investigation I take a closer look at timers that are set to expire hours or even days in the future. One common example for this class of timers is the "time bomb" that uninstalls a trojan horse after a couple of days after it had searched through the user's documents and exfiltrated matching data.
Timers can be configured to periodically trigger an action. This can be seen in the following example.
kd> dt -r _KTIMER 80540d70 ntdll!_KTIMER +0x000 Header : _DISPATCHER_HEADER +0x000 Type : 0x8 '' +0x001 Absolute : 0 '' +0x002 Size : 0xa '' +0x003 Inserted : 0x1 '' +0x004 SignalState : 0n1 +0x008 WaitListHead : _LIST_ENTRY [ 0x80540d78 - 0x80540d78 ] +0x010 DueTime : _ULARGE_INTEGER 0x3`e9711d2a +0x018 TimerListEntry : _LIST_ENTRY [ 0x80542688 - 0x80542688 ] +0x020 Dpc : 0x80540d98 _KDPC +0x000 Type : 0n19 +0x002 Number : 0 '' +0x003 Importance : 0x1 '' +0x004 DpcListEntry : _LIST_ENTRY [ 0x0 - 0x0 ] +0x00c DeferredRoutine : 0x804ef844 void nt!IopIrpStackProfilerTimer+0 +0x010 DeferredContext : 0x80540d20 Void +0x014 SystemArgument1 : (null) +0x018 SystemArgument2 : (null) +0x01c Lock : (null) +0x024 Period : 0n60000
Note that Period in this example is greater than zero. This timer will invoke the DeferredRoutine every 60 seconds.
We can calculate the time of the next occurrence, using the same formula as before:
kd> !filetime (0x3`e9711d2a - 0x3`d76bb6e4 + 0x1C6846E`81004d6c) 5/31/2006 04:56:27.453 (UTC)
Periodic timers may lead you to critical parts of a software or system. During investigations, I've seen "watchdog" type code, that re-infects a partly disinfected system, or code that periodically exfiltrates data.
The timer in the next example is set to expire at the end of the century, at 12/31/2099 23:00:00.001 UTC, which is 01/01/2100 00:00:00.001 local time. Was this intended by the programmer?
kd> dt -r _KTIMER 80546660 ntdll!_KTIMER +0x000 Header : _DISPATCHER_HEADER +0x000 Type : 0x8 '' +0x001 Absolute : 0x1 '' +0x002 Size : 0xa '' +0x003 Inserted : 0x1 '' +0x004 SignalState : 0n0 +0x008 WaitListHead : _LIST_ENTRY [ 0x80546668 - 0x80546668 ] +0x010 DueTime : _ULARGE_INTEGER 0x68ece8`0a46c088 +0x018 TimerListEntry : _LIST_ENTRY [ 0x805427a0 - 0x805466f8 ] +0x020 Dpc : 0x805466a0 _KDPC +0x000 Type : 0n19 +0x002 Number : 0 '' +0x003 Importance : 0x1 '' +0x004 DpcListEntry : _LIST_ENTRY [ 0x0 - 0x0 ] +0x00c DeferredRoutine : 0x805256c6 void nt!ExpCenturyDpcRoutine+0 +0x010 DeferredContext : (null) +0x014 SystemArgument1 : (null) +0x018 SystemArgument2 : (null) +0x01c Lock : (null) +0x024 Period : 0n0
Our first indicator is the name that is associated with the DeferredRoutine: ExpCenturyDpcRoutine. If you examine the Header carefully you will notice that Absolute is different from null.
As we've seen before, InterruptTime is a steadily increasing counter. Even changing the system's clock affects only the difference between InterruptTime and SystemTime, but not InterruptTime in itself. The majority of timer objects are relative to the InterruptTime scale; the corresponding parameter to SetTimer/SetTimerEx is negative.
By calling SetTimer/SetTimerEx with a non-negative FILETIME, the programmer binds the timer's DueTime to the SystemTime scale. Whenever the system's clock gets adjusted, Windows has to adjust these timers as well. In order to recognize the proper timers, Windows maintains the Absolute property in the object's header.
Beside a handler routine for the dawn of a new century you should also find a timer that triggers ExpTimeZoneDpcRoutine whenever daylight saving time starts and ends.
In a forensic examination, an "absolute" timer indicates the programmer's will to tie an event to the real world's clock. Understanding the meaning of that specific date and time to the programmer may become the key to your investigation and reveal the programmer's motive.
Overly large DueTime
During your investigation you are likely to stumble upon overly large DueTimes. The corresponding timer would expire in a few thousand years and WinDbg refuses to convert the date at all.
The value 0x0fffffff`ffffffff interpreted as FILETIME is 06/18/5254 21:21:00. So, one could use the higher bits as flags without problems. I noticed that any offending DueTimes have their most significant nibble set to 0x8. But what does this flag indicate?
I think it could be kind of a "parking brake". By turning the flag on, the timer's expiration would be effectively prevented. The original DueTime is still preserved, so the timer could be reactivated at any time (possibly leading to instant removal from the list, if DueTime has passed).
Here is an example:
kd> dt -r _KTIMER ffb7f500 ntdll!_KTIMER +0x000 Header : _DISPATCHER_HEADER +0x000 Type : 0x8 '' +0x001 Absolute : 0 '' +0x002 Size : 0xa '' +0x003 Inserted : 0x1 '' +0x004 SignalState : 0n0 +0x008 WaitListHead : _LIST_ENTRY [ 0xffb7f508 - 0xffb7f508 ] +0x010 DueTime : _ULARGE_INTEGER 0x80000000`50c86d74 +0x018 TimerListEntry : _LIST_ENTRY [ 0xff67d128 - 0x80542840 ] +0x020 Dpc : 0xffb7f558 _KDPC +0x000 Type : 0n19 +0x002 Number : 0 '' +0x003 Importance : 0x1 '' +0x004 DpcListEntry : _LIST_ENTRY [ 0x340030 - 0x260033 ] +0x00c DeferredRoutine : 0x80525b0c void nt!ExpTimerDpcRoutine+0 +0x010 DeferredContext : 0xffb7f500 Void +0x014 SystemArgument1 : 0x00330030 Void +0x018 SystemArgument2 : 0x0033005c Void +0x01c Lock : (null) +0x024 Period : 0n0
The unmasked DueTime is
0x80000000`50c86d74 && 0x80000000`00000000 =
kd> !filetime ( 0x0`50c86d74 - 0x3`d76bb6e4 + 0x1C6846E`81004d6c) 5/31/2006 04:30:42.843 (UTC)
Please note that the original DueTime is earlier than the current system time.