Posted by: Nagareshwar Talekar | November 23, 2009

Coming Soon – SpyDLLRemover for Win7

With Microsoft Launching Windows 7,  SpyDLLRemover is now getting ready to put up the show.  Compared to Vista, Windows 7 has gone  through a lot of internal structural changes which will be addressed in the upcoming version of  SpyDLLRemover.

Apart from support for Windows 7,  new SpyDLLRemover features following improvements…

  • Settings to control Spy Scan.
  • Enriched user friendly interface
  • Improved DLL Auto Analysis
  • Other enhancements related to performance, product name session info display and many more.
  • Numerous bug fixes

So keep watching this space for surprise news…!

Posted by: rootkitanalytics | November 1, 2009

Wandering Through Trojan.NtRootKit.47 Driver

Wandering Through Trojan.NtRootKit.47 Driver
Author: Davide “ocean” Quarta


I didn’t have the dropper at the moment of writing this, only the driver. Without the dropper we can only get a generic idea of what the  driver is used for. The driver has been reverse engineered by deadlist, a really irritating thing to do actually, but it can be useful to see the generic structure of a typical driver.

It’s a driver with dll functionality. Erssd shows us that the driver is produced by ErrorSafe, a fake-av (scareware) company. Seems like there are no rootkit functionality in this driver, while only a few zw* functions are exposed to the dropper, through the use of IOCTLS, though we can’t know how this is used without access to the dropper.


Driver entry point:

Driver Entry Point

Simple start structure, a Device is created with name “erssdd” and linked with a Dosdevice with the same name, next every PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1] will be written to point to a general IRP_dispatch procedure. Also a driver unload routine is set.

.text:000113EA                 push    1Ch             ; IRP_MJ_MAXIMUM_FUNCTION+1
.text:000113EC                 lea        edi, [ebx+38h]
.text:000113EF                 pop      ecx
.text:000113F0                 mov     eax, offset irp_dispatch
.text:000113F5                 rep stosd

.text:000113F7                 mov     dword ptr [ebx+34h], offset unload

unload procedure is pretty simple too

.text:0001133A unload:
.text:0001133A                 cmp     Handle, 0
.text:00011341                  jz      short loc_1134A
.text:00011343                 push    0
.text:00011345                 call    close_handle
.text:0001134A loc_1134A:
.text:0001134A                 push   offset DestinationString
.text:0001134F                 call     ds:IoDeleteSymbolicLink
.text:00011355                 push   DeviceObject
.text:0001135B                 call     ds:IoDeleteDevice
.text:00011361                 retn    4

