虛擬裝置驅動程式(VxD)在 Ring 0 執行,透過控制訊息分派器響應 VMM(虛擬機管理器)發送的系統事件。本範例示範靜態 VxD 攔截兩個關鍵虛擬機生命週期事件:
Create_VM:新虛擬機建立(如啟動 DOS 視窗)VM_Terminate2:虛擬機銷毀(關閉 DOS 視窗)VxD 可透過 VxDCall SHELL_Message 在指定虛擬機顯示訊息框(類似 Ring 3 的 MessageBox):
; 參數透過暫存器傳遞
EBX = 目標虛擬機控制塊 (VMCB) 線性位址 (即 VM handle)
EAX = 訊息框旗標 (MB_OK, MB_ICONEXCLAMATION 等,定義於 shell.inc)
ECX = 訊息字串 32-bit 線性位址
EDI = 標題字串 32-bit 線性位址
ESI = 回呼函數位址 (NULL 表示不需回呼)
EDX = 回呼函數參數
; 返回:CF=0 成功,CF=1 失敗
.386p
include vmm.inc
include shell.inc
; 裝置宣告:名稱 MESSAGE, 版本 1.0, 控制程序 MESSAGE_Control
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 ; 訊息字串
jmp CommonCode
EndProc OnVMCreate
BeginProc OnVMClose
mov ecx, OFFSET32 VMDestroyed ; 訊息字串
jmp CommonCode
EndProc OnVMClose
CommonCode:
; 取得系統虛擬機控制代碼 (EBX 目前是新建立/銷毀的 VM,非系統 VM)
VMMCall Get_Sys_VM_Handle ; 返回 EBX = 系統 VM handle
mov eax, MB_OK + MB_ICONEXCLAMATION
mov edi, OFFSET32 MsgTitle
xor esi, esi ; 無回呼
xor edx, edx
VxDCall SHELL_Message
ret
VxD_PAGEABLE_CODE_ENDS
end
Begin_Control_Dispatch / Control_Dispatch / End_Control_Dispatch 自動產生控制程序入口點,將 VMM 發送的訊息 ID 對應到處理函數。VMM 會在適當時機呼叫 MESSAGE_Control,由巨集生成的跳轉表分派。
| 段類型 | 巨集 | 特性 | 適用場景 |
|---|---|---|---|
| 可分頁代碼 | VxD_PAGEABLE_CODE_SEG/ENDS | 可被換出至磁碟 | 非即時、非中斷處理的一般函數 |
| 鎖定代碼 | VXD_LOCKED_CODE_SEG/ENDS | 常駐記憶體 | 中斷處理、高優先級回呼、分頁錯誤處理 |
| 可分頁資料 | VxD_PAGEABLE_DATA_SEG/ENDS | 可分頁 | 一般變數、字串 |
| 鎖定資料 | VXD_LOCKED_DATA_SEG/ENDS | 常駐 | 中斷服務常式需存取的資料、共享緩衝區 |
本範例的訊息處理非即時,故置於可分頁段。
Create_VM / VM_Terminate2 到達時,EBX = 觸發事件的目標 VM Handle。VMMCall Get_Sys_VM_Handle 取得系統 VM Handle 覆蓋 EBX。cb_s STRUC
CB_VM_Status DD ? ; VM 狀態旗標
CB_High_Linear DD ? ; 系統共享區映射基址 (對應 VM 的 V86 區域)
CB_Client_Pointer DD ? ; Client Register Structure 指標 (被中斷程式的暫存器影像)
CB_VMID DD ? ; VM 識別碼 (系統 VM = 1)
CB_Signature DD ? ; "VMcb" 簽章,用於驗證 handle 有效性
cb_s ENDS
指定段屬性與匯出符號,確保 VxD 正確載入:
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
_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
ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32 message.asm
link -VxD -def:message.def message.obj
-VxD:連結器產生 VxD 格式 (LE 可執行檔)-def:指定模組定義檔message.vxd 複製到 C:\WINDOWS\SYSTEM\C:\WINDOWS\SYSTEM.INI,在 [386Enh] 區段加入:device=message.vxdDYNAMIC 關鍵字,配合 CreateFile("\\.\vxdname.vxd") 從 Ring 3 載入/卸載,無需修改 SYSTEM.INI 重開機。W32_DeviceIoControl 處理函數,配合 DeviceIoControl 實現雙向資料交換。VM_Suspend/VM_Resume (暫停/繼續)、Destroy_VM、Device_Init 等。Hook_V86_Int_Chain、Set_PM_Int 攔截中斷,實現硬體監控或虛擬化。本範例展示了 VxD 開發的核心流程:裝置宣告、控制訊息分派、段屬性管理、VMM/VxD 服務呼叫、共享資料處理、建置部署。雖然 Windows 9x 已退出歷史舞台,但 VxD 架構對理解 Windows 核心設計、Ring 0 程式設計、虛擬化技術仍具極高參考價值。