Flag: Tornado! Hurricane!

FUTo

Thursday, January 5 2006 18:28.38 CST
Author: peter # Views: 30437 Printer Friendly ...

 Foreward

Since the introduction of FU, the rootkit world has moved away from implementing system hooks to hide their presence. Because of this change in offense, a new defense had to be developed. The new algorithms used by rootkit detectors, such as BlackLight, attempt to find what the rootkit is hiding instead of simply detecting the presence of the rootkit's hooks. This paper will discuss an algorithm that is used by both Blacklight and IceSword to detect hidden processes. This paper will also document current weaknesses in the rootkit detection field and introduce a more complete stealth technique implemented as a prototype in FUTo.

Thanks:

Peter would like to thank bugcheck, skape, thief, pedram, F-Secure for doing great research, and all the nologin/research'ers who encourage mind growth.

C.H.A.O.S. would like to thank Amy, Santa (this work was three hours on Christmas day), lonerancher, Pedram, valerino, and HBG Unit.

 Introduction

In the past year or two, there have been several major developments in the rootkit world. Recent milestones include the introduction of the FU rootkit, which uses Direct Kernel Object Manipulation (DKOM); the introduction of VICE, one of the first rootkit detection programs; the birth of Sysinternals' Rootkit Revealer and F-Secure's Blacklight, the first mainstream Windows rootkit detection tools; and most recently the introduction of Shadow Walker, a rootkit that hooks the memory manager to hide in plain sight.

Enter Blacklight and IceSword. The authors chose to investigate the algorithms used by both Blacklight and IceSword because they are considered by many in the field to be the best detection tools. Blacklight, developed by the Finnish security company F-Secure, is primarily concerned with detecting hidden processes. It does not attempt to detect system hooks; it is only concerned with hidden processes. IceSword uses a very similar method to Blacklight. IceSword differentiates itself from Blacklight in that it is a more robust tool allowing the user to see what system calls are hooked, what drivers are hidden, and what TCP/UDP ports are open that programs, such as netstat, do not.

 Blacklight

This paper will focus primarily on Blacklight due to its algorithm being the research focus for this paper. Also, it became apparent after researching Blacklight that IceSword used a very similiar algorithm. Therefore, if a weakness was found in Blacklight, it would most likely exist in IceSword as well.

Blacklight takes a userland approach to detecting processes. Although simplistic, its algorithm is amazingly effective. Blacklight uses some very strong anti-debugging features that begin by creating a Thread Local Storage (TLS) callback table. Blacklight's TLS callback attempts to befuddle debuggers by forking the main process before the process object is fully created. This can occur because the TLS callback routine is called before the process is completely initialized. Blacklight also has anti-debugging measures that detect the presence of debuggers attaching to it. Rather than attempting to beat the anti-debugging measures by circumventing the TLS callback and making other program modifications, the authors decided to just disable the TLS routine. To do this, the authors used a tool called LordPE. LordPE allows users to edit PE files. The authors used this tool to zero out the TLS callback table. This disabled the forking routine and gave the authors the ability to use an API Monitor. It should be noted that disabling the callback routine would allow you to attach a debugger, but when the user clicked "scan" in the Blacklight GUI Blacklight would detect the debugger and exit. Instead of working up a second measure to circumvent the anti-debugging routines, the authors decided to analyze the calls occuring within Blacklight. To this end, the authors used Rohitabs API Monitor.

In testing, one can see failed calls to the API OpenProcess (tls zero is Blacklight without a TLS table). Blacklight tries opening a process with process id (PID) of 0x1CC, 0x1D0, 0x1D4, 0x1D8 and so on. The authors dubbed the method Blacklight uses as PID Bruteforce (PIDB). Blacklight loops through all possible PIDS calling OpenProcess on the PIDs in the range of 0x0 to 0x4E1C. Blacklight keeps a list of all processes it is able to open, using the PIDB method. Blacklight then calls CreateToolhelp32Snapshot, which gives Blacklight a second list of processes. Blacklight then compares the two lists, to see if there are any processes in the PIDB list that are not in the list returned by the CreateToolhelp32Snapshot function. If there is any discrepancy, these processes are considered hidden and reported to the user.

 Windows OpenProcess

In Windows, the OpenProcess function is a wrapper to the NtOpenProcess routine. NtOpenProcess is implemented in the kernel by NTOSKRNL.EXE. The function prototype for NtOpenProcess is:

