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

Windows 虛擬設備驅動程序 (VxD) 深度解析(二):初始化、服務與構建

     編輯:關於C++

八、VxD 初始化流程

當虛擬機器管理器 (VMM) 初始化一個 VxD 時,會依序執行以下六個關鍵步驟:

  1. 載入實模式初始化段並呼叫實模式初始化程序:此程序可決定是否阻止 VxD 載入、阻止 Windows 啟動、指定設備實例資料,以及在記憶體中選取分頁供設備專用。
  2. 載入 VxD 其他段至 32 位平坦記憶體模式的保護模式記憶體,並捨棄實模式初始化段。
  3. 發送 Sys_Critical_Init 訊息至裝置控制程序:此時硬體中斷被禁止,VxD 應儘快完成自身初始化。
  4. 發送 Device_Init 訊息至裝置控制程序:硬體中斷已允許,VxD 必須準備好管理來自設備的中斷。
  5. 發送 Init_Complete 訊息至裝置控制程序。
  6. 捨棄初始化程式碼與資料段,釋放其他已用記憶體:VxD 在處理完 Init_Complete 後,不得嘗試存取這些段中的程序與資料。

在初始化過程的任何時刻,VxD 均可設定進位旗標返回 VMM 以阻止載入。部分 VMM 服務(如初始化資訊服務)僅在初始化期間有效。

九、實模式初始化

任何靜態裝置驅動程式均可提供實模式初始化程序,在 Windows 切換至保護模式前執行初始化任務。VMM 載入 VxD 時會呼叫該程序,其可檢查 Windows 環境(包括登錄檔與初始化檔設定)以決定是否應載入該 VxD。該程序亦可向 Windows 回傳資訊,為每個虛擬機器的實例指定保留給設備專用的實體記憶體分頁與資料項位址。

十、VxD 服務機制

VxD 可提供服務功能(函數或程序)供 VMM 與其他 VxD 使用,使其能直接存取該 VxD 的特性、測試並修改其功能。VxD 無法像 Windows DLL 那樣導出函數,而是透過 INT 20H 由 VMM 提供動態連結至 VxD 服務。中斷處理程序依服務編號判斷支援該服務的 VxD,並查詢 VxD 服務表中的服務位址。

1. 定義服務

VxD 使用 BeginProc/EndProc 巨集搭配 Service 與 Async_Service 選項定義服務。巨集標記服務程式碼的起止,選項標識該程序為服務。範例:

BeginProc VSAMPLED_Get_Version, Service
mov ax, 030Ah
clc
ret
EndProc VSAMPLED_Get_Version

Async_Service 表示該服務可被非同步呼叫(如在中斷處理中呼叫)。非同步服務必須可重入,且不得呼叫 VMM 與非非同步的 VxD 服務。

VMM 與標準 VxD 採用兩種呼叫慣例:

  • 基於暫存器的慣例:服務名不以下劃線開頭,參數與結果皆透過暫存器傳遞,服務保護所有未明確用於回傳值的暫存器。
  • 基於 32 位 C 語言的慣例:服務名以下劃線(_)開頭,參數透過堆疊中的 32 位值傳遞,結果透過 EAX(32 位)或 EAX/EDX(64 位)回傳,服務保護 EBX、ES、FS、GS、ESI、EDI,僅修改旗標暫存器與 EAX、EBX、EDX。

2. 宣告服務表

VxD 使用 Begin_Service_Table/End_Service_Table 巨集宣告服務表,標記包含服務名與選用段名的列表。宣告必須置於含 Declare_Virtual_Device 巨集的檔案中,且須先定義裝置指定符號。範例:

Create_VSAMPLED_Service_Table equ 1
Begin_Service_Table VSAMPLED
VSAMPELD_Service VSAMPLED_Get_Version, Local
VSAMPLED_Service VSAMPLED_Service_1
VSAMPLED_Service VSAMPLED_Service_2, VxD_ICODE
End_Service_Table VSAMPLED
  • Create_VSAMPLED_Service_Table 符號指示為 VSAMPLED 建立服務表。
  • 服務名必須與 BeginProc 定義的名稱完全一致。
  • 若服務定義於含服務表宣告的檔案中,需加 LOCAL 選項;否則視為外部服務。
  • 若服務不在 VxD_CODE 區段,需註明區段名(如 VxD_ICODE)。
  • 服務宣告順序極重要:第一個必須是 Get_Version 服務(清除進位旗標並在 AX 回傳版本號),新服務必須附加於表尾或保留空間中。插入服務會導致所有使用該 VxD 服務的 VxD 需重建。
  • 為方便其他 VxD 引用,服務表宣告宜置於包含檔中。

