在 VxD(Ring 0)與 V86 模式程式(Real Mode,如 DOS 程式、BIOS 服務)交互時,面臨兩大難題:
段:偏移 (16:16),Ring 0 使用 32 位線性位址。直接傳遞線性位址給 V86 程式會導致存取錯誤或崩潰。V86 記憶體管理器(V86MMGR)提供標準化解決方案:API 傳輸 與 API 映射。
V86MMGR_Set_Mapping_Info 調整大小。; 輸入
EBX = 當前 VM Handle
EBP = Client Register Structure 指標 (被中斷 V86 程式暫存器影像)
ECX = 要求位元組數
CF = 1 複製 Ring 0 資料到緩衝區, 0 僅分配不複製
FS:ESI = Ring 0 來源緩衝區 (Selector:Offset),CF=1 時有效
; 輸出 (成功 CF=0)
ECX = 實際分配位元組數 (≤ 要求值,需保存供 Free_Buffer 使用)
EDX:EDI = V86 緩衝區位址 (EDX=段, DI=偏移) — 供 V86 程式使用
; 失敗 CF=1
; 輸入參數與 Allocate_Buffer 相同
; CF=1 時從 V86 緩衝區複製資料到 FS:ESI 指向的 Ring 0 緩衝區
; 自動釋放最近一次 Allocate_Buffer 分配的緩衝區 (LIFO)
完整流程:分配緩衡區 → 設定 V86 暫存器 → 模擬中斷 → 釋放緩衝區取回資料 → 傳回 Ring 3 應用程式。
OnDeviceIoControl:
; 1. 取得系統 VM Handle 與 Client Register 指標
VMMCall Get_Sys_VM_Handle
mov Handle, ebx
assume ebx:ptr cb_s
mov ebp, [ebx+CB_Client_Pointer]
; 2. 分配傳輸緩衝區並複製輸出結構體模板
mov ecx, sizeof MID
stc ; CF=1 複製資料
push esi
mov esi, OFFSET32 MediaID
push ds
pop fs ; FS = DS (平坦模式 Selector)
VxDCall V86MMGR_Allocate_Buffer
pop esi
jc EndI
mov AllocSize, ecx ; 保存實際分配大小
; 3. 準備 V86 暫存器影像執行 INT 21h
Push_Client_State
VMMCall Begin_Nest_V86_Exec
assume ebp:ptr Client_Byte_Reg_Struc
mov [ebp].Client_CH, 8 ; CH=8 (功能子代碼)
mov [ebp].Client_CL, 66h ; CL=66h (IOCTL 子功能)
assume ebp:ptr Client_Word_Reg_Struc
mov edx, edi ; EDI = V86 緩衝區位址 (段:偏移)
mov [ebp].Client_BX, 3 ; BL=磁碟機號 (3=C:)
mov [ebp].Client_AX, 440Dh ; AX=440Dh (IOCTL)
mov [ebp].Client_DX, dx ; DX=偏移
shr edx, 16
mov [ebp].Client_DS, dx ; DS=段
mov eax, 21h
VMMCall Exec_Int ; 模擬 INT 21h
VMMCall End_Nest_Exec
Pop_Client_State
; 4. 釋放緩衝區並取回資料
mov ecx, AllocSize
stc
mov ebx, Handle
push esi
mov esi, OFFSET32 MediaID
push ds
pop fs
VxDCall V86MMGR_Free_Buffer
pop esi
; 5. 複製卷標字串到 Ring 3 輸出緩衝區
mov edx, esi
assume edx:ptr DIOCParams
mov edi, [edx].lpvOutBuffer
mov esi, OFFSET32 MediaID.midVolLabel
mov ecx, 11
rep movsb
mov byte ptr [edi], 0
mov ecx, [edx].lpcbBytesReturned
mov dword ptr [edx], 11
EndI:
xor eax, eax
ret
MID STRUC
midInfoLevel DW 0
midSerialNum DD ?
midVolLabel DB 11 DUP(?) ; 卷標 (11 字元)
midFileSysType DB 8 DUP(?) ; 檔案系統類型
MID ENDS
MediaID MID <>
Handle DD ?
AllocSize DD ?
invoke DeviceIoControl, hVxD, 1, NULL, 0, addr DiskLabel, 12, addr BytesReturned, NULL
invoke MessageBox, hDlg, addr DiskLabel, addr Template, MB_OK+MB_ICONINFORMATION
DiskLabel 接收 11 字元卷標 + 結束 0V86MMGR_Map_PagesV86MMGR 的 API 傳輸機制優雅解決了 Ring 0 與 V86 模式間的大量資料交換與定址轉換問題。掌握「分配→設定暫存器→模擬中斷→釋放取回」標準流程,配合 Push_Client_State/Exec_Int 等輔助服務,即可實現 VxD 與 Real Mode 程式(DOS、BIOS、啟動扇區代碼)的深度互操作。此技術雖屬 9x 時代,但其設計思想(跨特權級緩衝區管理、上下文保存/恢復、模擬執行環境)在現代虛擬化、沙箱、相容性層中依然閃耀著工程智慧的光芒。