NTSTATUS NtOpenProcess (
    OUT PHANDLE ProcessHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes,
    IN PCLIENT_ID ClientId OPTIONAL);

The ClientId parameter is the actual PID that is passed by OpenProcess. This parameter is optional, but during our observation the OpenProcess function always specified a ClientId when calling NtOpenProcess.

NtOpenProcess performs three primary functions:
  • 1. It verifies the process exists by calling PsLookupProcessByProcessId.
  • 2. It attempts to open a handle to the process by calling ObOpenObjectByPointer.
  • 3. If it was successful opening a handle to the process, it passes the handle back to the caller.
PsLookupProcessByProcessId was the next obvious place for research. One of the outstanding questions was how does PsLookupProcessByProcessId know that a given PID is part of a valid process? The answer becomes clear in the first few lines of the disassembly:

PsLookupProcessByProcessId:
  mov edi, edi
  push ebp
  mov ebp, esp
  push ebx
  push esi
  mov eax, large fs:124h
  push [ebp+arg_4]
  mov esi, eax
  dec dword ptr [esi+0D4h]
  push PspCidTable
  call ExMapHandleToPointer

From the above disassembly, it is clear that ExMapHandleToPointer queries the PspCidTable for the process ID.

Now we have a complete picture of how Blacklight detects hidden processes:
  • 1. Blacklight starts looping through the range of valid process IDs, 0 through 0x41DC.
  • 2. Blacklight calls OpenProcess on every possible PID.
  • 3. OpenProcess calls NtOpenProcess.
  • 4. NtOpenProcess calls PsLookupProcessByProcessId to verify the process exists.
  • 5. PsLookupProcessByProcessId uses the PspCidTable to verify the processes exists.
  • 6. NtOpenProcess calls ObOpenObjectByPointer to get the handle to the process.
  • 7. If OpenProcess was successful, Blacklight stores the information about the process and continues to loop.
  • 8. Once the process list has been created by exhausting all possible PIDs. Blacklight compares the PIDB list with the list it creates by calling CreateToolhelp32Snapshot. CreateToolhelp32Snapshot is a Win32 API that takes a snapshot of all running processes on the system. A discrepancy between the two lists implies that there is a hidden process. This case is reported by Blacklight.
 PspCidTable

The PspCidTable is a "handle table for process and thread client IDs". Every process' PID corresponds to its location in the PspCidTable. The PspCidTable is a pointer to a HANDLE_TABLE structure.

typedef struct _HANDLE_TABLE {
   PVOID        p_hTable;
   PEPROCESS    QuotaProcess;
   PVOID        UniqueProcessId;
   EX_PUSH_LOCK HandleTableLock [4];
   LIST_ENTRY   HandleTableList;
   EX_PUSH_LOCK HandleContentionEvent;
   PHANDLE_TRACE_DEBUG_INFO DebugInfo;
   DWORD        ExtraInfoPages;
   DWORD        FirstFree;
   DWORD        LastFree;
   DWORD        NextHandleNeedingPool;
   DWORD        HandleCount;
   DWORD        Flags;
};

Windows offers a variety of non-exported functions to manipulate and retrieve information from the PspCidTable. These include:
  • - [ExCreateHandleTable] creates non-process handle tables. The objects within all handle tables except the PspCidTable are pointers to object headers and not the address of the objects themselves.
  • - [ExDupHandleTable] is called when spawning a process.
  • - [ExSweepHandleTable] is used for process rundown.
  • - [ExDestroyHandleTable] is called when a process is exiting.
  • - [ExCreateHandle] creates new handle table entries.
  • - [ExChangeHandle] is used to change the access mask on a handle.
  • - [ExDestroyHandle] implements the functionality of CloseHandle.
  • - [ExMapHandleToPointer] returns the address of the object corresponding to the handle.
  • - [ExReferenceHandleDebugIn] tracing handles.
  • - [ExSnapShotHandleTables] is used for handle searchers (for example in oh.exe).
Below is code that uses non-exported functions to remove a process object from the PspCidTable. It uses hardcoded addresses for the non-exported functions necessary; however, a rootkit could find these function addresses dynamically.

typedef PHANDLE_TABLE_ENTRY (*ExMapHandleToPointerFUNC)
                     ( IN PHANDLE_TABLE HandleTable,
                       IN HANDLE ProcessId);

