Client_Reg_Struc STRUCYou can see that there are two sets of members in this structure: Client_xxx and Client_Alt_xxx. This requires a little explanation. In a given VM, there can be two threads of execution: V86 and protected-mode. If an interrupt occurs when a V86 program is active, the Client_xxx will contain the images of the registers of the V86 program, the Client_Alt_xxx will contain those of the PM program. Alternately, if an interrupt occurs when the PM program is active, the Client_xxx will contain the values of the PM program's registers while the Client_Alt_xxx will contain the values of the V86 program's registers. The Client_resX are reserved and not used.Client_EDI DD ?Client_Reg_Struc ENDS
Client_ESI DD ?
Client_EBP DD ?
Client_res0 DD ?
Client_EBX DD ?
Client_EDX DD ?
Client_ECX DD ?
Client_EAX DD ?
Client_Error DD ?
Client_EIP DD ?
Client_CS DW ?
Client_res1 DW ?
Client_EFlags DD ?
Client_ESP DD ?
Client_SS DW ?
Client_res2 DW ?
Client_ES DW ?
Client_res3 DW ?
Client_DS DW ?
Client_res4 DW ?
Client_FS DW ?
Client_res5 DW ?
Client_GS DW ?
Client_res6 DW ?
Client_Alt_EIP DD ?
Client_Alt_CS DW ?
Client_res7 DW ?
Client_Alt_EFlags DD ?
Client_Alt_ESP DD ?
Client_Alt_SS DW ?
Client_res8 DW ?
Client_Alt_ES DW ?
Client_res9 DW ?
Client_Alt_DS DW ?
Client_res10 DW ?
Client_Alt_FS DW ?
Client_res11 DW ?
Client_Alt_GS DW ?
Client_res12 DW ?
cb_s STRUCCB_Client_Pointer contains the pointer to the client register structure of that VM. For example, you can obtain the pointer to the client register structure of the current VM by the following code:
CB_VM_Status DD ?
CB_High_Linear DD ?
CB_Client_Pointer DD ?
CB_VMID DD ?
CB_Signature DD ?
cb_s ENDS
VMMCall Get_Cur_VM_Handle ; return the current VM handle in ebxNow that we understand the client register structure, we can proceed to using it. We will use the client register structure to pass values in registers to an MS-DOS interrupt, namely, int 21h, service 2h, Display Character service. This MS-DOS service takes the character to be displayed in dl. If we pass the bell character (07h) to this service, it will play the bell through the PC speaker.
assume ebx:ptr cb_s
mov ebp,[ebx+CB_Client_Pointer] ; pointer to client reg struct
.386p
include \masm\include\vmm.inc
include \masm\include\vwin32.inc
include \masm\include\v86mmgr.incVxDName TEXTEQU <VXDINT>
ControlName TEXTEQU <VXDINT_Control>
VxDMajorVersion TEXTEQU <1>
VxDMinorVersion TEXTEQU <0>VxD_STATIC_DATA_SEG
VxD_STATIC_DATA_ENDSVXD_LOCKED_CODE_SEG
;----------------------------------------------------------------------------
; Remember: The name of the vxd MUST be uppercase else it won't work/unload
;----------------------------------------------------------------------------
DECLARE_VIRTUAL_DEVICE %VxDName,%VxDMajorVersion,%VxDMinorVersion, %ControlName,UNDEFINED_DEVICE_ID,UNDEFINED_INIT_ORDERBegin_control_dispatch %VxDName
Control_Dispatch W32_DEVICEIOCONTROL, OnDeviceIoControl
End_control_dispatch %VxDNameVXD_LOCKED_CODE_ENDS
VXD_PAGEABLE_CODE_SEG
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode==1
Push_Client_State
VMMCall Begin_Nest_V86_Exec
assume ebp:ptr Client_Byte_Reg_Struc
mov [ebp].Client_dl,7
mov [ebp].Client_ah,2
mov eax,21h
VMMCall Exec_Int
VMMCall End_Nest_Exec
Pop_Client_State
EndI:
.endif
xor eax,eax
ret
EndProc OnDeviceIoControl
VXD_PAGEABLE_CODE_ENDSend
Push_Client_StateThere is not much to analyze. When the VxD receives DeviceIoControl message, ebp already points to the current VM's client register structure. We call Push_Client_State macro to save the current state of the client registers on the stack. We later restore the client registers with Pop_Client_State.
VMMCall Begin_Nest_V86_ExecBegin the nested execution block by calling Begin_Nest_V86_Exec.
assume ebp:ptr Client_Byte_Reg_StrucAlter the images of dl and ah registers in the client register structure. This altered values will be used by the interrupt.
mov [ebp].Client_dl,7
mov [ebp].Client_ah,2
mov eax,21hExec_Int expects the interrupt number in eax. We want to issue int 21h. Then we call Exec_Int to simulate the interrupt.
VMMCall Exec_Int
VMMCall End_Nest_ExecWhen Exec_Int returns, we end the nested execution block and restore the saved values of the client registers from the stack.
Pop_Client_State