掌機 - Windows Driver Model (WDM) - Assembly - DriverEntry



C/C++程式的進入點是main(),而對於WDM而言,它的進入點則是DriverEntry(),如果沒有export DriverEntry(),系統將無法正確載入驅動程式

DriverEntry()的定義如下:

proto :PDRIVER_OBJECT, :PUNICODE_STRING

系統透過呼叫DriverEntry()載入驅動程式並傳入兩個參數,第一個參數PDRIVER_OBJECT是指向該驅動程式的資料位置,該位置會包含驅動程式的所有資訊,這些資訊並非全部都提供給使用者使用,有些欄位是Undocument的,保留給系統調度使用,Microsoft可能隨系統不同而修改,因此,建議使用者不要使用這些Undocument欄位的資料,另一個參數PUNICODE_STRING則是該驅動程式的Registry位置,驅動程式在安裝時,系統都會產生一個註冊表項目(位於CurrentControlSet\Services\),該項目就是當Windows系統啟動時,用來載入驅動程式使用的,Windows系統依據註冊表來決定哪些驅動程式需要被載入以及載入的順序,因此,隨意修改註冊表,可能會導致驅動程式無法被正確載入,嚴重時,可能無法啟動系統

使用者需要注意的是,就算有多個相同的裝置(如:兩個一樣型號的USB滑鼠插入電腦),系統只會在發現第一個裝置時,載入該驅動程式並產生一份Driver Object,之後發現的裝置,系統還是使用那份已經產生的Driver Object,使用者可能很好奇,相同裝置使用同一份Driver Object資料?那每個裝置的驅動程式資料不就會亂掉嗎?答案是:不會的,因為每個裝置必須Create自己的Device Object(跟Driver Object是不一樣的東西),每個裝置的資料必須存在自己Create的Device Object中,因此,每個Device Object各代表不同的裝置

那在DriverEntry()副程式,需要做哪一些事情呢?

WDM驅動程式 Legacy驅動程式
需要註冊使用到的Callback副程式,如:AddDevice()、DriverUnload()等 除了需要註冊Callback副程式以外,還要產生Device Object,因為Legacy驅動程式沒有AddDevice() Callback,所以需要在DriverEntry()產生Device Object

範例:

DriverEntry proc pOurDriver:PDRIVER_OBJECT, pOurRegistry:PUNICODE_STRING
    mov eax, pOurDriver
    mov (DRIVER_OBJECT PTR [eax]).MajorFunction[IRP_MJ_PNP    * (sizeof PVOID)], offset IrpPnp
    mov (DRIVER_OBJECT PTR [eax]).MajorFunction[IRP_MJ_CREATE * (sizeof PVOID)], offset IrpFile
    mov (DRIVER_OBJECT PTR [eax]).MajorFunction[IRP_MJ_CLOSE  * (sizeof PVOID)], offset IrpFile
    mov (DRIVER_OBJECT PTR [eax]).MajorFunction[IRP_MJ_WRITE  * (sizeof PVOID)], offset IrpFile
    mov (DRIVER_OBJECT PTR [eax]).MajorFunction[IRP_MJ_READ   * (sizeof PVOID)], offset IrpFile
    mov (DRIVER_OBJECT PTR [eax]).DriverUnload, offset Unload
    mov eax, (DRIVER_OBJECT PTR [eax]).DriverExtension
    mov (DRIVER_EXTENSION PTR [eax]).AddDevice, AddDevice
    mov eax, STATUS_SUCCESS
    ret
DriverEntry endp

P.S. 需要注意DriverEntry()的回傳值,因為回傳值會決定載入驅動程式的成功或失敗,另外,除了DriverEntry()名稱必須固定以外,其餘的Callback副程式名稱都可以隨意命名