終於到了禮拜天,抓緊時間寫了段文檔。
由於不是一次兩次就能說的清楚,所以我分塊來說明,這篇希望能講解出一個驅動的架構,以後的講解就在這個架構的基礎上深入展
開。
對於檔案過濾驅動的整體描述,我認為下面這個文章裡codewarrior(會思考的草) 說的很不錯,在次感謝
http://community.csdn.net/Expert/topic/4849/4849948.xml?temp=.1946985
這裡先對ddk裡面幾個基礎的東東大概說明下:
入口函數:
和win32編程一樣,驅動也有一個入口函數DriverEntry(相當於main WinMain),這裡注意他們之間的運行方式是不同的,win32入口
函數後是進入訊息迴圈,驅動DriverEntry的主要功能是註冊一些IRP的相當於回調處理方式的函數,也就是我們所說的派遣函數。。
IRP:
IRP(I/O 請求包),驅動編程裡十分重要的概念,說白了它就是一個資料結構,裡面有對應操作需要的資料,比如我們應用程式層調用了
CreateFile函數,在驅動層可能就構建一個IRP(IRP_MJ_CREATE),通過這個IRP的處理完成對應操作,如果我們對使用者開啟,建立檔案
等操作有興趣(比只允許指定程式開啟對應檔案),就可以通過掛接的方式讓系統將這個IRP發送到我們指定的函數(就是
DriverEntry裡面指定的),然後...
CDO:
CDO(ontrol Device Object),控制裝置物件,這個對象代表這個驅動,它是供我們應用程式層的程式使用的,在DriverEntry裡面建立
它,注意它沒有裝置擴充。這裡有必要說一下一般見到說的DO(device object),DO是用來綁定到檔案系統驅動的FDO上的,和CDO
不同。他們都使用IoCreateDevice函數建立,注意區別。
Device Extension:
Device Extension(裝置擴充),使用IoCreateDevice建立DO等時通過第2個參數來指定,其實它就是一塊儲存有用資料的記憶體,這
裡一般就是一個結構體。請注意它會隨DO一起傳遞,這就是它的關鍵好處所在。
就講這幾個了,還有很多,用到的時候再說,下面先從DriverEntry說起。
DriverEntry一般都下面這樣的形式,2個參數的類型都帶了P,相信大家一看就知道是指標形式,加下注釋
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,//指向系統建立的我們的驅動對象
IN PUNICODE_STRING RegistryPath//驅動註冊key的路徑
)
首先需要做的是申明一個全域的PDRIVER_OBJECT變數,儲存我們的DriverObject,因為我們在其他地方可能會用到它,然後就是取得
一些需要使用函數的地址,存放在全域變數中,這裡不說這個。接著就可以建立我們的控制裝置物件了,就是前面說的CDO,建立它
使用函數IoCreateDevice,如下:
DEVICE_OBJECT * ourCDO = NULL;//注意這個變數是全域,為了看的清楚我才放在這裡!!!!!!!!
//我們的CDO控制裝置物件,前面有說到它
NTSTATUS status = STATUS_SUCCESS;//傳回值我讓它預設為成功
UNICODE_STRING Name_2k;//請注意我這裡加了個2k,是為了引起大家的注意,因為XP系統裡下面那個串會不
//一樣
RtlInitUnicodeString(&Name_2k,L"//FileSystem//OurFilter_Cdo");//就是這個串,xp下是
//L"//FileSystem//Filters//OurFilter_Cdo"
status = IoCreateDevice(DriverObject,//我們的驅動程式對象
0,//擴充裝置的大小,就是前面說的Device Extension,還記得前面說的CDO沒有裝置擴充嗎
//?,所以置0
&Name_2k,//裝置名稱
FILE_DEVICE_DISK_FILE_SYSTEM,//裝置的類型
FILE_DEVICE_SECURE_OPEN,//指出裝置所允許的操作
FALSE,//TRUE表示只能有一個線程使用該裝置,FALSE則沒有1個使用的限制
&ourCDO //返回的控制裝置物件CDO
);
if(!NT_SUCCESS(status))//如果建立控制裝置物件失敗,退出
return status;
接下來我們可以建立一個Win32可見的符號串連
UNICODE_STRING Link_2k;
RtlInitUnicodeString(&Link_2k,L"//DosDevices//OurFilter");
status = IoCreateSymbolicLink(&Link_2k ,&Name_2k);
if(!NT_SUCCESS(status))
return status;
到這裡後我們就可以設定我們的派遣函數了,前面說過了,就是能處理到IRP的函數,具體怎麼設定,我先以一個簡單的為了動態禦
載而設定的DriverUnload函數為例子來說明,該函數會在禦載的時候調用,設定這個函數的代碼大致如下:
先聲明函數,為了使DriverEntry可見,所以一般是在對應的標頭檔裡面聲明
void DriverUnload(IN PDRIVER_OBJECT DriverObject);
接著在DriverEntry裡添加
//設定Unload
DriverObject->DriverUnload = DriverUnload;
至於DriverUnload函數都需要做些什麼,主要就是一些DO ,CDO等的刪除,資源的釋放,取消掛接等等,這裡由於我們上面的操作比
較簡單,所以需要釋放的東東也就不多
void DriverUnload(IN PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING uniNameString;
RtlInitUnicodeString(&uniNameString, L"//FileSystem//OurFilter_Cdo");
IoDeleteSymbolicLink(&uniNameString); //刪除win32可見
IoDeleteDevice(pDriverObject->DeviceObject); //刪除裝置
return ;
}
到這裡,一個最基本的驅動架構也就出來了,加入DbgPrint()調試資訊,編譯得到XX.sys後裝載調試完全可以看到輸出的調試資訊
,由於DriverUnload的設定使其能支援動態禦載,如何編譯調試等這裡就不說了。以後的資料就在這個架構的基礎上擴充。
再次說明一下,由於是在網吧匆忙寫的,加上水平很菜,沒說清楚或有錯誤請大家指出,有時間我會把後面的都寫出來,希望對大家
有協助