3. 引入服務

VxD 可透過包含另一 VxD 的服務表宣告來引入其服務,此時裝置指定符號定義不得先於服務表宣告。呼叫端使用 VMMcall 巨集呼叫 VMM 服務,VxDcall 巨集呼叫 VxD 服務。由於電腦配置不同,VxD 可能在啟動時載入失敗,因此呼叫端必須在呼叫前驗證目標 VxD 服務是否有效:嘗試呼叫其 Get_Version,若 VxD 未載入,VMM 會設定進位旗標並在 AX 回傳 0。

十一、VxD API 程序

VxD 可提供 V86 模式與保護模式 API 程序,允許虛擬機中執行的應用程式存取 VxD 功能。若要啟用,必須在 Declare_Virtual_Device 巨集參數中定義。應用程式將 BX 設為 VxD 識別碼,呼叫 INT 2FH 功能 1684H 取得特定虛擬機 API 程序入口位址,VMM 回傳位址供應用程式間接呼叫。

呼叫時,VMM 保存應用程式暫存器並呼叫 VxD API 程序,將目前虛擬機控制代碼置於 BX,Client_Reg_Struc 結構位址置於 EBP。API 程序必須檢測客戶暫存器值(透過 Client_Reg_Struc)判斷呼叫功能。慣例上,AH 指定主功能號,AL 指定次功能號,其他暫存器作參數。API 程序透過修改客戶暫存器回傳值,可修改 EAX、EBX、ECX、EDX、ESI、EDI。

BeginProc VSAMPLED_API_Get_Version
movzx eax, [ebp.Client_AX] ; 取功能號
or eax, eax
jnz Undefined
Get_Version:
mov [ebp.Client_AX], 030AH ; 在客戶暫存器 AX 回傳值
and [ebp.Client_Flags], NOT CF_Mask ; 清除進位旗標
ret
Undefined:
or [ebp.Client_Flags], CF_Mask ; 設定進位旗標
ret
EndProc VSAMPLED_API_Get_Version

十二、VxD INT 2FH 功能

VxD 可為 INT 2FH 中斷安裝回呼程序以提供功能,允許應用程式在 VxD 未提供 API 程序時存取 VxD(如標準虛擬顯示裝置支援與 Windows 顯示驅動程式通訊的 INT 2FH 功能集)。Windows 自身安裝 INT 2FH 處理程序支援多種功能,允許 MS-DOS 裝置驅動程式與 TSR 在 Windows 啟動或虛擬機運行時執行特定動作。

十三、建立 VxD 步驟

  1. 建立 VxD 來源檔,使用 32 位平坦模式組譯器 MASM.EXE(MASM 6.11+)組譯。
  2. 建立模組定義檔(.DEF),使用 32 位平坦模式連結器 LINK.EXE 連結目標檔。慣例上輸出檔名與 VxD 同名,副檔名為 .VXD。
  3. 使用 MAPSYM.EXE 為可執行檔建立除錯資訊。

VxD 不與 Windows DLL 相容,Windows 應用程式無法直接載入使用。但 Win32 應用程式可透過 CreateFile 與 DeviceIoControl 載入動態載入的 VxD 並互動。模組定義檔格式範例:

LIBRARY VSAMPLED
DESCRIPTION 'VSAMPLED Device (Version 4.0)'
EXETYPE DEV386
SEGMENTS
_LTEXT PRELOAD NONDISCARDABLE
_LDATA PRELOAD NONDISCARDABLE
_ITEXT CLASS 'ICODE' DISCARDABLE
_IDATA CLASS 'ICODE' DISCARDABLE
_TEXT CLASS 'PCODE' NONDISCARDABLE
_DATA CLASS 'PCODE' NONDISCARDABLE
EXPORTS
VSAMPLED_DDB @1

LIBRARY 必須指定與裝置描述區塊(DDB)相同的 VxD 名稱,EXPORTS 必須指定 DDB 名稱,DDB 匯出序數固定為 1。

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