This is one dog-turd of a driver. It uses IoAttachDeviceToDeviceStack to intercept the IRP_MJ_CREATE Irp requests of the Windows afd.sys, Ancillary Function Driver for WinSock. From this hook location it seems to return STATUS_ACCESS_DENIED to a whole range of AV and anti-malware drivers.
It appears that AV drivers use afd.sys as part of their winsock functions. I don't know what afd.sys does but if you disassemble its IRP_MJ_CREATE function you see a reference to "AfdOpenPacketXX" and some associated code. (Winsock + packet) is enough to know for now.
Code:
PDEVICE_OBJECT
IoAttachDeviceToDeviceStack(
IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice
);
IoAttachDeviceToDeviceStack establishes layering between drivers
so that the same IRPs are sent to each driver in the chain.
An intermediate driver can use this routine during initialization
to attach its own device object to another driver's device object.
Subsequent I/O requests sent to TargetDevice are sent first to the
intermediate driver.
The malware calls IoAttachDeviceToDeviceStack on afd.sys during its DriverEntry routine in pretty much a standard fashion
http://msdn.microsoft.com/en-us/library/ms795014.aspx
Here is the main DispatchControl routine of the malware, which was defined during DriverEntry to handle all the DRIVER_OBJECT MajorFunctions. This is also the function that is called as a result of the IoAttachDeviceToDeviceStack hook.
What the malware does is to check the DEVICE_OBJECT to see if it matches its own, or whether the context is from an external Irp. It then goes to separate DeviceControl functions for each case.
Code:
:00026C46
:00026C46 ; int __stdcall DispatchControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
:00026C46 DispatchControl proc near ; DATA XREF: start+2Do
:00026C46
:00026C46 DeviceObject = dword ptr 8
:00026C46 Irp = dword ptr 0Ch
:00026C46
:00026C46 mov edi, edi
:00026C48 push ebp
:00026C49 mov ebp, esp
:00026C4B mov eax, [ebp+DeviceObject]
:00026C4E cmp eax, DeviceObject ; is this our DEVICE_OBJECT?
:00026C54 jz short loc_26C61
:00026C56 push [ebp+Irp] ; Irp
:00026C59 push eax ; DeviceObject
:00026C5A call DeviceControl_AFD_SYS
:00026C5F jmp short loc_26C85
:00026C61 ; ---------------------------------------------------------------------------
:00026C61
:00026C61 loc_26C61: ; CODE XREF: DispatchControl+Ej
:00026C61 mov ecx, [ebp+Irp] ; Irp
:00026C64 mov edx, dword ptr [ecx+IRP.Tail.Overlay.CurrentStackLocation]
:00026C67 and [ecx+IRP.IoStatus.Information], 0
:00026C6B cmp byte ptr [edx], 0Eh ;
:00026C6B ; switch (IrpStack->MajorFunction)
:00026C6B ; is this IRP_MJ_DEVICE_CONTROL?
:00026C6E jnz short default_IRP
:00026C70 push ecx ; Irp
:00026C71 push eax ; DeviceObject
:00026C72 call DeviceControl_MALWARE
:00026C77
:00026C77 default_IRP: ; CODE XREF: DispatchControl+28j
:00026C77 and [ecx+IRP.IoStatus.anonymous_0.Status], 0
:00026C7B xor dl, dl ; PriorityBoost
:00026C7D call ds:IofCompleteRequest
:00026C83 xor eax, eax
:00026C85
:00026C85 loc_26C85: ; CODE XREF: DispatchControl+19j
:00026C85 pop ebp
:00026C86 retn 8
:00026C86 DispatchControl endp
:00026C86
DeviceControl_AFD_SYS tells us that IRP_MJ_CREATE is the specific Irp being hooked.
Code:
:00026A50 ; int __stdcall DeviceControl_AFD_SYS(PDEVICE_OBJECT DeviceObject, PIRP Irp)
:00026A50 DeviceControl_AFD_SYS proc near ; CODE XREF: DispatchControl+14p
:00026A50
:00026A50 DeviceObject = dword ptr 8
:00026A50 Irp = dword ptr 0Ch
:00026A50
:00026A50 mov edi, edi
:00026A52 push ebp
:00026A53 mov ebp, esp
:00026A55 mov eax, [ebp+Irp]
:00026A58 mov ecx, dword ptr [eax+IRP.Tail.Overlay.CurrentStackLocation]
CurrentStackLocation
Ptr32 to struct _IO_STACK_LOCATION
struct _IO_STACK_LOCATION, 9 elements, 0x24 bytes
+0x000 MajorFunction : UChar
+0x001 MinorFunction : UChar
+0x002 Flags : UChar
+0x003 Control : UChar
+0x004 Parameters : union __unnamed, 38 elements, 0x10 bytes
+0x014 DeviceObject : Ptr32 to struct _DEVICE_OBJECT, 25 elements, 0xb8 bytes
+0x018 FileObject : Ptr32 to struct _FILE_OBJECT, 27 elements, 0x70 bytes
+0x01c CompletionRoutine : Ptr32 to long
+0x020 Context : Ptr32 to Void
:00026A5B cmp byte ptr [ecx], 0 ; // case IRP_MJ_CREATE:?
switch (IrpStack->MajorFunction)
case IRP_MJ_CREATE:?
// enum
char* IRP_MJ_REQUEST_STRINGS[] = {
"IRP_MJ_CREATE",
"IRP_MJ_CREATE_NAMED_PIPE",
"IRP_MJ_CLOSE",
"IRP_MJ_READ",
"IRP_MJ_WRITE",
"IRP_MJ_QUERY_INFORMATION",
"IRP_MJ_SET_INFORMATION",
"IRP_MJ_QUERY_EA",
"IRP_MJ_SET_EA",
"IRP_MJ_FLUSH_BUFFERS",
"IRP_MJ_QUERY_VOLUME_INFORMATION",
"IRP_MJ_SET_VOLUME_INFORMATION",
"IRP_MJ_DIRECTORY_CONTROL",
"IRP_MJ_FILE_SYSTEM_CONTROL",
"IRP_MJ_DEVICE_CONTROL",
"IRP_MJ_INTERNAL_DEVICE_CONTROL",
"IRP_MJ_SHUTDOWN",
"IRP_MJ_LOCK_CONTROL",
"IRP_MJ_CLEANUP",
"IRP_MJ_CREATE_MAILSLOT",
"IRP_MJ_QUERY_SECURITY",
"IRP_MJ_SET_SECURITY",
"IRP_MJ_POWER",
"IRP_MJ_SYSTEM_CONTROL",
"IRP_MJ_DEVICE_CHANGE",
"IRP_MJ_QUERY_QUOTA",
"IRP_MJ_SET_QUOTA",
"IRP_MJ_PNP"
};
:00026A5E push eax ; Irp
:00026A5F push [ebp+DeviceObject] ; DeviceObject
:00026A62 jz short to_IRP_MJ_CREATE
:00026A64 call FallThru_AFD_IRP_MJ_
:00026A69 jmp short loc_26A70
:00026A6B ; ---------------------------------------------------------------------------
:00026A6B
:00026A6B to_IRP_MJ_CREATE: ; CODE XREF: DeviceControl_AFD_SYS+12j
:00026A6B call Hook_AFD_IRP_MJ_CREATE
:00026A70
:00026A70 loc_26A70: ; CODE XREF: DeviceControl_AFD_SYS+19j
:00026A70 pop ebp
:00026A71 retn 8
:00026A71 DeviceControl_AFD_SYS endp
The working code for the hook is in Hook_AFD_IRP_MJ_CREATE. The driver goes through a string comparison between a blacklist of AV products and the ImageFileName received from using
ZwQueryInformationProcess / ProcessImageFileName
http://www.osronline.com/article.cfm?article=472
At the end of it all it completes the Irp request with STATUS_ACCESS_DENIED, presumably to the blacklisted processes:
Code:
:00026902 ; Hook_AFD_IRP_MJ_CREATE+2A25
:00026902 sub esi, offset aKavsvc_exe_2 ; "kavsvc.exe"
:00026908 cmp esi, 1163h
:0002690E jnb short fallthru
:00026910 mov eax, [ebp+pIrp]
:00026916 mov ecx, eax ; Irp
:00026918 mov esi, 0C0000022h ; STATUS_ACCESS_DENIED
:0002691D xor dl, dl ; PriorityBoost
:0002691F mov [eax+IRP.IoStatus.Information], ebx
:00026922 mov [ecx+IRP.IoStatus.anonymous_0.Status], esi
:00026925 call ds:IofCompleteRequest ; // fastcall
:00026925 ; IoCompleteRequest(
:00026925 ; IN PIRP Irp,
:00026925 ; IN CCHAR PriorityBoost
:00026925 ; );
Quote:
@text:00016A70 intersting cryp_names?
|
There's similar code in the IRP_MJ_CREATE hook as well. I don't see any logical use for it. It looks more like garbage code put in to confuse analysis, maybe some crazy loop delay, or it might be involved in the string comparison, I don't know. I welcome other opinions.
Interspersed with crypted string/variable manipulations (and/or/mul/div), are 512 calls to the following seemingly useless code snippet:
:00011FB8 xor_eax proc near
:00011FB8 and null_var1, 0
:00011FBF xor eax, eax
:00011FC1 retn 4
:00011FC1 xor_eax endp
All the work is done on the stack and I don't see any apparent use for the final result.
There's also a call to KeBugCheckEx if some magic numbers aren't the same, the crypted stuff might have something to do with it.
There's also an OS version specific call to IoGetRequestorProcess which makes no sense in the code, in that it returns a PEPROCESS. IoGetRequestorProcess returns a process pointer for the thread that requested the I/O operation.
http://msdn.microsoft.com/en-us/library/ms795464.aspx
The driver also hooks a bunch of system calls and uses a LoadImageNotifyRoutine callback, regular rootkit stuff. The use of IoAttachDeviceToDeviceStack however is something I haven't seen before.
In the end, the main point of the IRP_MJ_CREATE hook appears to be to return STATUS_ACCESS_DENIED to blacklisted processes, thereby halting their communication with afd.sys and winsock.
Is it any wonder it crashes VMWare?
The question was raised - can the malware bypass vmware to the host? While there is code to intercept a winsock function, I don't really see an "escape route". The whole malware needs to be reversed, there are still a lot of questions.
Kayaker