C++第四十篇 -- 研究一下Windows驅動開發(三)-- NT式驅動的基本結構

對於NT式驅動來講,主要的函數是DriverEntry例程、卸載例程及各個IRP的派遣例程。安全

1、驅動加載過程與驅動入口函數(DriverEntry)函數

和編寫普通應用程序同樣,驅動程序有個入口函數,也就是首先被執行的函數。這個函數一般被命名爲DriverEntry。該函數的原型爲:spa

NTSTATUS DriverEntry(
    _In_ PDRIVER_OBJECT  DriverObject,
    _In_ PUNICODE_STRING RegistryPath
    )

 

DriverEntry主要是對驅動程序進行初始化工做,它是由系統進程所調用的。在Windows中有個特殊的進程叫作系統進程,打開進程管理器,裏面有個名爲System的進程就是系統進程。系統進程在系統啓動的時候,就已經被建立了。線程

驅動加載的時候,系統進程啓動新的線程,調用執行體組件中的對象管理器,建立一個驅動對象。這個驅動對象是一個DRIVER_OBJECT的結構體。另外,系統進程調用執行體組件中的配置管理程序,查詢此驅動程序對應的註冊表中的項。指針

系統線程調用驅動程序的DriverEntry例程時,同時傳進兩個參數,分別是DriverObject和RegisreyPath。其中,一個是指向剛纔被建立驅動對象的指針,另一個是指向設備服務鍵的鍵名字符串的指針。在DriverEntry中,主要功能是對系統進程建立的驅動對象進行初始化。另外,設備服務鍵的鍵名有時候須要保存下來,由於這個字符串不是長期存在的(函數返回後可能消失)。若是之後想使用這個UNICODE字符串就必須先把它複製到安全的地方。code

這個字符串的內容通常是Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\服務名。在驅動程序中,字符串用INICODE字符串來表示。UNICODE是寬字符集,每一個字符用16位表示。對象

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
#ifdef MIDL_PASS
    [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
    _Field_size_bytes_part_opt_(MaximumLength, Length) PWCH   Buffer;
#endif // MIDL_PASS
}

 

》Length:記錄這個字符串用多少字節記錄。若是字符串有N個字符,那麼Length將會是N的2倍。blog

》MaximumLength:記錄buffer的大小,也就是這個結構最大能記錄的字節數。MaximumLength要大於或等於Length。接口

》Buffer:記錄字符串的指針。與ASCII字符串不一樣,這裏的字符串每一個字符否是16位。進程

在驅動中可使用KdPrint打印UNICODE的信息。其語法是:

KdPrint(("%S\n", RegistryPath->Buffer));

 

KdPrint(("%ws", RegistryPath->Buffer));

 

DriverEntry返回值是NTSTATUS的數據,NTSTATUS是被定義爲32位的無符號長整形。在驅動程序開發中,人們習慣用NTSTATUS返回狀態。其中0~0X7FFFFFFF,被認爲是正確的狀態,而0X80000000~0XFFFFFFFF,被認爲是錯誤的狀態。有個很是有用的宏——NT_SUCCESS,被用來檢測狀態是否正確。經常使用的NTSTATUS值有STATUS_SUCCESS。

DriverEntry的返回值若是表示成功,則意味着加載驅動成功,不然意味着加載驅動失敗,調用對象管理程序銷燬驅動對象。

最後須要說明的是DriverEntry參數的修飾「IN」。「IN」、「OUT」、「INOUT」在DDK中被定義成空串,它們的功能相似於程序註釋,當看到一個「IN」參數時,應該認定該參數是純粹用於輸入目的。「OUT」參數表明這個參數僅用於函數的輸出函數。「INOUT」用於既能夠輸入又能夠輸出的參數。例如DriverEntry例程,它的DriverObject指針是IN參數,即便用者不能改變這個指針自己,但徹底能夠改變它指向的對象。

 

2、建立設備對象

在NT式的驅動中,建立設備對象是由IoCreateDevice內核函數完成的。

NTSTATUS IoCreateDevice{
    IN PDRIVER_OBJECT DriverObject,
    IN ULONG DeviceExtensionSize,
    IN PUNICODE_STRING DeviceName OPTIONAL,
    IN DEVICE_TYPE DeviceType,
    IN ULONG DeviceCharacteristics,
    IN BOOLEAN Exclusive,
    OUT PDEVICE_OBJECT *DeviceObject
};

 

》DriverObject:輸入參數,每一個驅動程序中。會有惟一的驅動對象與之對應,但每一個驅動對象會有若干個設備對象。DriverObject指向的就是驅動對象的指針。

》DeviceExtensionSize:輸入參數,指定設備擴展的大小,I/O管理器會根據這個大小,在內存中建立設備擴展,並與驅動對象關聯。

》DeviceName:輸入參數,設置設備對象的特徵。

》Exclusive:輸入參數,設置設備對象是否爲內核模式下使用,通常設置爲TRUE。

》DeviceObject:輸出參數,I/O管理器負責建立這個設備對象,並返回設備對象的地址。

》返回值:返回此函數的調用狀態。

設備名稱用UNICODE字符串指定,而且字符串必須是「\Device\[設備名]」的形式。在Windows下的全部設備都是以相似名字命名的,例如,磁盤分區的C盤、D盤、E盤、F盤就是被命名爲「\Device\Harddisk Volume1」、「\Device\HarddiskVolume2」、「\Device\HarddiskVolume3」、「\Device\HarddiskVolume4」.

固然也能夠不指定設備名字,若是在IoCreateDevice中沒有指定設備對象的名字,I/O管理器會自動分配一個數字做爲設備的設備名,例如,「\Device\00000001」、「\Device\00000002」、「\Device\00000003」.

若是指定了設備名,只能被內核模式下的其餘驅動所識別。可是在用戶模式下的應用程序沒法識別這個設備。讓用戶模式下的應用程序能識別設備有兩種辦法,第一種是經過符號連接找到設備,第二種是經過設備接口找到設備。設備接口的辦法在NT驅動中不多使用。

符號連接能夠理解爲設備對象起了一個「別名」。設備對象的名稱只能被內核模式的驅動識別,而別名也能夠被用戶模式下的應用程序十倍。例如,常說的C盤、D盤就是符號連接。所謂的C盤,指的是名爲「C:」的符號連接,其真正的設備對象是「\Device\HarddiskVolume1」,建立符號連接的函數是IoCreateSymbolicLink,其函數聲明以下。

121頁。

相關文章
相關標籤/搜索