VxD Example: MessageBox

In the previous tutorials, you learn about mechanics of VxD programming. Now is the time to apply what you have learned. In this tutorial, we will create a simple static VxD which will display a message box whenever a VM is created/destroyed.
Download the example here.

Trapping VM creation and termination events

When a VM is created, the VMM sends Create_VM control message to all VxDs. Also when a VM is terminated normally, it sends VM_Terminate and VM_Terminate2 to all VxDs. Our job is easy: Process Create_VM and VM_Terminate2 messages in our device control procedure. When our VxD receives those two control messages, it displays a message box on the screen.
When our VxD receives Create_VM or VM_Terminate2 message, ebx contains the handle of the VM. A VM handle can be considered as the unique ID of the VM. Each VM has its unique ID (VM handle). You can use VM handle in the same manner as you use a process ID, by passing it as a parameter to the services that need it.
On close examination, a VM handle is actually the 32-bit linear address of the VM control block (VMCB).
VM Control Block is a structure that contains several important items about the VM. It's defined as:

Displaying a MessageBox

A VxD can use Virtual Shell Device services to communicate to the users. One such service we will use in this example is SHELL_Message.
SHELL_Message is a register-based service. You pass parameters to it via registers. On return, the carry flag is clear if the call is successful. The carry flag is set otherwise.

The example

.386p
include vmm.inc
include shell.inc

DECLARE_VIRTUAL_DEVICE MESSAGE,1,0, MESSAGE_Control, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER

Begin_control_dispatch MESSAGE
    Control_Dispatch Create_VM, OnVMCreate
    Control_Dispatch VM_Terminate2, OnVMClose
End_control_dispatch MESSAGE

VxD_PAGEABLE_DATA_SEG
    MsgTitle db "VxD MessageBox",0
    VMCreated db "A VM is created",0
    VMDestroyed db "A VM is destroyed",0
VxD_PAGEABLE_DATA_ENDS

VxD_PAGEABLE_CODE_SEG
BeginProc OnVMCreate
    mov ecx, OFFSET32 VMCreated
CommonCode:
    VMMCall Get_sys_vm_handle
    mov eax,MB_OK+MB_ICONEXCLAMATION
    mov edi, OFFSET32 MsgTitle
    xor esi,esi
    xor edx,edx
    VxDCall SHELL_Message
    ret
EndProc OnVMCreate

BeginProc OnVMClose
    mov ecx,OFFSET32 VMDestroyed
    jmp CommonCode
EndProc OnVMClose
VxD_PAGEABLE_CODE_ENDS

end

Analysis:

Begin_control_dispatch MESSAGE
    Control_Dispatch Create_VM, OnVMCreate
    Control_Dispatch VM_Terminate2, OnVMClose
End_control_dispatch MESSAGE
The VxD processes two control messages, Create_VM and VM_Terminate2. When Create_VM control message is received, it calls OnVMCreate procedure. And when it receives VM_Terminate2 message, it calls OnVMClose procedure.
VxD_PAGEABLE_DATA_SEG
    MsgTitle db "VxD MessageBox",0
    VMCreated db "A VM is created",0
    VMDestroyed db "A VM is destroyed",0
VxD_PAGEABLE_DATA_ENDS
We put the data in the pageable data segment.
BeginProc OnVMCreate
    mov ecx, OFFSET32 VMCreated
CommonCode:
    VMMCall Get_sys_vm_handle
    mov eax,MB_OK+MB_ICONEXCLAMATION
    mov edi, OFFSET32 MsgTitle
    xor esi,esi
    xor edx,edx
    VxDCall SHELL_Message
    ret
EndProc OnVMCreate
OnVMCreate procedure is created using BeginProc and EndProc macros. It puts the parameters for SHELL_Message service into the registers. Since we want to display the message box in the system VM, we cannot use the value in ebx (which is the handle of the VM that is being created). Instead, we use a VMM service, Get_Sys_VM_Handle, to obtain the VM handle of the system VM. This service returns the VM handle in ebx. We put the addresses of the message and the caption into ecx and edi, respectively. We don't want to know the response of the user, so we zero out esi and edx. When all parameters are in the appropriate registers, we call SHELL_Message to display the message box.
BeginProc OnVMClose
    mov ecx,OFFSET32 VMDestroyed
    jmp CommonCode
EndProc OnVMClose
OnVMClose procedure is simplicity in itself. Since it uses identical code as OnVMCreate, it initializes ecx with the address of the different message and then jumps to the code inside OnVMCreate.

Module Definition File

VXD MESSAGE

SEGMENTS
    _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

    MESSAGE_DDB  @1

Assembling process

 ml -coff -c -Cx  -DMASM6 -DBLD_COFF -DIS_32 message.asm

 link -vxd -def:message.def message.obj

VxD Installation

  1. Put message.vxd in \system folder
  2. add the following line inside [386enh] section of system.ini
    1. device=message.vxd
  3. reboot your computer

Testing the VxD

Create a DOS box. You will see the message box, displaying the message, "A VM is created". When you close the DOS box, a message box appears with the message, "A VM is destroyed".

[Iczelion's Win32 Assembly Homepage]