Monday, September 17, 2012

MoVP 2.1 Atoms (The New Mutex), Classes and DLL Injection

Month of Volatility Plugins
In this post, we will discuss various ways you can analyze malware and understand infections by analyzing the atom tables. You'll be surprised that creating window classes, registering window messages, injecting DLLs with message hooks or event hooks all result in the creation of atoms in kernel memory. Thus today's MoVP 2.1 plugins are atomscan and atoms

Atoms are strings that can easily be shared between processes in the same session. However, instead of passing the actual string value, or performing string comparison operations, atom tables provide a simpler, faster implementation. In summary, one process adds an atom to an atom table by passing a string to a function such as AddAtom or GlobalAddAtom (or indirectly via one the APIs discussed shortly). The *AddAtom APIs return an integer identifier that the process or other processes can use to retrieve the string. An atom table is a hash bucket that contains the integer to string mappings. 

Atom tables are extremely interesting from a forensic perspective, because many Windows API functions create atoms without explicitly saying so. Malware authors use these APIs, but are not aware of the artifacts they leave on the system, thus they cannot try and cover up the tracks. Atoms even have a tendency to "stick around" longer than sometimes intended. For example, atoms have a reference count that is incremented and decremented automatically when they are added and deleted from the table. According to Microsoft’s About Atom Tables, string atoms remain in the atom table as long as the reference count is greater than zero, even after the application that placed it in the table terminates.

Data Structures

Atom tables are represented as _RTL_ATOM_TABLE structures.  As noted in Identifying Global Atom Table Leaks, the format of the structure is different in user mode than in kernel mode. When analyzing the session atom table (win32k!UserAtomTableHandle) and window station atom table (tagWINDOWSTATION.pGlobalAtomTable), we must be sure to use the kernel mode definition. 

The session atoms are accessible to all processes in the session. Processes can also create local atom tables accessible to only that process, but this post will not discuss the local tables. Below, the atom table and atom table entry structures for Windows 7 64-bit are shown. 

>>> dt("_RTL_ATOM_TABLE")
'_RTL_ATOM_TABLE' (112 bytes)
0x0   : Signature                      ['unsigned long']
0x8   : CriticalSection                ['_RTL_CRITICAL_SECTION']
0x18  : NumBuckets                     ['unsigned long']
0x20  : Buckets                        ['array', <function <lambda> at 0x10054c9b0>, ['pointer', ['_RTL_ATOM_TABLE_ENTRY']]]

>>> dt("_RTL_ATOM_TABLE_ENTRY")
'_RTL_ATOM_TABLE_ENTRY' (24 bytes)
0x0   : HashLink                       ['pointer64', ['_RTL_ATOM_TABLE_ENTRY']]
0x8   : HandleIndex                    ['unsigned short']
0xa   : Atom                           ['unsigned short']
0xc   : ReferenceCount                 ['unsigned short']
0xe   : Flags                          ['unsigned char']
0xf   : NameLength                     ['unsigned char']
0x10  : Name                           ['String', {'length': <function <lambda> at 0x10428b0c8>, 'encoding': 'utf16'}]

Key Points
  • Signature for an atom table is 0x6d6f7441 (Atom) and the structures exist in pools with tag AtmT. Together they provide a good initial pattern to scan for in physical memory. 
  • NumBuckets specifies the number of _RTL_ATOM_TABLE_ENTRY structures in the Buckets array. 
  • HashLink can be used to enumerate all atom entries in the bucket. 
  • Atom is the integer identifier for the atom table entry. This is the value returned by functions such as AddAtom and FindAtom
  • ReferenceCount is incremented each time the specified string is added to the atom table. Likewise, it is decremented each time it is deleted. 
  • Name is the string name of the atom. 
The AtomScan Plugin

The atomscan plugin locates atom tables in physical memory by searching for the pool tags and then performing sanity checks on the Signature and NameLength fields. The downside to this method is that there is no clear way to link an atom table to its owning session or window station (thus a second plugin, atoms, is also provided which is able to perform the association). Atoms are reported the order in which they were found, unless you specify --sort-by=atom (sorts by atom ID) or --sort-by=refcount (sorts by number of references to the atom). 

Here are some examples of how you can leverage atoms in your malware analysis and forensic investigations

1. Window class names. When applications call RegisterClassEx, win32k.sys creates an atom from the WNDCLASSEX.lpszClassName parameter. Some malware tries to be cute and creates blank window class names (" ") or uses non-ascii characters thinking no one will ever see them. You can see this happening in the disassembly below from a sample of Mutihack.


The output of the atomscan command shows a blank atom name:


$ python vol.py -f mutihack.vmem atomscan
AtomOfs(V)       Atom Refs   Pinned Name
---------- ---------- ------ ------ ----
[snip]
0xe179d850     0xc038      1      1 OleMainThreadWndClass
0xe17a7e40     0xc094      2      0 Shell_TrayWnd
0xe17c34b8     0xc0c4      2      0 UnityAppbarWindowClass
0xe17c7678     0xc006      1      1 FileName
0xe17d40a0     0xc0ff      2      0 
0xe17d4128     0xc027      1      1 SysCH
0xe17e78f0     0xc01c      1      1 ComboBox
0xe17e9070     0xc065     26      0 6.0.2600.6028!Combobox
0xe17ec350     0xc13e      1      0 Xaml
0xe18119c0     0xc08c      5      0 OM_POST_WM_COMMAND
[snip]

2. Registered window messages. Using the RegisterWindowMessage API results in the creation of an atom based on the string passed as an argument to the function. A classic example is shown below from a disassembly of the Clod malware. Registering the WM_HTML_GETOBJECT window message is one of the required steps to obtaining a fully marshaled IHTMLDocument2interface from an HWND. In other words, this is how Clod gains scriptable control over Internet Explorer – such as the ability to add/remove/modify DOM elements or inspect form variables upon submission (like credentials to banking sites).


3. Injected DLLs. Malware that uses SetWindowsHookEx or SetWinEventHook to inject a DLL into other processes will unknowingly create new atoms that identify the full path to the malicious library. It makes sense if you think about. Assume a malware process calls one of the hooking APIs and specifies "C:\windows\bad.dll" and then terminates. How does the system "remember" the DLL path when it comes time to load it in the other processes? Easy - the hooking APIs call through from user32.dll into win32k.sys and the kernel driver saves the string into the atom table. Take the example below from the Laqma malware:


As you can see in the disassembly, the HINSTANCE parameter to SetWindowsHookEx is a handle to the library C:\WINDOWS\system32\Dll.dll. Guess what shows up in the atom table?

$ python vol.py –f laqma.vmem atomscan
AtomOfs(V)       Atom Refs   Pinned Name
---------- ---------- ------ ------ ----
0xe1000d10     0xc001      1      1 USER32
0xe155e958     0xc002      1      1 ObjectLink
0xe100a308     0xc003      1      1 OwnerLink
0xe1518c00     0xc004      1      1 Native
0xe1b2aa88     0xc1b2      2      0 __axelsvc
0xe4bcb888     0xc1be      2      0 ShImgVw:CPreview
0xe11b0250     0xc1c1      2      0 __srvmgr32
0xe1f8bc30     0xc1c3      1      0 C:\WINDOWS\system32\psbase.dll
0xe28ed818     0xc1c7      1      0 BCGP_TEXT
0xe2950c98     0xc19f      1      0 ControlOfs01420000000000FC
0xe11d6290     0xc1a0      1      0 C:\WINDOWS\system32\Dll.dll
0xe1106380     0xc1a1      1      0 BCGM_ONCHANGE_ACTIVE_TAB
0xe11a5090     0xc1a2      1      0 ControlOfs01EE0000000003C8
[snip]

4. System presence marking. If you're not familiar with the importance of mutexes, see Lenny Zelter's Looking at Mutex Objects for Malware Discovery. Most likely though you've never heard of using atoms for malware discovery. Well guess what, now you have...and Volatility is the only only tool I know about (for live systems *or* physical memory analysis) that carves such structures. Below, you'll see a disassembly showing how Tigger uses atoms instead of mutexes. First, it calls GlobalFindAtomA to check if an atom named ~Sun Nov 16 15:46:54 2008~ exists on the machine. If so, the malware terminates, assuming it has already completed the infection. Otherwise, it calls GlobalAddAtomA to mark the machine infected. 


The next function enters a loop that looks for an atom named putas38 every 200 milliseconds. It will sleep forever if the atom is never created, so surely another thread creates the atom, which causes the code below to exit the loop. At that time, the malware proceeds to hook various API functions. 

Conclusion 

Atoms are inevitable artifacts of many USER and GDI API functions. They're created both directly and indirectly by malware more often than you realize. In the case when they're created indirectly (by creating class names, installing hooks, etc) there's a pretty good chance the malware authors have never heard of an atom - so this post should give you a competitive advantage in detection. For more information on atoms, see Extraordinary String Based Attacks: Smashing the Atom by Tarjei Mandt.

More information on the atomscan and atoms plugins and their uses in forensic investigations will be presented at Open Memory Forensics Workshop (OMFW) 2012

No comments:

Post a Comment