Monday, October 1, 2012

MoVP 4.1 Detecting Malware with GDI Timers and Callbacks

Month of Volatility Plugins 

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.

No comments:

Post a Comment