Detecting Behavior

 < Day Day Up > 

Detecting behavior is a promising new area in rootkit detection. It is perhaps the most powerful. The goal of this technique is to catch the operating system in a "lie." If you find an API that returns values you know to be false, not only have you identified the presence of a rootkit, but you have also identified what the rootkit is trying to hide. The behavior you are looking for is the lie. A caveat to this is that you must be able to determine what the "truth" is without relying upon the API you are checking.

Detecting Hidden Files and Registry Keys

Mark Russinovich and Bryce Cogswell have released a tool called Rootkit-Revealer.[7] It can detect hidden Registry entries as well as hidden files. To determine what the "truth" is, RootkitRevealer parses the files that correspond to the different Registry hives without the aide of the standard Win32 API calls, such as RegOpenKeyEx and RegQueryValueEx. It also parses the file system at a very low level, avoiding the typical API calls. RootkitRevealer then calls the highest level APIs to compare the result with what it knows to be true. If a discrepancy is found, the behavior of the rootkit (and, hence, what it is hiding) is identified. This technique is fairly straightforward, yet very powerful.

[7] B. Cogswell and M. Russinovich, RootkitRevealer, available at:

Detecting Hidden Processes

Hidden processes and files are some of the most common threats you will face. A hidden process is particularly threatening because it represents code running on your system that you are completely unaware of. In this section, you will learn different ways to detect processes the attacker does not want you to see.

Hooking SwapContext

Hooking functions is useful during detection. The SwapContext function in ntoskrnl.exe is called to swap the currently running thread's context with the thread's context that is resuming execution. When SwapContext has been called, the value contained in the EDI register is a pointer to the next thread to be swapped in, and the value contained in the ESI register is a pointer to the current thread, which is about to be swapped out. For this detection method, replace the preamble of SwapContext with a five-byte unconditional jump to your detour function. Your detour function should verify that the KTHREAD of the thread to be swapped in (referenced by the EDI register) points to an EPROCESS block that is appropriately linked to the doubly linked list of EPROCESS blocks. With this information, you can find a process that was hidden using the DKOM tricks outlined in Chapter 7, Direct Kernel Object Manipulation. The reason this works is that scheduling in the kernel is done on a thread basis, as you will recall, and all threads are linked to their parent processes. This detection technique was first documented by James Butler et. al.[8]

[8] J. Butler et al., "Hidden Processes: The Implication for Intrusion Detection," Proceedings of the IEEE Workshop on Information Assurance (United States Military Academy, West Point, NY), June 2003.

Alternatively, you could use this method to detect processes hidden by hooking. By hooking SwapContext, you get the true list of processes. You can then compare this data with that returned by the APIs used to list processes, such as the NtQuerySystemInformation function that was hooked in the section Hooking the System Service Descriptor Table in Chapter 4.

Different Sources of Process Listings

There are ways to list the processes on the system other than going through the ZwQuerySystemInformation function. DKOM and hooking tricks will fool this API. However, a simple alternative like listing the ports with netstat.exe may reveal a hidden process, because it has a handle to a port open. We discuss using netstat.exe in Chapter 4.

The process CSRSS.EXE is another source for finding almost all the processes on the system. It has a handle to every process except these four:

  • The Idle process

  • The System process



By walking the handles in CSRSS.EXE and identifying the processes to which they refer, you obtain a data set to compare against the list of processes returned by the APIs. Table 10-1 contains the offsets necessary in order to find the handle table of CSRSS.EXE. Within the EPROCESS block of every process is a pointer to a structure that is its HANDLE_TABLE. The HANDLE_TABLE structure contains a pointer to the actual handle table, among other information. For further information on how to parse the handle table, see Russinovich and Solomon's book, Microsoft Windows Internals.[9]

[9] M. Russinovich and D. Solomon, Microsoft Windows Internals, Fourth Edition (Redmond, Wash.: Microsoft Press, 2005), pp. 124 49.

Table 10-1. Offsets for finding handles from an EPROCESS block.

Windows 2000

Windows XP

Windows 2003

Offset to Handle Table in EPROCESS




Offset to the actual table within the Handle Table Structure




Another technique exists for identifying the list of processes without calling a potentially corrupted API. You know from our earlier discussion that every process's EPROCESS block has a pointer to its handle table. It turns out that all these handle table structures are linked by a LIST_ENTRY, similarly to the way all processes are linked by a LIST_ENTRY (see Chapter 7). By finding the handle table for any process and then walking the list of handle tables, you can identify every process on the system. As of this writing, we believe this is the technique used by BlackLight[10] from the antivirus company F-Secure.

[10] F-Secure BlackLight (Helsinki, Finland: F-Secure Corporation, 2005):

In order to walk the list of handle tables, you need the offset of the LIST_ENTRY within the handle table structure (in addition to the offset within the EPROCESS block of the pointer to the handle table, which you have from the Table 10-1). The HANDLE_TABLE structure also contains the PID of the process that owns the handle table. The PID is also found at different offsets depending on the version of the Windows operating system. The offsets to identify every process based upon its PID are given in Table 10-2.

Table 10-2. Offsets used to walk the handle tables and ID the processes.

Windows 2000

Windows XP

Windows 2003

Offset to LIST_ENTRY within Handle Table




Offset to Process ID within Handle Table




As you traverse each process using the LIST_ENTRY values, you can find the owning PIDs. Now you have another data set to compare against if the Win32 API fails to list a particular process. The following function lists all the processes on the system by walking the linked list of handle tables:

 void ListProcessesByHandleTable(void) {    PEPROCESS eproc;    PLIST_ENTRY start_plist, plist_hTable = NULL;    PDWORD d_pid;    // Get the current EPROCESS block.    eproc = PsGetCurrentProcess();    plist_hTable = (PLIST_ENTRY)((*(PDWORD)((DWORD) eproc +                    HANDLETABLEOFFSET)) + HANDLELISTOFFSET);    start_plist = plist_hTable;    do    {       d_pid = (PDWORD)(((DWORD)plist_hTable + EPROCPIDOFFSET)                - HANDLELISTOFFSET);       // Print the Process ID as a debug message.       // You could store it to compare to API calls.       DbgPrint("Process ID: %d\n", *d_pid);       // Advance.       plist_hTable = plist_hTable->Flink;    }while (start_plist != plist_hTable); } 

This is just another way to identify a hidden process, but it is very effective. If the rootkit does not alter this list in the kernel, which can be difficult to do, your detection method will catch its hidden processes. There are other, similar structures in the kernel that could be used in this way as well. Detection techniques are evolving as fast as rootkits are.

     < Day Day Up > 

    Rootkits(c) Subverting the Windows Kernel
    Rootkits: Subverting the Windows Kernel
    ISBN: 0321294319
    EAN: 2147483647
    Year: 2006
    Pages: 111

    Similar book on Amazon © 2008-2017.
    If you may any questions please contact us: