[原創]W2k Driving 學習筆記(二)使用GCC創建 Windows NT 下的內核DLL
再溫習<<Windows 2000 Driving>>分層驅動程序一章的時候,看到了關於緊耦合
驅動連接方式,這種方式不依賴於I/O管理器的串聯,而是直接調用內核例程,這樣可以大
大的提高驅動的執行效率。
為了實現這樣一種功能,必須提供一種類似於在用戶模式中DLL的機製,隻不過該"DLL"
是加載到內核中的。其實Windows NT 內核本身早就利用了這樣機製,比如Hal.dll、ntoskrnl.exe和某些類驅動程序等,他們分別為第3方驅動程序導出了HAL層、內核層、執行體層的功能函數。
在 Tim Roberts 的 《內核模式的 DLL》一文中,給出了內核DLL的主要特征:
內核 DLL 就像用戶模式 DLL 一樣:鏈接器在構建 DLL 時生成一個導入庫,然後將此庫包含到將要使
用此DLL 的任何驅動程序的目標庫列表中。既不需要注冊表技巧,也不需要任何特別的動作來起停該 DLL。
內核 DLL將隨任何引用之的其他驅動程序自動加載,而隨最後一個引用之的驅動程序自動卸載(注 1)。
為了實現這樣一個DLL,Roberts給出的做法是使用DDK來生成一個TARGETTYPE為
EXPORT_DRIVER的項目。我試了一下,如其所願,的確建立一個xxx.sys文件,我還
觀察了一下該sys的PE類型,發現它與標準的內核sys並無兩樣,那麼能不能用gcc來生成一
個內核模式的DLL呢?答案是肯定的!如果你正在用gcc(MinGW)在寫Windows NT 下
的Core Dll的話,那麼也可以寫出DDK中EXPORT_DRIVER類型的模塊了,具體做法從略...
好了,上麵隻是開個玩笑,嗬嗬。下麵就詳細說說如何用MinGW來寫一個CoreDll:
- 首先在你的係統中應該安裝一個MinGW,我現在用的是(MinGW 5.1.4);
- 在你的係統中還要有一個Masm32V9.0+的環境(這個不是必須的,Gcc也有能力自己生成驅動程序文件,而我采用的是Masm方式),你也可以安裝WINDDK,用它的環境生成最終的的驅動文件。
- 用gccNTDrvFrame(注2)建立一個新的驅動包,其中如果要想實現CoreDll動態加載和卸載功能必須在sys.c中提供以下2個例程,你可以將構造和析構的相關內容放在它們裏麵。你同樣要提供一個Driver 必須包含標準的 DriverEntry 入口點,不過實際上係統不會調用它。這個需求是創建係統的人為限製,因為它會為每個內核驅動程序把 /ENTRY:DriverEntry 添加到鏈接器選項中。因此我們為隻導出的 DLL 也必須提供一個偽入口點。 :
__declspec(dllexport) DDKAPI NTSTATUS DllInitialize(/ IN PUNICODE_STRING RegistryPath); __declspec(dllexport) DDKAPI NTSTATUS DllUnload(void);
4. 建立一個需要導出的函數,我這裏隻是示例一下,所以寫了一個簡單的導出函數:
__declspec(dllexport) DDKAPI NTSTATUS GetMagicNum(IN int *pVal) { if(!pVal) { DbgPrint("err : pVal == NULL!/n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } DbgPrint("*pVal is %d/n",*pVal); *pVal *= 11 * 11; DbgPrint("After OP --- *pVal is %d/n",*pVal); return STATUS_SUCCESS
5. 為連接器建立def文件,內容如下:
NAME CoreDll.sys EXPORTS DllInitialize PRIVATE DllUnload PRIVATE GetMagicNum
6. 運行gccNTDrvFrame的builder,完成CoreDll的編譯和連接,如果沒有錯誤將會生
成若幹個文件,其中隻會用到2個:一個是xxx.sys,這個不用說就是供其它驅動調用
的CoreDll,另一個是xxx.lib,它是所有需要調用xxx.sys的其它驅動程序建立時需要
的文件,它和hal.lib、ntoskrnl.lib完全一樣。
7. 新建另一個Driver工程,在b.bat中的link連接選項中添加xxx.lib。聲明和調用外部
函數的方法如下:
__declspec(dllimport) DDKAPI NTSTATUS GetMagicNum(IN int *pVal); DDKAPI NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,/ PUNICODE_STRING pRegistryPath) { PDEVICE_OBJECT pDevObj; NTSTATUS status = STATUS_DEVICE_CONFIGURATION_ERROR; PRINT("[%s]enter DriverEntry.../n",__func__); RtlInitUnicodeString(&DevName,DEVNAMEW); RtlInitUnicodeString(&SymlnkName,SYMLNKNAMEW); if(IoCreateDevice(pDriverObject,0,&DevName,FILE_DEVICE_UNKNOWN,/ 0,false,&pDevObj) != STATUS_SUCCESS) { PRINT("[%s]IoCreateDevice Failed!/n",__func__); goto QUIT; } if(IoCreateSymbolicLink(&SymlnkName,&DevName) != STATUS_SUCCESS) { IoDeleteDevice(pDevObj); PRINT("[%s]IoCreateSymbolicLink Failed!/n",/ __func__); goto QUIT; } pDevObj->Flags |= DO_BUFFERED_IO; pDriverObject->DriverUnload = DriverUnload; pDriverObject->MajorFunction[IRP_MJ_CREATE] = / DrvDispatchCreateClose; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = / DrvDispatchCreateClose; pDriverObject->MajorFunction[IRP_MJ_READ] = / DispatchRead; pDriverObject->MajorFunction[IRP_MJ_WRITE] = / DispatchWrite; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = / DrvDispatchControl; pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = / DrvShutdown; if(!NT_SUCCESS(IoRegisterShutdownNotification(/ pDriverObject->DeviceObject))) { PRINT("[%s]err : Register Shutdown Failed!/n",/ __func__); } int i = 11; GetMagicNum(&i); PRINT("[%s]Addr of KeServiceDescriptorTable : %p/n",/ __func__,KeServiceDescriptorTable); PRINT("[%s]leave DriverEntry.../n",__func__); status = STATUS_SUCCESS; QUIT: return status; }
你當然不一定非要在DriverEntry中調用,因為xxx.sys由係統在調用sys之前自動
動態加載.
8. 用builder建立這個sys,然後整個過程結束了。
結束語:這裏隻是一個最簡單的示例,如果是隻幹這樣的"小"事而用CoreDll的話,未免
殺雞用牛刀的意思。CoreDll的用途可以被極大的拓展,至於如何發揮您的激情與才幹,就
不是我力所能及的了。(^o^)
注1 :不過,在 Windows 98 第二版或者 Windows Me 中內核 DLL 永遠也不會卸載。
注2 :gccNTDrvFrame是我寫的一個gcc建立windows NT 驅動的框架包,稍後會在新文章中介紹。
(PS : 文章參考https://sluttery.spaces.live.com/blog/cns!3569FEA80C717FD4!519.entry)
最後更新:2017-04-02 00:06:42
上一篇:
存儲過程與函數的區別
下一篇:
Linux之間傳送文件的SCP命令
萬物互聯天下 創造未來奇跡
錯誤整理:No plugin found for prefix 'jetty' in the current project and in the plugin groups
從戀愛到婚後的短信詞頻圖發生了這些變化,你中了幾槍?
php視頻課程
天貓超市進軍香港,天貓618次日達還包郵驚呆剁手黨
ubuntu和mac OS X下另一種使用QQ的方法
React+Redux打造“NEWS EARLY”單頁應用 一步步讓你理解最前沿技術棧的真諦
sql語句判斷範圍區間
Design Pattern: Adapter 模式 - Class Adapter
C++中判斷一個文件是否存在的方法