.386p;--------------------------------------------------------------------------------------------------------------------------------
include vmm.inc
include vwin32.incDECLARE_VIRTUAL_DEVICE DYNAVXD,1,0, DYNAVXD_Control,\
UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDERBegin_control_dispatch DYNAVXD
Control_Dispatch w32_DeviceIoControl, OnDeviceIoControl
End_control_dispatch DYNAVXDVxD_PAGEABLE_CODE_SEG
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode==DIOC_Open
xor eax,eax
.endif
ret
EndProc OnDeviceIoControl
VxD_PAGEABLE_CODE_ENDSend
VXD DYNAVXD DYNAMICSEGMENTS
_LPTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
_DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TLS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LMGTABLE CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_LMSGDATA CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_IMSGTABLE CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_IMSGDATA CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_ITEXT CLASS 'ICODE' DISCARDABLE
_IDATA CLASS 'ICODE' DISCARDABLE
_PTEXT CLASS 'PCODE' NONDISCARDABLE
_PMSGTABLE CLASS 'MCODE' NONDISCARDABLE IOPL
_PMSGDATA CLASS 'MCODE' NONDISCARDABLE IOPL
_PDATA CLASS 'PDATA' NONDISCARDABLE SHARED
_STEXT CLASS 'SCODE' RESIDENT
_SDATA CLASS 'SCODE' RESIDENT
_DBOSTART CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_16ICODE CLASS '16ICODE' PRELOAD DISCARDABLE
_RCODE CLASS 'RCODE'EXPORTS
DYNAVXD_DDB @1
; VxDLoader.asm
.386Below is the source code of the dynamic VxD that is called by vxdloader.asm
.model flat,stdcall
include windows.inc
include kernel32.inc
includelib kernel32.lib
include user32.inc
includelib user32.lib.data
AppName db "DeviceIoControl",0
VxDName db "\\.\shellmsg.vxd",0
Success db "The VxD is successfully loaded!",0
Failure db "The VxD is not loaded!",0
Unload db "The VxD is now unloaded!",0
MsgTitle db "DeviceIoControl Example",0
MsgText db "I'm called from a VxD!",0
InBuffer dd offset MsgTitle
dd offset MsgText
.data?
hVxD dd ?
.code
start:
invoke CreateFile,addr VxDName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0
.if eax!=INVALID_HANDLE_VALUE
mov hVxD,eax
invoke MessageBox,NULL,addr Success,addr AppName,MB_OK+MB_ICONINFORMATION
invoke DeviceIoControl,hVxD,1,addr InBuffer,8,NULL,NULL,NULL,NULL
invoke CloseHandle,hVxD
invoke MessageBox,NULL,addr Unload,addr AppName,MB_OK+MB_ICONINFORMATION
.else
invoke MessageBox,NULL,addr Failure,NULL,MB_OK+MB_ICONERROR
.endif
invoke ExitProcess,NULL
end start
.386p
include vmm.inc
include vwin32.inc
include shell.incDECLARE_VIRTUAL_DEVICE SHELLMSG,1,0, SHELLMSG_Control,\
UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDERBegin_control_dispatch SHELLMSG
Control_Dispatch w32_DeviceIoControl, OnDeviceIoControl
End_control_dispatch SHELLMSGVxD_PAGEABLE_DATA_SEG
pTitle dd ?
pMessage dd ?
VxD_PAGEABLE_DATA_ENDSVxD_PAGEABLE_CODE_SEG
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode==DIOC_Open
xor eax,eax
.elseif [esi].dwIoControlCode==1
mov edi,[esi].lpvInBuffer
;-----------------------------------
; copy the message title to buffer
;-----------------------------------
VMMCall _lstrlen, <[edi]>
inc eax
push eax
VMMCall _HeapAllocate,<eax,HEAPZEROINIT>
mov pTitle,eax
pop eax
VMMCall _lstrcpyn,<pTitle,[edi],eax>
;-----------------------------------
; copy the message text to buffer
;-----------------------------------
VMMCall _lstrlen, <[edi+4]>
inc eax
push eax
VMMCall _HeapAllocate,<eax,HEAPZEROINIT>
mov pMessage,eax
pop eax
VMMCall _lstrcpyn,<pMessage,[edi+4],eax>
mov edi,pTitle
mov ecx,pMessage
mov eax,MB_OK
VMMCall Get_Sys_VM_Handle
VxDCall SHELL_sysmodal_Message
VMMCall _HeapFree,pTitle,0
VMMCall _HeapFree,pMessage,0
xor eax,eax
.endif
ret
EndProc OnDeviceIoControl
VxD_PAGEABLE_CODE_ENDSend
invoke CreateFile,addr VxDName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0We call CreateFile to load the dynamic VxD. Note FILE_FLAG_DELETE_ON_CLOSE flag. This flag instructs Windows to unload the VxD when the VxD handle returned from CreateFile is closed. If CreateFile is successful, we store the VxD handle for future use.
.if eax!=INVALID_HANDLE_VALUE
mov hVxD,eax
....
.else
invoke MessageBox,NULL,addr Failure,NULL,MB_OK+MB_ICONERROR
.endif
invoke MessageBox,NULL,addr Success,addr AppName,MB_OK+MB_ICONINFORMATIONThe program displays a message box when the VxD is loaded/unloaded. It calls DeviceIoControl with dwIoControlCode 1 and passes the address of InBuffer in lpInBuffer parameter, and the size of InBuffer (8) in nInBufferSize. InBuffer is a dword array of two elements: each element is the address of a text string.
invoke DeviceIoControl,hVxD,1,addr InBuffer,8,NULL,NULL,NULL,NULL
invoke CloseHandle,hVxD
invoke MessageBox,NULL,addr Unload,addr AppName,MB_OK+MB_ICONINFORMATION
MsgTitle db "DeviceIoControl Example",0Now we turn our attention to the VxD.
MsgText db "I'm called from a VxD!",0
InBuffer dd offset MsgTitle
dd offset MsgText
BeginProc OnDeviceIoControlOnDeviceIoControl processes DIOC_Open code by returning 0 in eax.
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode==DIOC_Open
xor eax,eax
.elseif [esi].dwIoControlCode==1It also processes control code 1. The first thing it does is to extract the data in lpvInBuffer which are the two dwords passed in lpInBuffer of DeviceIoControl API. It puts the address to the dword array into edi for extraction. The first dword is the address of the text to be used as the message box title. The second dword is the address of the text to be used as the message box text.
mov edi,[esi].lpvInBuffer
;-----------------------------------It calculates the length of the message box title by calling VMM service _lstrlen. The value in eax returned by _lstrlen is the length of the string. We increase the length by 1 to take into account the terminating NULL. Next we allocate a block of memory large enough to hold the string with its terminating NULL by calling _HeapAllocate. HEAPZEROINIT flag instructs _HeapAllocate to zero out the memory block. _HeapAllocate returns the address of the memory block in eax. We then copy the string from the address space of the win32 app into the memory block we allocated. We do the same operation on the text string that we will use as the message box text.
; copy the message title to buffer
;-----------------------------------
VMMCall _lstrlen, <[edi]>
inc eax
push eax
VMMCall _HeapAllocate,<eax,HEAPZEROINIT>
mov pTitle,eax
pop eax
VMMCall _lstrcpyn,<pTitle,[edi],eax>
mov edi,pTitleWe store the addresses of the title and message into edi and ecx, respectively. Put the desired flag into eax, obtain the VM handle of the system VM by calling Get_Sys_VM_handle and then call SHELL_Sysmodal_Message. SHELL_SysModal_Message is the system modal version of SHELL_Message. It freezes the system until the user responds to the message box.
mov ecx,pMessage
mov eax,MB_OK
VMMCall Get_Sys_VM_Handle
VxDCall SHELL_sysmodal_Message
VMMCall _HeapFree,pTitle,0When SHELL_Sysmodal_Message returns, we can free the memory blocks by calling _HeapFree.
VMMCall _HeapFree,pMessage,0