DeviceIoControl 是 Win32 應用程式與動態 VxD 通訊的標準橋樑,實現 Ring-3 到 Ring-0 的受控呼叫。本文完整解析四大 VxD 介面架構、DeviceIoControl 參數結構、DIOCParams 解析、最小動態 VxD 框架與完整計算機啟動範例,掌握核心模組開發關鍵技術。
| 介面 | 呼叫者 | 位元寬度 | 用途 |
|---|---|---|---|
| VxD Services | VxD 間、VMM | 32-bit | 核心服務呼叫(VMMCall/VxDCall) |
| V86 Interface | V86 模式程式 | 16-bit | DOS/Win16 應用呼叫 VxD |
| Protected-Mode Interface | 保護模式 16-bit 程式 | 16-bit | Win16 DLL/驅動呼叫 VxD |
| Win32 DeviceIoControl | Win32 應用程式 | 32-bit | 標準 Ring-3 ↔ Ring-0 通道 |
invoke CreateFile, addr VxDName, 0, 0, 0, 0, \
FILE_FLAG_DELETE_ON_CLOSE, 0
; VxDName = "\\.\shellmsg.vxd"
; 成功 → EAX = 裝置控制代碼
; 失敗 → EAX = INVALID_HANDLE_VALUE
FILE_FLAG_DELETE_ON_CLOSE:關閉控制代碼時自動卸載 VxD。\\.\完整路徑 或 \\.\檔名(同目錄)。invoke DeviceIoControl, hVxD, 1, addr InBuffer, 8, \
NULL, NULL, NULL, NULL
; hVxD : CreateFile 回傳控制代碼
; 1 : dwIoControlCode (自訂操作碼)
; addr InBuffer : 輸入緩衝區位址
; 8 : nInBufferSize (位元組)
; NULL... : 無輸出緩衝區
收到訊息時 ESI 指向此結構:
DIOCParams STRUC
Internal1 DD ? ; Win32 用戶暫存器結構指標
VMHandle DD ? ; 虛擬機控制代碼
Internal2 DD ? ; DDB 指標
dwIoControlCode DD ? ; 控制碼 (對應 DeviceIoControl 第 2 參數)
lpvInBuffer DD ? ; 輸入緩衝區線性位址
cbInBuffer DD ? ; 輸入緩衝區大小
lpvOutBuffer DD ? ; 輸出緩衝區線性位址
cbOutBuffer DD ? ; 輸出緩衝區大小
lpcbBytesReturned DD ? ; 實際寫入輸出位元組數指標
lpoOverlapped DD ? ; OVERLAPPED 結構指標
hDevice DD ? ; Ring-3 裝置控制代碼
tagProcess DD ? ; 處理序標記
DIOCParams ENDS
.386p
include vmm.inc
include vwin32.inc
DECLARE_VIRTUAL_DEVICE DYNAVXD, 1, 0, DYNAVXD_Control, \
UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
Begin_Control_Dispatch DYNAVXD
Control_Dispatch W32_DeviceIoControl, OnDeviceIoControl
End_Control_Dispatch DYNAVXD
VxD_PAGEABLE_CODE_SEG
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode == DIOC_Open
xor eax, eax ; 允許開啟
.endif
ret
EndProc OnDeviceIoControl
VxD_PAGEABLE_CODE_ENDS
end
DIOC_Open(CreateFile 觸發),回傳 EAX=0 表示成功。DIOC_CloseHandle。.data
VxDName db "\\.\shellmsg.vxd",0
InBuffer dd offset MsgTitle
dd offset MsgText
MsgTitle db "DeviceIoControl Example",0
MsgText db "I'm called from a VxD!",0
.code
invoke CreateFile, addr VxDName, 0,0,0,0, FILE_FLAG_DELETE_ON_CLOSE, 0
.if eax != INVALID_HANDLE_VALUE
mov hVxD, eax
invoke DeviceIoControl, hVxD, 1, addr InBuffer, 8, NULL, NULL, NULL, NULL
invoke CloseHandle, hVxD
.endif
VxD_PAGEABLE_DATA_SEG
pTitle dd ?
pMessage dd ?
VxD_PAGEABLE_DATA_ENDS
VxD_PAGEABLE_CODE_SEG
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode == DIOC_Open
xor eax, eax
.elseif [esi].dwIoControlCode == 1 ; 自訂控制碼 1
mov edi, [esi].lpvInBuffer ; EDI → InBuffer 陣列
; 複製標題字串
VMMCall _lstrlen, <[edi]>
inc eax
push eax
VMMCall _HeapAllocate, <eax, HEAPZEROINIT>
mov pTitle, eax
pop eax
VMMCall _lstrcpyn, <pTitle, [edi], eax>
; 複製內文字串
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_ENDS
_lstrlen 取長 → _HeapAllocate 配置 Ring-0 堆疊 → _lstrcpyn 複製內容。SHELL_sysmodal_Message 凍結整個系統直到使用者回應,需 Get_Sys_VM_Handle 取得系統 VM 控制代碼。_HeapFree 釋放,避免核心記憶體洩漏。VXD SHELLMSG DYNAMIC
SEGMENTS
... (標準段定義)
EXPORTS
SHELLMSG_DDB @1
; VxD
ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32 shellmsg.asm
link -vxd -def:shellmsg.def shellmsg.obj
; Loader
ml /coff /c /Cp vxdloader.asm
link /subsystem:windows vxdloader.obj
執行 vxdloader.exe,點擊按鈕 → 載入 VxD → 彈出「I'm called from a VxD!」系統模態對話框 → 關閉 → 卸載 VxD。
DeviceIoControl 介面讓動態 VxD 成為 Win32 應用程式的 Ring-0 DLL 延伸,適用於硬體存取、即時處理、系統級監控等場景。核心要點:正確處理 DIOC_Open、解析 DIOCParams、跨 Ring 緩衝區複製、嚴格記憶體管理。本文範例提供最小框架與完整實戰範本,可直接作為專案起始點。