FUTo

Author: peter # Views: 1259 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值