it will just check if there’s and object handle open and close it (inside function close_handle there’s a call to

now the irp dispatcher procedure 🙂

IRP Dispatcher:

IRP Dispatch

the first part of it is simply an initialization that also makes use (as obvious) of the IoGetCurrentIrpStackLocation:

.text:0001128E              push    ebp
.text:0001128F              mov     ebp, esp
.text:00011291              sub     esp, 0Ch
.text:00011294              push    ebx
.text:00011295              push    esi
.text:00011296              push    edi
.text:00011297              mov     edi, [ebp+Irp]
.text:0001129A              mov     esi, [edi+60h]  ; Irp->Tail.Overlay.CurrentStackLocation
.text:0001129D              mov     eax, [edi+_IRP.AssociatedIrp.SystemBuffer] ; Irp->AssociatedIrp.SystemBuffer
.text:000112A0              xor     edx, edx
.text:000112A2              mov     [edi+1Ch], edx  ; Irp->IoStatus.Information
.text:000112A5              lea     ebx, [edi+_IRP.IoStatus] ; Irp->IoStatus
.text:000112A8              mov     [ebx], edx      ; clear IoStatus.Status
.text:000112AA              mov     ecx, [esi+_IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLength]
.text:000112AD              mov     [ebp+InputBufferLenght], ecx
.text:000112B0              mov     ecx, [esi+_IO_STACK_LOCATION.Parameters.DeviceIoControl.OutputBufferLength]
.text:000112B3              mov     [ebp+OutputBufferLenght], ecx
.text:000112B6              mov     ecx, [esi+_IO_STACK_LOCATION.Parameters.DeviceIoControl.IoControlCode]
.text:000112B9              mov     [ebp+Irp], ecx
.text:000112BC              movzx   ecx, byte ptr [esi] ; IO_STACK_LOCATION.MajorFunction
.text:000112BF              dec     ecx
.text:000112C0              dec     ecx
.text:000112C1              mov     [ebp+SystemBuffer], eax
.text:000112C4              jz      short IRP_MJ_CLOSE
.text:000112C6              sub     ecx, 0Ch
.text:000112C9              jnz     short complete_irp

what happens on IRP_MJ_CLOSE is really simple, closes an open handle (if there’s one) and the complete the irp. Only other accepted request is IRP_MJ_DEVICE_CONTROL.

.text:000112CB                 mov     ecx, [edi+4]    ; Irp->MdlAddress
.text:000112CE                 cmp     ecx, edx
.text:000112D0                 jz      short loc_112E5
.text:000112D2                 test    byte ptr [ecx+6], 5 ;Mdl->MdlFlags ==
.text:000112D6                 jz      short loc_112DD
.text:000112D8                 mov     eax, [ecx+0Ch]
.text:000112DB                 jmp     short loc_112E5

if mdl flags are right map the page!

.text:000112DD loc_112DD:
.text:000112DD                 push    edx             ; AccessMode
.text:000112DE                 push    ecx             ; MemoryDescriptorList
.text:000112DF                 call    ds:MmMapLockedPages

For IRP_MJ_DEVICE_CONTROL driver must have a DeviceDispatch routine, let’s give a look a it.


Device Despatch

Dispatch routine is done in a similar way to this one from IRP Cheat Sheet in MSDN:

// <– Process the IRP here.
Irp->IoStatus.Status = STATUS_XXX;
Irp->IoStatus.Information = YYY;
IoCompletRequest(Irp, IO_NO_INCREMENT);
return STATUS_XXX;

As we can notice there’s a switch/nested if that checks for the function in ioctl code. For every function a check is performed on the minimum lenght for the buffer, if condition is not met, the status returned will be:

“mov     dword ptr [esi], STATUS_BUFFER_TOO_SMALL”

As we can easily see from the code some global variables are used, a variable contains a Handle that will be used by every function. Every function exposes a Zw* function in a way they can be used from the usermode dropper. Exposed functions are ZwWriteFile, ZwReadFile, ZwOpenFile, ZwClose,

For the symbolic link desired access is:

push    READ_CONTROL    ; DesiredAccess

and  the handle attributes make sure that the handle is actually accessed only from kernel mode:

mov     [ebp+DestinationString.MaximumLength], 800h
mov     [ebp+ObjectAttributes.Length], 18h
mov     [ebp+ObjectAttributes.RootDirectory], ebx
mov     [ebp+ObjectAttributes.Attributes], OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE
mov     [ebp+ObjectAttributes.SecurityDescriptor], ebx
mov     [ebp+ObjectAttributes.SecurityQualityOfService], ebx
call    ds:ZwOpenSymbolicLinkObject

which opens a symbolic link to “\DosDevices\”%c”:” where “%c” is the drive.

ZwQuerySymbolicLink is obviously used to get \DosDevices\Harddisk* string to build a string that can be used to open subsequently a file with ZwOpen.

Inside the call that uses ZwOpen is used also ZwQueryVolumeInformationFile, that’s used to retrieve some information about files.

push     edi             ; VolumeInformationClass
push     8               ; VolumeInformationLength
lea        eax, [ebp+var_28]
push    eax             ; VolumeInformation
lea        eax, [ebp+IoStatusBlock]
push    eax             ; IoStatusBlock
push    Handle          ; FileHandle
call      esi ; ZwQueryVolumeInformationFile

Thanks to…

Thanks to evilcry for proof-read and correction of this paper and for being a great friend.
Thanks to emdel, alby, nex for being great friends.

…Thanks to EvilFingers 🙂