In association with heise online

Way down

I press on and, using dt _driver_object, look at the driver object which is, according to the device object, located at 0x82166c40. Once more I am confronted with an invalid type 0 – the correct value being 4. Nonetheless, the name is set to the correct Unicode string – \Driver\atapi – and functions such as DriverInit and DriverStartIO are pointing to the original Windows atapi driver. But the MajorFunction Array – containing the driver's I/O operations, such as IRP_MJ_READ and IRP_MJ_WRITE – is again located in the familiar address space 0x820dxxxx – very suspicious. Time to take a closer look.


I don't need to look at the code too closely – a cursory analysis tells me what's going on. Thanks to the symbol table, the disassembled code generated using uf shows lots of familiar calls to the filesystem runtime library, such as FsRtlProcessFileLock and FsRtlAllocatePool. The functions also contain typical return codes such as 0xC0000123 (STATUS_FILE_DELETED) and 0xC000007F (STATUS_ DISK_FULL).

"This damn rootkit has implemented its own filesystem", I blurt out. Hans, who has been watching patiently over my shoulder the whole time, starts and looks at me questioningly. I try to explain to him that Windows usually uses either the FAT32 or NTFS file system to manage files, but that this rootkit includes its own file management functions and is thus operating at the deepest driver level. Accessing the rootkit files using a standard operating system is therefore far from simple.

Zoom The rootkit hooks itself into the driver hierarchy and has its own filesystem

Hans stares at me in incomprehension. I shrug my shoulders and turn back to the debugger. This is really interesting – let's see what else we can turn up. A closer inspection of the read and write functions reveals a strange loop with a familiar structure. A quick analysis of the disassembled function confirms that we're dealing with the RC4 encryption algorithm.

This means that analysis systems will be unable to recognise the filesystem; even if you were able to read and analyse the raw data byte by byte, there would be no telltale traces, just a few cryptic blocks apparently full of garbage. The guys who did this know what they're doing – I've never seen a rootkit which has penetrated so far into the kernel.


Closer analysis of the actual ATAPI driver object using !drvobj \driver\atapi 2 shows me that TDL has diverted the StartIO routine onto itself. A bit of background knowledge is required here – read and write processes usually operate in a multi-stage process, but it is always StartIO which retrieves data from or sends data to the hard drive's I/O port. The rootkit thus has all read and write operations under its control. The user, any anti-virus software and the operating system see only what TDL wants to show them. It is also able to ensure that the area containing its files does not get overwritten.

To localise the memory area occupied by the rootkit, I toss the DriverStartIO address to !pool and determine that it is part of a block which starts at 0x820d6000 and is 0xF000 in length. Using the search command 's', I search this area for strings and discover several interesting entries – including the characteristic '!This program cannot be run …' and a reference to the configuration file cfg.ini.


The messages 'Invalid partition table' and 'Error loading operating system' look more interesting. These are clear indications that the rootkit has been messing with the master boot record. The strings ldr32 and ldr64 sound like separate bootloader processes for 32- and 64-bit-operating systems. The files drv32 and drv64 are the rootkit itself and cmd.dll and cmd64.dll are the corresponding user mode components.

Reverse engineering at a later date should reveal the precise details, but one thing is already clear – the rootkit obviously spreads on 32- and 64-bit systems and takes control of the operating system at a very early stage.

I am, however, left wondering where the rootkit's user mode component is hiding. I hazard a guess that it's in Internet Explorer and obtain IE's memory address using !process 0 1 iexplore.exe. I set this as the debugger context using .process /r /d. The /r switch ensures that the symbols for this process are also loaded. Using !vad together with the VadRoot address from the process structure, I bring up a list of virtual address descriptors (VADs).


This is a complete list of all of the memory areas associated with a particular process. As well as the actual image, it lists all the dlls which have been loaded by a process and the memory allocated dynamically at runtime. If something has been injected into the browser, it should show up here.

In just the second entry, a block at 0x250 jumps out at me. It is marked as executable and writeable with [/code]EXECUTE_READWRITE, but is not part of a file. To display this memory area, I need to multiply the offset by the block length of 0x1000. The [code]dc (display content) command spits out a characteristic PE header containing the magic string 'MZ...', in honour of Mark Zbikowski. Ladies and gentlemen, allow me to present the cmd.dll user mode component.

It's back to the string search, and once more it yields interesting results. As well as various URLs including and, it finds commands such as DownloadAndExecute and DownloadCrypted2, which appear to be responsible for obtaining instructions from a command and control server. A particularly illuminating string is \\?\globalroot\device\00000f9f\7a256516\cfg.ini, as it tells me how the user mode component accesses the native filesystem.

Next: Boot tricks

Print Version | Permalink:
  • Twitter
  • Facebook
  • submit to slashdot
  • StumbleUpon
  • submit to reddit

  • July's Community Calendar

The H Open

The H Security

The H Developer

The H Internet Toolkit