Kaspersky Hooking Engine Analysis

In this article we will talk about a few hooking techniques used by antivirus software. For the purpose of this analysis the antivirus chosen will be Kaspersky (http://www.kaspersky.com/it/trials PURE 3.0 Total Security), we will deal with various hooking techniques used both at user and kernel mode.
The reference operating system will be Windows 7 Professional 32-bit.

The image below shows a summary of the techniques we will analyze in this article.

intro

In order we will deal with:

  • User-space Processes
  • Inline hooking
  • IAT and EAT
  • Virtual Address Descriptor
  • Hidden registry entry
  • IDT
  • SSDT
  • MINI-FILTER
  • IRP
  • TDI HOOKING
  • CALLBACKS
  • Conclusion

User-space Processes

We start with a brief introduction by looking at the processes of kaspersky in user-space.

The main userspace process is “avp.exe” which is instantiated twice: one instance runs under the privileges of NT AUTHORITY\SYSTEM the other is used for the user interface (avp.exe user). The other process: ProtectedObjectsSrv.exe acts as encryption service.
We will focus on the last one: it runs as a background Windows service called “CSObjectsSrv” (CryptoStorage control service).

startService

InfoWatch CryptoStorage is intended for centralized protection of confidential data using cryptographic methods during data storage and processing. The product is based on the integrative approach to data protection. The functional capabilities include file and folder encryption using resilient encryption algorithms, an option to create special data storage objects – the container files, logical disks and flash drives and differentiation of access rights to the protected objects.

InfoWatch CryptoStorage protects against unauthorised access to the RAM content dumped to the hard disk in case of hibernation, crash dumps or data coming from temporary files and swap files. More information about this topic can be found at http://infowatch.com

Let’s now look at all the hooking methods starting from the userland.

Inline hooking

To find API hooks in User-mode, we can use use the apihooks plugin of Volatility

apihook

The processes involved in the inline hooking are:

  • svchost.exe
  • avp.exe[pid1] NT Authority\SYSTEM
  • avp.exe[pid2]

avp.exe one is for the protection service (avp.exe system), the other one, as already said, is for the user interface (avp.exe user). The service requires full system access, that’s why it runs as System.

Let’s examine svchost.exe, this process is subject to inline hooking, in fact, at address 0x7453b5dd we can find a jump that leads to wfapigp.dll, which resides at location 0x74586218.

firewallInlineEdit

Using Volatility we can dump the process with pid 1560 and using IDA we can quickly disassemble the dump and double check for the presence of the hook at location 0x7453b5dd.

edit1

Scrolling again the report generated by Volatility, we can see that the process avp.exe uses different modules (image below)

usermodeHook

The process avp.exe makes use of different hooking techniques​​, let’s try and investigate the following module:

  • ushata.dll

In this case the hooking occurs inside ntdll.dll, the function hooked is ZwProtectVirtualMemory, which is located at 0x77015f18, checking with IDA we can confirm the presence of a jump at 0x71722066, which is the location in which the hooking module ushata.dll is loaded.

ushdatadll

In here we can see how avp.exe loads ushdata.dll using a standard LoadLibraryEx()

Loadushdata

In this context, can occur something similar to what is described in the following code, basically:

hDLL = LoadLibraryExW(L"USHATA.DLL", null, 8);
lpGetNumber = (LPGETNUMBER)GetProcAddress((HMODULE)hDLL, "InitHooks");

initHook

Let’s see what are the methods exported by the module ushdata.dll:

ushdata

So the exported functions of ushdata.dll module are InitHooks, SetClientVerdict and SetShuttingDownHint.

In general from the report generated by volatility, the modules and functions that are subject to inline hooking, are:

  • C:\Program Files\Kaspersky Lab\Kaspersky PURE 3.0\avp.exe[pid1] and [pid2] C:\Windows\SYSTEM32\ntdll.dll (FUNCTIONS ntdll.dll!NtProtectVirtualMemory e ntdll.dll!ZwProtectVirtualMemory)
  • C:\Program Files\Kaspersky Lab\Kaspersky PURE 3.0\avp.exe[pid1] and [pid2] ntdll.dll!NtProtectVirtualMemory JMP 70B12066 C:\Program Files\Kaspersky Lab\Kaspersky PURE 3.0\ushata.dll
  • C:\Program Files\Kaspersky Lab\Kaspersky PURE 3.0\avp.exe[pid1] and [pid2] C:\Windows\system32\kernel32.dll
  • C:\Program Files\Kaspersky Lab\Kaspersky PURE 3.0\avp.exe[pid1] and [pid2] C:\Windows\system32\ole32.dll
  • C:\Program Files\Kaspersky Lab\Kaspersky PURE 3.0\avp.exe[pid1] and [pid2] USER32.dll!NotifyWinEvent + 6AE

The undocumented used is NtProtectVirtualMemory, which will allows to set the page protection and returns the old protection (http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Memory%20Management/Virtual%20Memory/NtProtectVirtualMemory.html).

IAT and EAT

Continuing the analysis of the hooking in User-space, we can still make use of Volatility to detect the hooking performed on both the IAT and EAT. We will find only two functions: one for the IAT hooking and another one for EAT hooking.

IAT_EAT

Referring to the image at the top (EAT Hook), we conclude that the affected module is kernel32.dll, specifically the CreateThread function, as shown in the figure below:

eat

Virtual Address Descriptor

We can open a brief parenthesis on the kernel data structure that takes care of registering the use of virtual addresses in a process, it is called Process VAD (Virtual Address Descriptor). For each process the memory manager maintains a set of VADs, which contain information on the address space of the process itself. Reconstructing the VAD tree allows for the reconstruction of the process with all of its mapped files.
Here’s an example:

VAD

The protection field highlighted in red is extracted from the flProtect parameter passed as input to the VirtualAlloc API (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887%28v=vs.85%29.aspx).

You can also use the windbg command !vad to display the VADs of a given process:

kd> !process 0 1 avp.exe
kd> !vad [address of VadRoot]

Hidden registry entry

A hive is a database of registry values ​​divided in logical groups of keys and subkeys; the values ​​in the registry, in turn, have a number of supporting files containing backups of their data.
These files are located mainly in the %SystemRoot% \System32\Config and are created/updated each time the user logs in.

Here is a table showing the standard hive with the respective files (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724877%28v=vs.85%29.aspx):

Registry hive Supporting files
HKEY_CURRENT_CONFIG System, System.alt, System.log, System.sav
HKEY_CURRENT_USER Ntuser.dat, Ntuser.dat.log
HKEY_LOCAL_MACHINE\SAM Sam, Sam.log, Sam.sav
HKEY_LOCAL_MACHINE\Security Security, Security.log, Security.sav
HKEY_LOCAL_MACHINE\Software Software, Software.log, Software.sav
HKEY_LOCAL_MACHINE\System System, System.alt, System.log, System.sav
HKEY_USERS\.DEFAULT Default, Default.log, Default.sav

 

Let’s look for hidden registry values related to the driver klif.sys and let’s start with the help command !reg:
  • !reg hivelist

It displays a list of all hives in the system, then we select the Hive Address of SYSTEM using the following command:

  • !reg openkeys “Hive Address of SYSTEM”

It displays all open keys in a hive:

hive

I also used the above the command:

  • !reg cellIndex “HiveAddress of SYSTEM” “Index”

It displays the virtual address for a cell in a hive, Index specifies the cell index.

Using the command:

  • !reg valuelist “HiveAddress of SYSTEM” KeyNodeAddress
we can show a list of the values in the specified key node, KeyNodeAddress specifies the address of the key node. Then we show the registry key value structure
  • !reg kvalue Address

Address specifies the address of the value, finally, we can reuse the cell index with the new index of the cell and dc command (it displays double word values, 4 bytes, and ASCII characters)

hive1

We can achieve the same result using Volatility, let’s briefly show how to do that using the command hivelist:

hiveVol1

And once again we come across the KLIF service:

hiveVol2

Let’s now move to the analysis of the hooking at kernel space, in particular we will deal with: IDT, SSDT and IRP hooking.

IDT

System calls are used to traverse the barrier that exists between user space and kernel space, for this task the IDT  is used, the IDT is the table that implements the interrupt vector table, in turn used to dispatch the interrupts. The IDT is composed, internally, of a data structure of 8 bytes entries, which describes how the interrupt must be managed (x86 CPU). In the picture below you can see the relationship between IDT and the instruction “int 2e” that is normally used to initiate a system call, even though on recent CPUs the SYSENTER instruction is used a replacement.

NtSystemCallsImage3

The goal of IDT hooking is to hook any function already registered for a given interrupt.
Let’s see if the software in question uses these techniques, so we can analyze it with windbg and the command !idt

idt

Now let’s run the same check with volatility,using the command idt, we will see that the two results match:

idtVol

In the selected row we can see, from the column Value, that the address matches the one analyzed with windbg, also in the column Module we can notice the presence of ntoskrnl.exe, which shows that there are no hooks in place.

SSDT

The System Service Descriptor Table (SSDT) contains pointers to kernel mode functions provided by the kernel executable module (ntoskrnl.exe). There is a second SSDT called shadow SSDT table, that instead stores the native functions provided by the GUI module win32k.sys. It ‘important to make an observation: when a system call reaches ntdll.dll, EAX will contain the hexadecimal value corresponding to the index into the SSDT of the function to be called, and immediately after the command int 2E the control is transferred to KiSystemService:

ssdt

We’re going to check the contents of the two tables for the software in question, it is possible to analyze the memory with Volatility or WinDBG:

ssdtWinDbg

From the figure on the left hand side we can see the memory belonging to klif.sys at address 0x8C836000. On the right hand side we have the output of the command:

  • kd> dps KiServiceTable l11C                                                                      

that show the presence of SSDT hooks from the klif module.

We can also investigate KeServiceDescriptorTable and KeServiceDescriptorTableShadow.
The module klif.sys seems to be the one that deals with SSDT and SSDT Shadow hooking.
Let’s look more closely at klif.sys, the first function we’re going to inspect is “PsSetLoadImageNotifyRoutine” that registers a driver-supplied callback that is subsequently notified whenever an image is loaded (or mapped into memory).

PsSetLoadImageNotifyRoutine

In the image below we see a series of two calls, the first one calls ZwQuerySystemInformation and then the second one invokes KeServiceDescriptorTable, which is the classical sequence used to install an SSDT hook.

KeServiceDescriptorTable

SSDT hooking is not performed on 64-bits systems because the Kernel Patch Protection (KPP), also known as Patchguard, protects this structure.
It is anyway possible to use a mini-filter driver as a workaround.

MINI-FILTER

And indeed that’s what we have, a minifilter driver:

minifilter

A mini-filter driver must specify an altitude value from an altitude range that represents a load order group.

A minifilter driver’s altitude ensures that the instance of the minifilter driver is always loaded at the appropriate location related to other minifilter driver instances, and it determines the order in which the filter manager calls the minifilter driver to handle I/O. Altitudes are allocated and managed by Microsoft itself.

The following figure shows a simplified I/O stack with the filter manager and three minifilter drivers.

In our case we haveDiagram illustrating a simplified I/O stack with the filter manager and three minifilter drivers

Load order group Altitude range Description
FSFilter Anti-Virus 320000-329999 This group includes filter drivers that detect and disinfect viruses during file I/O.

More information at http://msdn.microsoft.com/en-us/library/windows/hardware/ff549689%28v=vs.85%29.aspx

IRP

An IRP is an object used to communicate between all the different layers of a driver stack (http://msdn.microsoft.com/en-us/library/windows/hardware/hh439632%28v=vs.85%29.aspx).

For each driver, there are some major functions that receive IRPs to process. These major functions are kept inside a table of pointers.

This driver contains the following functions:

  • Driver Entry
  • AddDevice
  • Dispatch routine
  • Unload()

The Driver Object structure is presented as follows:

driverObj

By default the I/O manager does point the DriverInit at the DriverEntry(). The array MajorFunction is essentially a table, each driver populates this table with function pointers, called Dispatch routine. The main data structures used by the kernel driver majors are the IRPs. Some of the most used are: IRP_MJ_CREATE, IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_DEVICE_CONTROL.
We can sniff the traffic IRP to the driver klif using Irp Tracker:

klifIRPTracer

From the red boxes we can see the two processes: avp.exe and svchost.exe calling the NtFsControlFile API (which sends a control code directly to the driver klif)

irpTrace

TDI HOOKING

The kernel module responsible for TDI HOOKING is kltdi.sys, we can look for it inside the structure LDR_DATA_TABLE_ENTRY, pointed by PsLoadedModuleList. By running the modules command in Volatility we will get:

  • kltdi.sys           0x8cb7a000     0x9000 \SystemRoot\system32\DRIVERS\kltdi.sys

At this point we can check to see if there is something unusual for the driver “tdx“:

irpTra

As we can see this is a list of devices that belongs to \Driver\tdx and in each device the module kltdi.sys is present, loaded at the address 0x8cb57000. Using Windbg we can check what happens at the location where tdx.sys is loaded:

  • tdx.sys             0x8cb57000   0x17000 \SystemRoot\system32\DRIVERS\tdx.sys

We only see the location of the major Function IRP_MJ_CREATE:

DriverName: tdx

DriverStart: 0x8cb57000

DriverSize: 0x17000

DriverStartIo: 0x0

0 IRP_MJ_CREATE                       0x8cb62faa tdx.sys

Let’s set a breakpoint at the address 0x8cb62faa, this is the location where the major function IRP_MJ_CREATE of the module tdx.sys. After then we can start a ping and the debugger will immediately break at the address we are expecting, thus confirming the existence of a TDI hook.

kltdi

We can see in the call stack the presence of the module kltdi.sys, let’s focus on the function kltdi+0x4803:

kltdi1

The IoCallDriver routine sends an IRP to the driver associated with a specified device object, it accepts two input parameters DEVICE_OBJECT*an IRP*

NTSTATUS IoCallDriver(
    _In_     PDEVICE_OBJECT DeviceObject,
    _Inout_  PIRP Irp
);

Quoting the Microsoft’s documentation:

An IRP passed in a call to IoCallDriver becomes inaccessible to the higher-level driver, unless the higher-level driver has called IoSetCompletionRoutine to set up an IoCompletion routine for the IRP. If it has, the IRP input to the IoCompletion routine has its I/O status block set by the lower drivers, and all lower-level drivers’ I/O stack locations are filled with zeros.

CALLBACKS

Now let’s take a look at the kernel callbacks, once again with Volatility:

Thread creation (PsSetCreateThreadNotifyRoutine):

  • klif.sys
  • kl1.sys

Shutdown callbacks (IoRegisterShutdownNotification):

  • kl1.sys

KeRegisterBugCheckReasonCallback

  • kl1.sys

There are several addresses for the callbacks, but we want to point out the presence of kernel module kl1.sys, so let’s dig deeper:

kl1

kl1.sys is is a boot start driver, in the image below you can see the presence (in the DriverEntry routine) of the API IoRegisterBootDriverReinitialization.

IoRegisterBootDriverReinitialization() function registers a callback routine that will be called whenever all boot drivers have been loaded. This routine is typically used in filters that attach on non-Plug-and-Play devices, and thus, they cannot rely on AddDevice() function calling to be notified that a new device was created (check this example for more details http://driverentry.com.br/en/blog/?p=261).

kl1IDA

Now let’s also look at the Driver Dispatch Routines:

driverkl1

As you can see, all Driver Dispatch Routines point to the same address, kl1+0x32f0

Conclusion

The article was written for educational purposes, the analysis is not detailed and many things have been analysed very quickly, also there is still research to be done on the network part.

A big thanks goes to Quequero.

Reference

http://www.reconstructer.org/papers/Hunting%20rootkits%20with%20Windbg.pdf

Malware Analysts Cookbook and DVD: Tools and Techniques for Fighting Malicious Code