void HideFromBlacklight(DWORD eproc)
{
               PHANDLE_TABLE_ENTRY CidEntry;
               ExMapHandleToPointerFUNC map;
               ExUnlockHandleTableEntryFUNC umap;
               PEPROCESS p;
               CLIENT_ID ClientId;

               map = (ExMapHandleToPointerFUNC)0x80493285;

               CidEntry = map((PHANDLE_TABLE)0x8188d7c8,
                         LongToHandle( *((DWORD*)(eproc+PIDOFFSET)) ) );
               if(CidEntry != NULL)
               {
                  CidEntry->Object = 0;
               }
               return;
}

Since the job of the PspCidTable is to keep track of all the processes and threads, it is logical that a rootkit detector could use the PspCidTable to find hidden processes. However, relying on a single data structure is not a very robust algorithm. If a rootkit alters this one data structure, the operating system and other programs will have no idea that the hidden process exists. New rootkit detection algorithms should be devised that have overlapping dependencies so that a single change will not go undetected.

 FUTo

To demonstrate the weaknesses in the algorithms currently used by rootkit detection software such as Blacklight and Icesword, the authors have created FUTo. FUTo is a new version of the FU rootkit. FUTo has the added ability to manipulate the PspCidTable without using any function calls. It uses DKOM techniques to hide particular objects within the PspCidTable.

There were some design considerations when implementing the new features in FUTo. The first was that, like the ExMapHandleXXX functions, the PspCidTable is not exported by the kernel. In order to overcome this, FUTo automatically detects the PspCidTable by finding the PsLookupProcessByProcessId function and disassembling it looking for the first function call. At the time of this writing, the first function call is always to ExMapHandleToPointer. ExMapHandleToPointer takes the PspCidTable as its first parameter. Using this knowledge, it is fairly straightforward to find the PspCidTable.

PsLookupProcessByProcessId:
  mov edi, edi
  push ebp
  mov ebp, esp
  push ebx
  push esi
  mov eax, large fs:124h
  push [ebp+arg_4]
  mov esi, eax
  dec dword ptr [esi+0D4h]
  push PspCidTable
  call ExMapHandleToPointer

A more robust method to find the PspCidTable could be written as this algorithm will fail if even simple compiler optimizations are made on the kernel. Opc0de wrote a more robust method to detect non-exported variables like PspCidTable, PspActiveProcessHead, PspLoadedModuleList, etc. Opc0des method does not requires memory scanning like the method currently used in FUTo. Instead Opc0de found that the KdVersionBlock field in the Process Control Region structure pointed to a structure KDDEBUGGER_DATA32. The structure looks like this:

typedef struct _KDDEBUGGER_DATA32 {

    DBGKD_DEBUG_DATA_HEADER32 Header;
    ULONG   KernBase;
    ULONG   BreakpointWithStatus;       // address of breakpoint
    ULONG   SavedContext;
    USHORT  ThCallbackStack;            // offset in thread data
    USHORT  NextCallback;               // saved pointer to next callback frame
    USHORT  FramePointer;               // saved frame pointer
    USHORT  PaeEnabled:1;
    ULONG   KiCallUserMode;             // kernel routine
    ULONG   KeUserCallbackDispatcher;   // address in ntdll

    ULONG   PsLoadedModuleList;
    ULONG   PsActiveProcessHead;
    ULONG   PspCidTable;

    ULONG   ExpSystemResourcesList;
    ULONG   ExpPagedPoolDescriptor;
    ULONG   ExpNumberOfPagedPools;

    [...]

    ULONG   KdPrintCircularBuffer;
    ULONG   KdPrintCircularBufferEnd;
    ULONG   KdPrintWritePointer;
    ULONG   KdPrintRolloverCount;

    ULONG   MmLoadedUserImageList;

} KDDEBUGGER_DATA32, *PKDDEBUGGER_DATA32;

As the reader can see the structure contains pointers to many of the commonly needed/used non-exported variables. This is one more robust method to finding the PspCidTable and other variables like it.

The second design consideration was a little more troubling. When FUTo removes an object from the PspCidTable, the HANDLE_ENTRY is replaced with NULLs representing the fact that the process "does not exist." The problem then occurs when the process that is hidden (and has no PspCidTable entries) is closed. When the system tries to close the process, it will index into the PspCidTable and dereference a null object causing a blue screen. The solution to this problem is simple but not elegant. First, FUTo sets up a process notify routine by calling PsSetCreateProcessNotifyRoutine. The callback function will be invoked whenever a process is created, but more importantly it will be called whenever a process is deleted. The callback executes before the hidden process is terminated; therefore, it gets called before the system crashes. When FUTo deletes the indexes that contain objects that point to the rogue process, FUTo will save the value of the HANDLE_ENTRYs and the index for later use. When the process is closed, FUTo will restore the objects before the process is closed allowing the system to dereference valid objects.

 Conclusion

The catch phrase in 2005 was, ``We are raising the bar [again] for rootkit detection''. Hopefully the reader has walked away with a better understanding of how the top rootkit detection programs are detecting hidden processes and how they can be improved. Some readers may ask "What can I do?" Well, the simple solution is not to connect to the Internet, but a combination of using both Blacklight, IceSword and Rootkit Revealer will greatly help your chances of staying rootkit free. A new tool called RAIDE (Rootkit Analysis Identification Elimination) will be unveiled in the coming months at Blackhat Amsterdam. This new tool does not suffer from the problems brought forth here.

 Bibliography

[1] Blacklight Homepage. F-Secure Blacklight http://www.f-secure.com/blacklight/
[2]FU Project Page. FU http://www.rootkit.com/project.php?id=12
[3]IceSword Homepage. IceSword http://www.xfocus.net/tools/200505/1032.html
[4]LordPE Homepage. LordPE Info http://mitglied.lycos.de/yoda2k/LordPE/info.htm
[5]Opc0de. 2005. How to get some hidden kernel variables without scanning http://www.rootkit.com/newsread.php?newsid=101
[6]Rohitabs API Monitor. API Monitor - Spy on API calls http://www.rohitab.com/apimonitor/
[7]Russinovich, Solomon. Microsoft Windows Internals Fourth Edition.
[8]Silberman. RAIDE:Rootkit Analysis Identification Elimination http://www.blackhat.com/html/bh-europe-06/bh-eu-06-speakers.htmlSilberman

Article Comments Write Comment / View Complete Comments

    Username Comment Excerpt Date
hoglund I would suggest that the rootkit-world hasn't a... Wednesday, July 12 2006 00:52.05 CDT
vf I read this in uninformed as well. It's very in... Wednesday, January 18 2006 10:59.17 CST
Opcode Very nice article! :D It is cool to see my lit... Tuesday, January 10 2006 21:56.08 CST
linestyle good article!!,great work,too!:) Monday, January 9 2006 23:55.54 CST
MohammadHosein informative , i really liked this article and i... Friday, January 6 2006 07:33.49 CST

There are 30,779 total registered users.


Recently Created Topics
Intel pin in loaded ...
Jun/27
Going to do today wi...
Jun/27
how to create delphi...
Jun/27
enabling menu in a s...
Jun/18
How to get the Image...
Jun/17
OllyDBG Process Term...
Apr/28
Reversing opcode
Apr/24
Question about debbu...
Apr/16
IDA PRO Struct Point...
Apr/15
Problem with ollydbg
Mar/22


Recent Forum Posts
Intel pin in loaded ...
djnemo
OOP_RE tool available?
Bl4ckm4n
OOP_RE tool available?
van7hu
Should binaries be n...
Kolisar
Problem with ollydbg
nullx42
!findtrampoline Immu...
skycrack
looking for a softwa...
raxen
Documenting reversed...
raxen
.orpc section what's...
mbin
Pydbg load() issue
phreak


Recent Blog Entries
oleavr
Jun/25
Build a debugger in 5 minutes

oleavr
Apr/17
frida.re 1.2.0 is out, with...

gareebnavas
Jan/21
Android Malware Analysis

oleavr
Dec/21
frida.github.io: scriptable...

chr1x
Nov/05
!apilookup - Win32 API Func...

More ...


Recent Blog Comments
pedram on:
Dec/21
frida.github.io: scriptable...

capadleman on:
Jun/19
Using NtCreateThreadEx for ...

newlulu on:
Jun/10
Branch tracing and LBR acce...

newlulu on:
Jun/10
Advanced debugging techniques

newlulu on:
Jun/10
2 anti-trace mechanisms spe...

More ...


Imagery
SoySauce Blueprint
Jun 6, 2008

[+] expand

View Gallery (11) / Submit