windows過濾中裝置綁定的核心API之一
進行過濾的最主要的方法是對一個裝置對象(Device Object)進行綁定。讀者可以想象,Windows系統之所以可以運作,是因為Windows中已經存在許多提供了各種功能的裝置對象。這些裝置對象接收請求,並完成實際硬體的功能。
我們可以首先認為:一個真實的裝置對應一個裝置對象(雖然實際對應關係可能複雜得多)。通過編程可以產生一個虛擬裝置對象,並“綁定”(Attach)在一個真實的裝置上。一旦綁定,則本來作業系統發送給真實裝置的請求,就會首先發送到這個虛擬設備。
下面結合代碼進行講解。讀者可能希望編譯執行這些代碼,驅動的初學者請先閱讀本書第1章,以便學會如何安裝開發環境、編譯代碼和偵錯工具。
在WDK中,有多個核心API能實現綁定功能。下面是其中一個函數的原型:
NTSTATUS
IoAttachDevice(
IN PDEVICE_OBJECT SourceDevice,
IN PUNICODE_STRING TargetDevice,
OUT PDEVICE_OBJECT *AttachedDevice
);
IoAttachDevice參數如下:
SourceDevice是調用者產生的用來過濾的虛擬設備;而TargetDevice是要被綁定的目標裝置。請注意這裡的TargetDevice並不是一個PDEVICE_OBJECT(DEVICE_OBJECT是裝置對象的資料結構,以P開頭的是其指標),而是一個字串(在驅動開發中字串用UNICODE_STRING來表示)。實際上,這個字串是要被連結的裝置的名字。
Windows中許多裝置對象是有名字的,但是並不是所有的裝置對象都有名字。必須是有名字的裝置,才能用這個核心API進行綁定。
這裡有一個疑問:假設這個函數綁定一個名字所對應的裝置,那麼如果這個裝置已經被其他的裝置綁定了,會怎麼樣呢?
如果一個裝置被其他裝置綁定,它們在一起的一組裝置,被稱為裝置棧(之所以稱為棧,是由於和請求的傳遞方式有關)。實際上,IoAttachDevice總是會綁定裝置棧上最頂層的那個裝置。
AttachedDevice是一個用來返回的指標的指標。綁定成功後,被連結的裝置指標被返回到這個地址。
下面這個例子綁定串口1。之所以這裡綁定很方便,是因為在Windows中,串口裝置是有固定名字的。第一個串口名字為“/Device/Serial0”,第二個為“/Device/Serial1”,依次類推。請注意實際編碼時C語言中的“/”要寫成“//”。
UNICODE_STRING com_name = RLT_CONSTANT_STRING(L"//Device//Serial0");
NTSTATUS status = IoAttachDevice(
com_filter_device, // 產生的過濾裝置
&com_device_name, // 串口的裝置名稱
&attached_device); // 被連結的裝置指標返回到這裡
當然,試圖執行這段代碼的讀者可能會發現,這裡沒有提供如何產生一個過濾裝置的代碼。在接下來的第二個API介紹之後,讀者會看到完整的例子。