An Analysis of Rootkit Technologies: Part 2

ZeroAccess

Let us review various hiding mechanisms for kernel mode rootkits.

ZeroAccess is a rootkit family which infects randomly selected drivers from the "%SystemRoot%\system32\drivers" catalog. The malicious program writes itself to the beginning of the file. The rootkit then downloads more components from the Internet to the infected system. Once the download process is successfully completed, the rootkit injects its components into the address space of the user mode processes. Components are injected from the driver by mapping the memory pages containing malicious code to the address space of processes. The code is then executed by attaching asynchronous procedure calls to the threads in an alertable wait state.

In addition, the rootkit substitutes a system object-section "\KnownDlls\mswsock.dll" with its own object containing malicious code. It loads this malicious code to any process that uses the system library "mswsock.dll". After initialization, a malicious library loads the original "mswsock.dll" to the address space in such a way that does not affect the system performance.

Hiding the rootkit driver on the system is achieved by deleting the LDR_DATA_TABLE_ENTRY element from the linked list PsLoadedModuleList.

The rootkit also hides the original content of the infected driver. When attempting to read a file on the infected driver, the original file content is provided. A copy of this file is located in the %SystemRoot%\$NtUninstallKB catalog.

Substitution of the infected file content is accomplished by filtering the IRP_MJ_SCSI requests between the FDO and PDO devices in the driver stack. For this purpose, the rootkit substitutes a device pointer which follows FDO in the driver stack by a device created by the rootkit.

The address of the “device” object belonging to the rootkit driver, as well as a list of input/output procedures registered by the rootkit driver in its "DriverObject", is shown in Figure 4. 

Figure 4. !drvobj and !devobj commands of the windbg debugger for the device and driver objects of the rootkit driver

Complex logic is used in the rootkit driver. This logic identifies requests to the read/write sectors where a rootkit file is located and returns the content of the original file. In addition, the rootkit can hide processes of other malware it installs in a system. The rootkit removes an EPROCESS core object belonging to the hidden process of the EPROCESS.ActiveProcessLinks linked list to do this.

It is possible to diagnose the system infection by the ZeroAccess rootkit using the GMER anti-rootkit (Figure 5).

Figure 5. GMER scan results

An interesting peculiarity of the ZeroAccess rootkit is the hiding of file content based on a generic algorithm. As mentioned above, a filter lies between FDO and PDO devices of the disk driver that controls the IRP_MJ_SCSI requests directed to the disk PDO thus hiding the original file content infected by the rootkit. A common way to achieve this is by substitutiing the corresponding function pointer in DRIVER_OBJECT.MajorFunction for miniport driver by its function; or a hook using the insertion of the branching instruction into the function code. The ZeroAccess developers have found an additional method to control requests to the drive miniport.

Let us take a look at the code the rootkit uses to create a filter (Figure 6).

Figure 6. The code of IRP request filter setting up

A pointer to the disk driver object is created using an undocumented ObReferenceObjectByName function. The rootkit then enumerates all devices it has created using the IoEnumerateDeviceObjectList function and then retrieves a pointer to the related DEVICE_EXTENSION structure from each device (Figure 7).

Figure 7. The code of IRP request filter setting up (2)

DeviceExtension is a special field in the device object which allows developers to link information to the device object. This field does not have a well-defined structure. A driver developer can specify a format by himself/herself. The field is usually used for storing information on device state, pointers to various core objects used while working with the device and the other service information. A disk driver inherits handlers from the classpnp driver as well as the structure format, COMMON_DEVICE_EXTENSION.

To transmit IRP down by the stack, the device call is called. A pointer to this device is stored in the COMMON_DEVICE_EXTENSION.LowerDeviceObject field that points to PDO or to the filter device. This is device replaces the rootkit. In Figure 7, the listing shows that the rootkit creates its device-filter for each disk device using IoCreateDevice related to the rootkit driver object which will handle all incoming requests. Device-filter creation is followed by the code that sets device objects by specifying a stack size for the filter. The stack size is the same as for the disk device. The DEVICE_EXTENSION structure is then filled in for the rootkit filter. As it is shown in Figure 7, the original pointer to a lower device in the stack replaced by the rootkit. The LowerDeviceObject field address and a pointer to the FDO disk are saved here. At the end, flags for filter device are set and its address is assigned to the COMMON_DEVICE_EXTENSION.LowerDeviceObject field. The filter then starts functioning. All IRP requests directed to the miniport driver will be directed to the rootkit driver first.

A single handler for the IRP requests of all types is used in the filter. In Figure 1 it is presented as IrpHandler. The MajorFunction array is filled with the handler address using the stosd instruction. The array is located in the rootkit driver object 0x38 shifted. The handler body is presented on Figure 8.

Figure 8. IRP filter handler code

Figure 9. IRP filter handler code, Part 2

The code shows that the filter responds only to the IRP_MJ_INTERNAL_DEVICE_CONTROL requests. In other cases a system driver handler (CallOriginalIrpHandler) gets control. The handler analyzes the request parameters. A SCSI_REQUEST_BLOCK structure is used for communication with the disk driver miniport. The rootkit tracks requests to read/write sectors (SCSIOP_READ and SCSIOP_WRITE) by checking the operation code field value in Command Descriptor Block; requests of the other types are redirected to the system driver. If a read/write request is found, a special procedure is called (Figure 9). The procedure checks if the rootkits are stored in the sectors in which the operation occurs. If they are, fake request data is inserted into the buffer to hide the infected file content and protect those files against rewriting by antivirus programs. Afterwards, the request is executed and the system driver does not get control.

The technique the ZeroAccess rootkit uses to intercept requests to the disk drivers does not make any changes to core structures secured by PatchGuard. This means the technique can also be applied on the 64-bit version of the Windows OS.

In the next issue we will give an overview of famous TDL2 hiding technologies.

  • Back to articles


  • Share this post:    Twitter Facebook