?? windows文件系統(tǒng)過濾驅(qū)動(dòng)開發(fā)教程.txt
字號(hào):
下面是我常用的內(nèi)存分配函數(shù)。
//-----------------wdf.h中的代碼----------------------
// 最簡(jiǎn)單的分配內(nèi)存的函數(shù),可以指定分頁(yè)非分頁(yè)
_inline wd_pvoid wd_malloc(wd_bool paged,wd_size size)
{
if(paged)
return ExAllocatePool(PagedPool,size);
else
return ExAllocatePool(NonPagedPool,size);
}
// 釋放內(nèi)存
_inline wd_void wd_free(wd_pvoid point)
{
ExFreePool(point);
}
_inline wd_void wd_memzero(
wd_pvoid point,
wd_size size)
{
RtlZeroMemory(point,size);
}
有了上邊的基礎(chǔ),我就可以自己寫一個(gè)初始化FastIoDispatch指針的函數(shù)。
//-----------------wdf.h中的代碼----------------------
wd_bool wd_fio_disp_init(wd_drv *driver,wd_ulong size)
{
wd_fio_disp *disp = wd_malloc(wd_false,size);
if(disp == wd_null)
return wd_false;
wd_memzero((wd_pvoid)disp,size);
driver->FastIoDispatch = disp;
driver->FastIoDispatch->SizeOfFastIoDispatch = size;
return wd_true;
}
這個(gè)函數(shù)為FastIoDispacth指針分配足夠的空間并填寫它的大小。下面是再寫一系列的函數(shù)來(lái)設(shè)置這個(gè)函數(shù)指針數(shù)組。實(shí)際上,F(xiàn)astIo接口函數(shù)實(shí)在太多了,所以我僅僅寫出這些設(shè)置函數(shù)的幾個(gè)作為例子:
//-----------------wdf.h中的代碼----------------------
_inline wd_void wd_fio_disp_set_query_standard(
wd_drv *driver,
wd_fio_query_standard_func func)
{
driver->FastIoDispatch->FastIoQueryStandardInfo = func;
}
_inline wd_void wd_fio_disp_set_io_lock(
wd_drv *driver,
wd_fio_io_lock_func func)
{
driver->FastIoDispatch->FastIoLock = func;
}
_inline wd_void wd_fio_disp_set_io_unlock_s(
wd_drv *driver,
wd_fio_unlock_single_func func)
{
driver->FastIoDispatch->FastIoUnlockSingle = func;
}
...
好,如果你堅(jiān)持讀到了這里,應(yīng)該表示祝賀了。我們回顧一下,wd_main中,應(yīng)該做哪些工作。
a.生成一個(gè)控制設(shè)備。當(dāng)然此前你必須給控制設(shè)置指定名稱。
b.設(shè)置Dispatch Functions.
c.設(shè)置Fast Io Functions.
// ----------------wd_main 的近況----------------------------
...
wd_dev *g_cdo = NULL;
wd_stat wd_main(in wd_drv* driver,
in wd_ustr* reg_path)
{
wd_ustr name;
wd_stat status = wd_stat_suc;
// 然后我生成控制設(shè)備,雖然現(xiàn)在我的控制設(shè)備什么都不干
wd_ustr_init(&name,L"\\FileSystem\\Filters\\our_fs_filters");
status = wdff_cdo_create(driver,0,&name,&g_cdo);
if(!wd_suc(status))
{
if(status == wd_stat_path_not_found)
{
// 這種情況發(fā)生于\FileSystem\Filters路徑不存在。這個(gè)路徑是
// 在xp上才加上的。所以2000下可能會(huì)運(yùn)行到這里
wd_ustr_init(&name,L"\\FileSystem\\our_fs_filters");
status = wdff_cdo_create(driver,0,&name,&g_cdo);
};
if(!wd_suc(status))
{
wd_printf0("error: create cdo failed.\r\n");
return status;
}
}
wd_printf0("success: create cdo ok.\r\n");
// 開始設(shè)置幾個(gè)分發(fā)例程
wd_drv_set_dispatch(driver,my_disp_default);
wd_drv_set_create(driver,my_disp_create);
wd_drv_set_clean_up(driver,my_disp_clean_up);
wd_drv_set_file_sys_control(driver,my_disp_file_sys_ctl);
wd_drv_set_close(driver,my_disp_close);
wd_drv_set_read(driver,my_disp_read);
wd_drv_set_write(driver,my_disp_write);
// 指定fast io處理函數(shù)
if(!wd_fio_disp_init(driver,sizeof(wd_fio_disp)))
{
wd_dev_del(g_cdo);
wd_printf0("error: fast io disp init failed.\r\n");
return wd_stat_insufficient_res;
}
// 下面指定的這些函數(shù)都定義在wdf_filter_fio.h中,其實(shí)這些函數(shù)都統(tǒng)
// 一的返回了false
wd_fio_disp_set_check(
driver,
my_fio_check);
wd_fio_disp_set_read(
driver,
my_fio_read);
wd_fio_disp_set_write(
driver,
my_fio_write);
wd_fio_disp_set_query_basic(
driver,
my_fio_query_basic_info);
...
}
FastIo函數(shù)個(gè)數(shù)數(shù)量不明,我只覺得很多。因此不打算全部羅列,以"..."敷衍之。某些讀者可能會(huì)認(rèn)為這些代碼無(wú)法調(diào)試安裝。其實(shí)您可以參考sfilter中的示例自己完成這些代碼。
現(xiàn)在我們的my_xxx系列的函數(shù)還沒有開始寫,因此驅(qū)動(dòng)也不能編譯通過。在后邊的內(nèi)容中再逐步介紹。
4.設(shè)備棧,過濾,文件系統(tǒng)的感知
前邊都在介紹文件系統(tǒng)驅(qū)動(dòng)的結(jié)構(gòu),卻還沒講到我們的過濾驅(qū)動(dòng)如何能捕獲所有發(fā)給文件系統(tǒng)驅(qū)動(dòng)的irp,讓我們自己來(lái)處理?前面已經(jīng)解釋過了設(shè)備對(duì)象。現(xiàn)在來(lái)解釋一下設(shè)備棧。
任何設(shè)備對(duì)象都存在于某個(gè)設(shè)備棧中。設(shè)備棧自然是一組設(shè)備對(duì)象。這些設(shè)備對(duì)象是互相關(guān)聯(lián)的,也就是說(shuō),如果得到一個(gè)DO指針,你就可以知道它所處的設(shè)備棧。
任何來(lái)自應(yīng)用的請(qǐng)求,最終被windows io mgr翻譯成irp的,總是發(fā)送給設(shè)備棧的頂端那個(gè)設(shè)備。
原始irp irp irp irp
--------------> ------> -------> ----->
DevTop Dev2 ... DevVolumne ... ???
<-------------- <------ <------- <-----
原始irp(返回) irp irp irp
上圖向右的箭頭表示irp請(qǐng)求的發(fā)送過程,向左則是返回。可見irp是從設(shè)備棧的頂端開始,逐步向下發(fā)送。DevVolumue表示我們實(shí)際要過濾的Volume設(shè)備,DevTop表示這個(gè)設(shè)備棧的頂端。我們只要在這個(gè)設(shè)備棧的頂端再綁定一個(gè)設(shè)備,那發(fā)送給Volume的請(qǐng)求,自然會(huì)先發(fā)給我們的設(shè)備來(lái)處理。
有一個(gè)系統(tǒng)調(diào)用可以把我們的設(shè)備綁定到某個(gè)設(shè)備的設(shè)備棧的頂端。這個(gè)調(diào)用是IoAttachDeviceToDeviceStack,這個(gè)調(diào)用2000以及以上系統(tǒng)都可以用(所以說(shuō)到這點(diǎn),是因?yàn)檫€有一個(gè)IoAttachDeviceToDeviceStackSafe,是2000所沒有的。這常常導(dǎo)致你的filter在2000下不能用。)
我自己寫了一個(gè)函數(shù)來(lái)幫我實(shí)現(xiàn)綁定功能:
//----------------------wdf.h中的內(nèi)容----------------------------------
// 這個(gè)例程把源設(shè)備綁定到目標(biāo)設(shè)備的設(shè)備棧中去,并返回源設(shè)備所直
// 接綁定的設(shè)備。注意源設(shè)備未必直接綁定在目標(biāo)設(shè)備上。它應(yīng)綁定在
// 目標(biāo)設(shè)備的設(shè)備棧的頂端。
_inline wd_stat wd_dev_attach(in wd_dev *src,
in wd_dev *dst,
in out wd_dev **attached)
{
*attached = dst;
*attached = IoAttachDeviceToDeviceStack(src,dst);
if(*attached == NULL)
return wd_stat_no_such_dev;
return wd_stat_suc;
}
到這里,我們已經(jīng)知道過濾對(duì)Volume的請(qǐng)求的辦法。比如“C:”這個(gè)設(shè)備,我已經(jīng)知道符號(hào)連接為“C:”,不難得到設(shè)備名。得到設(shè)備名后,又不難得到設(shè)備。這時(shí)候我們IoCreateDevice()生成一個(gè)Device Object,然后調(diào)用wd_dev_attach綁定,不是一切ok嗎?所有發(fā)給“C:”的irp,就必然先發(fā)送給我們的驅(qū)動(dòng),我們也可以捕獲所有對(duì)文件的操作了!
這確實(shí)是很簡(jiǎn)單的處理方法。我得到的FileMon的代碼就是這樣處理的,如果不想處理動(dòng)態(tài)的Volume,你完全可以這樣做。但是我們這里有更高的要求。當(dāng)你把一個(gè)U盤插入usb口,一個(gè)“J:”之類的Volume動(dòng)態(tài)誕生的時(shí)候,我們依然要捕獲這個(gè)事件,并生成一個(gè)Device來(lái)綁定它。
一個(gè)新的存儲(chǔ)媒質(zhì)被系統(tǒng)發(fā)現(xiàn)并在文件系統(tǒng)中生成一個(gè)Volume的過程稱為Mounting.其過程開始的時(shí)候,F(xiàn)S的CDO將得到一個(gè)IRP,其Major Function Code為IRP_MJ_FILE_SYSTEM_CONTROL,Minor Function Code為IRP_MN_MOUNT。換句話說(shuō),如果我們已經(jīng)生成了一個(gè)設(shè)備綁定文件系統(tǒng)的CDO,那么我們就可以得到這樣的IRP,在其中知道一個(gè)新的Volume正在Mount.這時(shí)候我們可以執(zhí)行上邊所說(shuō)的操作。
現(xiàn)在的問題是如何知道系統(tǒng)中有那些文件系統(tǒng),還有就是我應(yīng)該在什么時(shí)候綁定它們的控制設(shè)備。
IoRegisterFsRegistrationChange()是一個(gè)非常有用的系統(tǒng)調(diào)用。這個(gè)調(diào)用注冊(cè)一個(gè)回調(diào)函數(shù)。當(dāng)系統(tǒng)中有任何文件系統(tǒng)被激活或者是被注銷的時(shí)候,你注冊(cè)過的回調(diào)函數(shù)就會(huì)被調(diào)用。
//----------------------wdf.h中的內(nèi)容----------------------------------
wd_stat wdff_reg_notify(
in wd_drv *driver,
in wdff_notify_func func
)
{
return IoRegisterFsRegistrationChange(driver,func);
}
你有必要為此寫一個(gè)回調(diào)函數(shù)。
//-------------------我的回調(diào)處理函數(shù)----------------------------------
wd_void my_fs_notify(
in wd_dev *dev,
in wd_bool active)
{
wd_wchar name_buf[wd_dev_name_max_len];
wd_ustr name;
wd_ustr_init_em(&name,name_buf,wd_dev_name_max_len);
// 如果注冊(cè)了,就應(yīng)該得到通知
wd_printf0("notify: a file sys have been acitved!!! \r\n");
// 得到文件系統(tǒng)對(duì)象的名字,然后打印出來(lái)
wd_obj_get_name(dev,&name);
wd_printf0("notify : file sys name = %wZ\r\n",&name);
if(active)
{
wd_printf0("notify: try to attach.\r\n");
// ... 請(qǐng)?jiān)谶@里綁定文件系統(tǒng)的控制設(shè)備
}
else
{
wd_printf0("notify: unactive.\r\n");
// ...
}
}
應(yīng)該如何綁定一個(gè)文件系統(tǒng)CDO?我們?cè)谙旅娴恼鹿?jié)再詳細(xì)描述。
現(xiàn)在我們應(yīng)該再在wd_main函數(shù)中加上下邊的內(nèi)容:
if(wdff_reg_notify(driver,my_fs_notify) != wd_stat_suc)
{
wd_printf0("error: reg notify failed.\r\n");
wd_fio_disp_release(driver);
wd_dev_del(g_cdo);
g_cdo = wd_null;
return wd_stat_insufficient_res;
};
wd_printf0("success: reg notify ok.\n");
我們?cè)俅位仡櫼幌拢瑆d_main中,應(yīng)該做哪些工作。
a.生成一個(gè)控制設(shè)備。當(dāng)然此前你必須給控制設(shè)置指定名稱。
b.設(shè)置Dispatch Functions.
c.設(shè)置Fast Io Functions.
d.編寫一個(gè)my_fs_notify回調(diào)函數(shù),在其中綁定剛激活的FS CDO.
e.使用wdff_reg_notify調(diào)用注冊(cè)這個(gè)回調(diào)函數(shù)。
5.綁定FS CDO,文件系統(tǒng)識(shí)別器,設(shè)備擴(kuò)展
上一節(jié)講到我們打算綁定一個(gè)剛剛被激活的FS CDO.前邊說(shuō)過簡(jiǎn)單的調(diào)用wd_dev_attach可以很容易的綁定這個(gè)設(shè)備。但是,并不是每次my_fs_notify調(diào)用發(fā)現(xiàn)有新的fs激活,我就直接綁定它。
首先判斷是否我需要關(guān)心的文件系統(tǒng)類型。我用下面的函數(shù)來(lái)獲取設(shè)備類型。
// ------------------wdf.h中的內(nèi)容-------------------
_inline wd_dev_type wd_dev_get_type(in wd_dev *dev)
{
return dev->DeviceType;
}
文件系統(tǒng)的CDO的設(shè)備類型有下邊的幾種可能,你的過濾驅(qū)動(dòng)可能只對(duì)其中某些感興趣。
enum {
wd_dev_disk_fs = FILE_DEVICE_DISK_FILE_SYSTEM,
wd_dev_cdrom_fs = FILE_DEVICE_CD_ROM_FILE_SYSTEM,
wd_dev_network_fs = FILE_DEVICE_NETWORK_FILE_SYSTEM
};
你應(yīng)該自己寫一個(gè)函數(shù)來(lái)判斷該fs是否你所關(guān)心的。
// -------------一個(gè)函數(shù),判斷是否我所關(guān)心的fs---------------
wd_bool my_care(wd_ulong type)
{
return (((type) == wd_dev_disk_fs) ||
((type) == wd_dev_cdrom_fs) ||
((type) == wd_dev_network_fs));
}
下一個(gè)問題是我打算跳過文件系統(tǒng)識(shí)別器。文件系統(tǒng)識(shí)別器是文件系統(tǒng)驅(qū)動(dòng)的一個(gè)很小的替身。為了避免沒有使用到的文件系統(tǒng)驅(qū)動(dòng)占據(jù)內(nèi)核內(nèi)存,windows系統(tǒng)不加載這些大驅(qū)動(dòng),而代替以該文件系統(tǒng)驅(qū)動(dòng)對(duì)應(yīng)的文件系統(tǒng)識(shí)別器。當(dāng)新的物理存儲(chǔ)媒介進(jìn)入系統(tǒng),io管理器會(huì)依次的嘗試各種文件系統(tǒng)對(duì)它進(jìn)行“識(shí)別”。識(shí)別成功,立刻加載真正的文件系統(tǒng)驅(qū)動(dòng),對(duì)應(yīng)的文件系統(tǒng)識(shí)別器則被卸載掉。對(duì)我們來(lái)說(shuō),文件系統(tǒng)識(shí)別器的控制設(shè)備看起來(lái)就像一個(gè)文件系統(tǒng)控制設(shè)備。但我們不打算綁定它。
分辨的方法是通過驅(qū)動(dòng)的名字。凡是文件系統(tǒng)識(shí)別器的驅(qū)動(dòng)對(duì)象的名字(注意是DriverObject而不是DeviceObject!)都為“\FileSystem\Fs_Rec”.
//-------------------用這些代碼來(lái)跳過文件系統(tǒng)識(shí)別器----------------------
wd_wchar name_buf[wd_dev_name_max_len];
wd_ustr name,tmp;
wd_ustr_init_em(&name,name_buf,wd_dev_name_max_len);
wd_ustr_init(&tmp,L"\\FileSystem\\Fs_Rec");
// 我不綁定識(shí)別器。所以如果是識(shí)別器,我直接返回成功。查看是否是識(shí)別
// 器的辦法是看是否是\FileSystem\Fs_Rec的設(shè)備。
wd_obj_get_name(wd_dev_drv(fs_dev),&name);
if(wd_ustr_cmp(&name,&tmp,wd_true) == 0)
{
wd_printf0("attach fs dev:is a recogonizer.\r\n");
return wd_stat_suc;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -