Nearly a year ago, Volatility became the first (and to this date, the only) memory forensics framework to analyze kernel timers for malware analysis. The timers plugin was introduced in two of my older blog posts: ZeroAccess, Volatility, and Kernel Timers and Ain't Nuthin But a K(Timer) Thing Baby! Today's MoVP introduces yet another new feature exclusive to Volatility that involves a different type of timer - GDI Timers. These timers can be set from user mode GUI applications and associated with a callback function that executes when the time elapses. As you'll see in this post, malware often uses these timers to schedule routine downloads, make sure processes stay hidden, and various other tasks that require constant or routine attention.
GDI Timers
The Windows API function SetTimer can be used by GUI applications to receive notification when a specified time elapses. When the timer expires, the system either calls an application-defined callback function (if one is provided as the lpTimerFunc argument) or it posts a WM_TIMER message to the application’s queue. The queue handler would then process the WM_TIMER message and perform the desired action.
From a forensic standpoint, timers are useful because they’re often used in place of simple while loops that use Sleep to perform actions at regular intervals. The difference is that SetTimer leaves obvious artifacts in GUI memory and while loops do not. Specifically, by analyzing timers, you can identify the process ID and thread ID that set the timer, the rate (initial time-out value in milliseconds), the countdown (milliseconds left before the timer expires), the window associated with the timer, and the address of the callback function.
Data Structures
The main structure for a GUI timer is tagTIMER. Microsoft does not document these structures or provide them in PDB files, so small portions were taken from the ReactOS source code and the rest was reverse engineered from win32k.sys binaries. The one shown below is for Windows 7 x64:
>>> dt("tagTIMER")
'tagTIMER' (None bytes)
0x0 : head ['_HEAD']
0x18 : ListEntry ['_LIST_ENTRY']
0x20 : pti ['pointer', ['tagTHREADINFO']]
0x28 : spwnd ['pointer', ['tagWND']]
0x30 : nID ['unsigned short']
0x38 : cmsCountdown ['unsigned int']
0x3c : cmsRate ['unsigned int']
0x40 : flags ['Flags', {'bitmap': {'TMRF_SYSTEM': 1, 'TMRF_ONESHOT': 4, 'TMRF_RIT': 2, 'TMRF_READY': 0, 'TMRF_WAITING': 5, 'TMRF_TIFROMWND': 6, 'TMRF_INIT': 3}}]
0x48 : pfn ['pointer', ['void']]
Key Points
- pti can be used to identify the process and thread that owns the timer
- spwnd is the window associated with the timer (can be NULL)
- nID is the unique ID assigned to the timer (returned by SetTimer).
- cmsCountdown is the number of milliseconds left before the timer expires
- cmsRate is the initial time-out value, in milliseconds. The uElapse argument to SetTimer is copied into this field.
- pfn is a pointer to the callback function (the lpTimerFunc argument to SetTimer). You can disassemble this address to determine what happens when a timer expires.
The GDITimers Plugin
GDI Timers are USER objects, so we can iterate through the USER handle table and capture TYPE_TYPER. The figure below shows a disassembly of malware setting a timer with ID 161h. As a result, the system will call TimerFuncHideProcess every 3 seconds. The objective is to continuously check and make sure one of the malware’s processes stays hidden.
In the next example, the image shows the same malware using SetTimer with ID 2EBh. The purpose of this one is to ensure the function TimerFuncHttpDownload is executed every uElapse seconds (passed as an argument, so it can vary). The callback function contacts the malware’s command and control server, so it makes sense that the attackers would want to do it more than once – in case the server is offline during the first attempt.
Analysts can detect these artifacts using the gditimers plugin (not to be confused with the original timers plugin, which explores kernel/executive timers). In the output below, two timers should immediately draw your attention: IDs 2EBh and 161h – because that’s what we saw in the IDA disassembly.
$ python vol.py -f laqma.vmem gditimers
Volatile Systems Volatility Framework 2.1_alpha
Thread Process nID Rate(ms) Countdown(ms) Func
-------- -------------------- ---------- ---------- ------------- ----------
696 csrss.exe:660 0x7ffe 1000 734 0xbf8012b8
1648 explorer.exe:1624 0x15 60000 45109 0x00000000
1480 svchost.exe:1064 0x7476 60000 16234 0x74f51070
696 csrss.exe:660 0x7ffd 35000 25625 0xbf8f4d9a
1648 explorer.exe:1624 0x19 86400000 70004672 0x00000000
1764 VMwareTray.exe:1760 0x0 5000 4859 0x00000000
1648 explorer.exe:1624 0xe 43200000 26805359 0x00000000
1764 VMwareTray.exe:1760 0x11 60000 45859 0x00000000
700 csrss.exe:660 0xfff5 100 100 0xbf807d00
356 svchost.exe:1064 0x0 300000 131234 0x77532ebb
2024 lanmanwrk.exe:920 0x2eb 600000 589578 0x00401fc8
2024 lanmanwrk.exe:920 0x161 3000 1578 0x004010aa
1648 explorer.exe:1624 0x0 60000 11922 0x00000000
384 KernelDrv.exe:352 0x8b 600000 595359 0x00404c2b
384 KernelDrv.exe:352 0x8c 3000 1359 0x004010aa
384 KernelDrv.exe:352 0xd 2000 1359 0x00410850
You might also notice from the plugin’s output that for ID 161h, there are 1578 milliseconds left until the next time the function at 0x004010aa executes. Interestingly, there are not only several legitimate timers set by explorer.exe and csrss.exe, but KernelDrv.exe (another Laqma component) also sets timers. For what purpose? That’s when you disassemble code at the specified TimerFunc callback and figure out.
Conclusion
To get a competitive edge over detecting advanced malware, learn your kernel better than the attackers. Be familiar with the side effects of API calls and know how to associate evidence you see in memory with the conditions which elicited them. Sit back and wait for someone to be creative and use a GDI timer instead of Sleep loop....
More information on the gditimers plugin and its usages in forensic investigations will be presented at Open Memory Forensics Workshop (OMFW) 2012.
More information on the gditimers plugin and its usages in forensic investigations will be presented at Open Memory Forensics Workshop (OMFW) 2012.
No comments:
Post a Comment