首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

V86 模式記憶體管理實戰:V86MMGR API 傳輸緩衝區與 Ring 0/Real Mode 資料交換

     編輯:組合語言

背景與挑戰

在 VxD(Ring 0)與 V86 模式程式(Real Mode,如 DOS 程式、BIOS 服務)交互時,面臨兩大難題:

  1. 大量資料傳輸:暫存器僅能傳遞少量參數,無法承載結構體、緩衝區。
  2. 定址模式不兼容:V86 使用 段:偏移 (16:16),Ring 0 使用 32 位線性位址。直接傳遞線性位址給 V86 程式會導致存取錯誤或崩潰。

V86 記憶體管理器(V86MMGR)提供標準化解決方案:API 傳輸 與 API 映射。

核心機制:傳輸緩衝區

  • 位於 V86 記憶體範圍(1MB 以下)的一塊專用記憶體,預設 4KB。
  • 雙向通道:Ring 0 ↔ V86 緩衝區資料複製。
  • 管理方式:堆疊式 (LIFO),分配/釋放必須嚴格配對、逆序釋放。
  • 可擴充:V86MMGR_Set_Mapping_Info 調整大小。

關鍵服務詳解

V86MMGR_Allocate_Buffer — 分配並複製 Ring 0 → V86

; 輸入
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

V86MMGR_Free_Buffer — 複製 V86 → Ring 0 並釋放

; 輸入參數與 Allocate_Buffer 相同
; CF=1 時從 V86 緩衝區複製資料到 FS:ESI 指向的 Ring 0 緩衝區
; 自動釋放最近一次 Allocate_Buffer 分配的緩衝區 (LIFO)

實戰範例:取得磁碟機卷標 (INT 21h/440Dh/66h)

完整流程:分配緩衡區 → 設定 V86 暫存器 → 模擬中斷 → 釋放緩衝區取回資料 → 傳回 Ring 3 應用程式。

VxD 代碼關鍵片段

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 ?

Ring 3 應用程式端

invoke DeviceIoControl, hVxD, 1, NULL, 0, addr DiskLabel, 12, addr BytesReturned, NULL
invoke MessageBox, hDlg, addr DiskLabel, addr Template, MB_OK+MB_ICONINFORMATION
  • 控制碼 1 觸發上述 VxD 邏輯
  • 無輸入緩衝區,輸出緩衝區 DiskLabel 接收 11 字元卷標 + 結束 0

API 映射:另一種跨模式資料共享方式

  • 將擴充記憶體頁面映射到所有 VM 的 V86 線性位址空間同一位置。
  • 服務:V86MMGR_Map_Pages
  • 適用場景:多個 VM 需同時存取同一資料結構(如全域狀態、共享緩衝區)。
  • 缺點:比 API 傳輸慢,消耗全域線性位址空間,僅在必要時使用。

關鍵技術點總結

  1. LIFO 原則:嚴格配對 Allocate/Free,順序錯誤會導致緩衝區洩漏或資料錯亂。
  2. Client Register Structure:修改此結構體即修改 V86 程式恢復執行時的暫存器值,實現參數傳遞與結果返回。
  3. Begin/End_Nest_V86_Exec:建立/銷毀巢狀 V86 執行環境,支援在 VxD 內安全模擬中斷。
  4. Exec_Int:模擬指定中斷向量,自動處理保護模式到 V86 的切換。
  5. 段:偏移轉換:EDI 回傳的 32 位值,高 16 位=段,低 16 位=偏移,需拆解填入 DS:DX 等暫存器影像。

總結

V86MMGR 的 API 傳輸機制優雅解決了 Ring 0 與 V86 模式間的大量資料交換與定址轉換問題。掌握「分配→設定暫存器→模擬中斷→釋放取回」標準流程,配合 Push_Client_State/Exec_Int 等輔助服務,即可實現 VxD 與 Real Mode 程式(DOS、BIOS、啟動扇區代碼)的深度互操作。此技術雖屬 9x 時代,但其設計思想(跨特權級緩衝區管理、上下文保存/恢復、模擬執行環境)在現代虛擬化、沙箱、相容性層中依然閃耀著工程智慧的光芒。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved