日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

文件系统过滤驱动开发(一)—Win32底层开发小组

發(fā)布時間:2025/3/20 windows 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 文件系统过滤驱动开发(一)—Win32底层开发小组 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

??? 聲明:本文無太多新意,只是介紹下學(xué)習(xí)經(jīng)驗(yàn),大神級人物(如總監(jiān)大人)請略過,謝謝合作>_<

??? 吐槽一下:學(xué)驅(qū)動算起來也是從上學(xué)期9月份開始吧,之前在家買了<Windows驅(qū)動開發(fā)技術(shù)詳解>這本書,搭了個環(huán)境之后,其實(shí)也沒碰很多,編了個經(jīng)典的Hello,World!之后就無太多后續(xù)動作,暑假嘛,你們懂的,學(xué)習(xí)無壓力.上學(xué)期斷斷續(xù)續(xù)算是把基礎(chǔ)啃完了(其實(shí)也只是啃完-__-),就到了萬惡的期末考試復(fù)習(xí)月.寒假開始著手過濾驅(qū)動這一塊的學(xué)習(xí),然后學(xué)期一開始就忙著這個SIG的項(xiàng)目.到現(xiàn)在的感覺就是,思路是有,但是有一些地方找不到切入點(diǎn),光查資料就花很多時間.現(xiàn)在分享一下我的學(xué)習(xí)心得,不對之處,敬請指出.

??? 我們小組主要想完成的東西是一個類似SandBoxIE的軟件,就是沙盒,現(xiàn)在360和微軟的瀏覽器當(dāng)中都加入了沙盒的功能.當(dāng)然我也沒試用過,因?yàn)樗压酚薪逃W(wǎng)加速- -,我個人對沙盒的理解是對一些操作的重定向,如文件寫入操作,注冊表寫入操作,當(dāng)然更高級的話還要加入內(nèi)存保護(hù).既然有了對寫入操作的重定向,那么對于讀取操作也應(yīng)該進(jìn)行重定向,因?yàn)樾枰x取修改過的文件或者注冊表值.簡單來說,這個沙盒像是一個容器,而我們可以在這個容器里面運(yùn)行其他程序,這個程序?qū)ξ覀儾僮飨到y(tǒng)做的修改會被重定向,結(jié)果是這些修改操作不會對系統(tǒng)有任何的影響,徐志摩同學(xué)很好的描述了這一過程:悄悄的我走了,正如我悄悄的來,我揮一揮衣袖,不帶走一片云彩...再比如在瀏覽器當(dāng)中加入沙盒功能,假設(shè)我們系統(tǒng)訪問了一個被掛馬的網(wǎng)站中了木馬,那么當(dāng)瀏覽器關(guān)閉的時候,木馬執(zhí)行的破壞操作都是無效的(當(dāng)然還是有泄漏帳號密碼的危險,這是另一個話題).

??? 由于驅(qū)動開發(fā)涉及底層,所以各個版本的Windows都會有所不同,我們針對的操作系統(tǒng)是WindowsXP,對于Windows2K而言,下面有些說的實(shí)現(xiàn)方法可能無法實(shí)現(xiàn)(底層的支持問題).對于文件操作的攔截,可以通過文件系統(tǒng)過濾來實(shí)現(xiàn).現(xiàn)在一般殺毒軟件的核心都需要一個文件過濾驅(qū)動,這樣才能實(shí)時監(jiān)控用戶的文件是否安全.關(guān)于磁盤過濾驅(qū)動和文件系統(tǒng)過濾驅(qū)動,磁盤過濾驅(qū)動比文件系統(tǒng)過濾驅(qū)動更為底層一點(diǎn),直接過濾磁盤可以實(shí)現(xiàn)對硬盤操作的還原,這樣也可以實(shí)現(xiàn)我們想要的功能,但是相對來說粒度太大,我們需要的針對特定程序的監(jiān)控,區(qū)分文件目錄而非無差別的任意磁盤讀寫操作.這一類的軟件有影子系統(tǒng),雨過天晴多點(diǎn)還原系統(tǒng).

??? 接下來進(jìn)入正題,如何開發(fā)文件系統(tǒng)過濾驅(qū)動,可能你需要對驅(qū)動對象,設(shè)備對象和IRP派遣函數(shù)有所了解.對于文件系統(tǒng)過濾驅(qū)動的框架而言有兩種選擇,一種是利用Minifilter,這個是文件系統(tǒng)微過濾驅(qū)動,微軟為Windows內(nèi)核開發(fā)者開發(fā)了一個新的驅(qū)動,叫做過濾管理器,提供一些接口供開發(fā)用戶使用,這樣就屏蔽了底層細(xì)節(jié),提高了用戶開發(fā)的效率,同時也利于在不同系統(tǒng)間的移植和解決兼容性問題.在減少代碼依賴性的同時,由于開發(fā)者不需要了解太多的底層細(xì)節(jié),只能通過提供的接口進(jìn)行開發(fā),可能在實(shí)現(xiàn)某些特定功能的時候會實(shí)現(xiàn)不了.另一種就是傳統(tǒng)型的文件過濾驅(qū)動,微軟提供了Sfilter的例子,細(xì)節(jié)需要開發(fā)者自己實(shí)現(xiàn).出于學(xué)習(xí)底層知識的目的,我們選用的是Sfilter的框架,雖然比較繁瑣,但是能學(xué)的多一點(diǎn).

??? 過濾驅(qū)動的一般思路是綁定相關(guān)的設(shè)備對象,之后就能得到該設(shè)備的IRP,進(jìn)行先手和后手的處理.在文件系統(tǒng)過濾驅(qū)動當(dāng)中,我們會生成三種設(shè)備:1,過濾驅(qū)動自身的控制設(shè)備;2,文件系統(tǒng)控制設(shè)備的過濾設(shè)備;3,文件系統(tǒng)卷設(shè)備的過濾設(shè)備.對于過濾驅(qū)動自身的控制設(shè)備主要是用來與應(yīng)用層進(jìn)行交互,剩下兩個是用來綁定文件系統(tǒng)的設(shè)備,像FAT32,NTFS這樣的文件系統(tǒng)主要生成兩類設(shè)備,一種是控制設(shè)備(CDO),一種是卷設(shè)備(VDO),我們需要綁定這兩種設(shè)備.綁定文件系統(tǒng)的控制設(shè)備我們就可以得到類似卷掛載/解掛載等操作的通知從而進(jìn)行相應(yīng)的處理,而綁定卷設(shè)備就能過濾相關(guān)的文件操作.這里的卷設(shè)備是指文件系統(tǒng)的卷設(shè)備,卷設(shè)備有兩類,一類是由卷管理器生成的,這類設(shè)備有名字,我們常見的C:,D:是這類卷設(shè)備的符號鏈接,其設(shè)備名是\Device\harddiskVolume1\,\Device\harddiskVolume2\,這些是由卷設(shè)備管理器生成的,綁定這些設(shè)備無法得到文件操作的.我們關(guān)心的文件系統(tǒng)卷設(shè)備是沒有名字的,需要通過其他方式獲得.

??? 如何獲取控制設(shè)備并綁定它,可以通過注冊文件系統(tǒng)變動回調(diào)來實(shí)現(xiàn),原型如下:

1: NTSTATUS 2: IoRegisterFsRegistrationChange( 3: IN PDRIVER_OBJECT DriverObject, 4: IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine 5: );

??? 回調(diào)函數(shù)的原型如下:

1: VOID 2: (*PDRIVER_FS_NOTIFICATION) ( 3: IN struct _DEVICE_OBJECT *DeviceObject, 4: IN BOOLEAN FsActive 5: );

??? 通過注冊回調(diào)函數(shù),可以得到系統(tǒng)已經(jīng)安裝了的文件系統(tǒng)控制設(shè)備對象也就是*DeviceObject,FsActive是表示文件系統(tǒng)是激活還是卸載,當(dāng)文件系統(tǒng)激活時我們綁定他,卸載則解綁定.文件系統(tǒng)的回調(diào)函數(shù)是用于通知文件系統(tǒng)的變更,在XP下,當(dāng)注冊文件系統(tǒng)回調(diào)之后系統(tǒng)會調(diào)用回調(diào)函數(shù)用以通知已經(jīng)激活的文件系統(tǒng),而在較早版本下面如Win2K+SP4之前的版本是不會,所以只能將文件過濾驅(qū)動做成靜態(tài)加載的形式在系統(tǒng)啟動早期加載.在回調(diào)函數(shù)中,我們根據(jù)FsActive判斷是綁定還是解綁定:

1: if (FsActive) 2: { 3: LzsbfAttachToFileSystemDevice(pDeviceObject, &DeviceName); 4: } 5: else 6: { 7: LzsbfDetachFromFileSystemDevice(pDeviceObject); 8: }

??? 需要注意的是,這個回調(diào)函數(shù)并不通知Raw文件系統(tǒng),如果需要關(guān)注此類文件系統(tǒng)需要自己判斷,我們只關(guān)心FAT32和NTFS文件系統(tǒng),故無視之.

??? 在回調(diào)函數(shù)當(dāng)中,我們還需要加入對文件系統(tǒng)識別器的判斷.Windows在加載文件系統(tǒng)驅(qū)動的時候并非一開始就加載完整驅(qū)動,IO管理器是利用識別器來識別新加入物理介質(zhì)的文件系統(tǒng),當(dāng)識別成功則卸載掉識別器,加載真正的驅(qū)動.我們要綁定的是真正的文件系統(tǒng)驅(qū)動設(shè)備,對于部分的文件系統(tǒng)識別器是由驅(qū)動"\FileSystem\Fs_Rec"生成的,注意只是部分,我們對于這部分的設(shè)備通過判斷其驅(qū)動對象(識別器是一個設(shè)備對象)的名字,如果是"\FileSystem\Fs_Rec"跳過不進(jìn)行綁定,對于不是由Fs_Rec產(chǎn)生的識別器,我們在IRP的派遣函數(shù)MarjorFunctions[IRP_MJ_FILE_SYSTEM_CONTROL]當(dāng)中進(jìn)行處理,我們能夠得到識別器卸載要求加載真正文件系統(tǒng)驅(qū)動的通知.

??? 通過文件系統(tǒng)回調(diào)函數(shù)提供的文件系統(tǒng)控制設(shè)備我們就可以綁定文件系統(tǒng)的控制設(shè)備,之后根據(jù)控制設(shè)備對象得到文件系統(tǒng)驅(qū)動對象,進(jìn)而可以枚舉其相關(guān)的卷設(shè)備,然后進(jìn)行一一綁定.具體的實(shí)現(xiàn)代碼如下:

1: NTSTATUS 2: LzsbfEnumerateFileSystemVolumes( 3: IN PDEVICE_OBJECT pFSDeviceObject, 4: IN PUNICODE_STRING pFSName 5: ) 6: { 7: PDEVICE_OBJECT pNewDeviceObject; 8: PLZSBFILTER_DEVICE_EXTENSION pNewDeviceExtension; 9: PDEVICE_OBJECT *DeviceList; 10: PDEVICE_OBJECT pStorageStackDeviceObject; 11: NTSTATUS status; 12: ULONG NumberOfDevice; 13: ULONG i; 14: BOOLEAN IsShadowCopyVolume; 15:? 16: PAGED_CODE(); 17:? 18: status = IoEnumerateDeviceObjectList(pFSDeviceObject->DriverObject, 19: NULL, 20: 0, 21: &NumberOfDevice 22: ); 23: if (!NT_SUCCESS(status)) 24: { 25: ASSERT(STATUS_BUFFER_TOO_SMALL == status); 26: NumberOfDevice += 8; 27: DeviceList = ExAllocatePoolWithTag(NonPagedPool, 28: (NumberOfDevice * sizeof(PDEVICE_OBJECT)), 29: LZSB_POOL_TAG 30: ); 31: if (NULL == DeviceList) 32: { 33: KdPrint(("Fail to allocate DeviceList\n")); 34: return STATUS_INSUFFICIENT_RESOURCES; 35: } 36:? 37: status = IoEnumerateDeviceObjectList(pFSDeviceObject->DriverObject, 38: DeviceList, 39: (NumberOfDevice * sizeof(PDEVICE_OBJECT)), 40: &NumberOfDevice 41: ); 42: if (!NT_SUCCESS(status)) 43: { 44: KdPrint(("Fail to call IoEnumerateDeviceObjectList()\n")); 45: ExFreePool(DeviceList); 46: return status; 47: } 48: 49: for (i = 0; i < NumberOfDevice; i++) 50: { 51: pStorageStackDeviceObject = NULL; 52: __try 53: { 54: if ((DeviceList[i] == pFSDeviceObject) || 55: (DeviceList[i]->DeviceType != pFSDeviceObject->DeviceType) || 56: LzsbfIsAttachedToDevice(DeviceList[i], NULL)) 57: { 58: KdPrint(("Not to attach this!\n")); 59: __leave; 60: } 61:? 62: LzsbfGetBaseDeviceObjectName(DeviceList[i], pFSName); 63: if (pFSName->Length > 0) 64: { 65: KdPrint(("It has a name, do not attach!\n")); 66: __leave; 67: } 68: 69: status = IoGetDiskDeviceObject(DeviceList[i], &pStorageStackDeviceObject); 70: if (!NT_SUCCESS(status)) 71: { 72: KdPrint(("Fail to get disk device object!\n")); 73: __leave; 74: } 75:? 76: status = LzsbfIsShadowCopyVolume(pStorageStackDeviceObject, &IsShadowCopyVolume); 77: if (NT_SUCCESS(status) && IsShadowCopyVolume) 78: { 79: KdPrint(("It is shadow copy volume, do not attach!\n")); 80: __leave; 81: } 82:? 83: status = IoCreateDevice(gLZSBFilterDriverObject, 84: sizeof(LZSBFILTER_DEVICE_EXTENSION), 85: NULL, 86: DeviceList[i]->DeviceType, 87: 0, 88: FALSE, 89: &pNewDeviceObject 90: ); 91: if (!NT_SUCCESS(status)) 92: { 93: KdPrint(("Fail to create new device!\n")); 94: __leave; 95: } 96:? 97: pNewDeviceExtension = pNewDeviceObject->DeviceExtension; 98: pNewDeviceExtension->LZSBDeviceType = FILESYSTEM_VOLUME_DEVICE; 99: pNewDeviceExtension->pStorageStackDeviceObject = pStorageStackDeviceObject; 100: RtlInitEmptyUnicodeString(&pNewDeviceExtension->DeviceName, 101: pNewDeviceExtension->DeviceNameBuffer, 102: sizeof(pNewDeviceExtension->DeviceNameBuffer) 103: ); 104: LzsbfGetObjectName(pStorageStackDeviceObject, 105: &pNewDeviceExtension->DeviceName); 106:? 107: ExAcquireFastMutex(&gLZSBFilterAttachLock); 108: if (!LzsbfIsAttachedToDevice(DeviceList[i], NULL)) 109: { 110: status = LzsbfAttachToMountedDevice(DeviceList[i], pNewDeviceObject); 111: if (!NT_SUCCESS(status)) 112: { 113: KdPrint(("Fail to attach volume device\n")); 114: LzsbfCleanupMountedDevice(pNewDeviceObject); 115: IoDeleteDevice(pNewDeviceObject); 116: } 117: } 118: else 119: { 120: KdPrint(("Is attached already\n")); 121: LzsbfCleanupMountedDevice(pNewDeviceObject); 122: IoDeleteDevice(pNewDeviceObject); 123: } 124: ExReleaseFastMutex(&gLZSBFilterAttachLock); 125: 126: } 127: __finally 128: { 129: if (pStorageStackDeviceObject != NULL) 130: { 131: ObDereferenceObject(pStorageStackDeviceObject); 132: } 133: ObDereferenceObject(DeviceList[i]); 134: } 135: } 136: ExFreePool(DeviceList); 137: } 138:? 139: KdPrint(("LZSBFilter!lzsbfEnumerateFileSystemVolumes() success!\n")); 140: return STATUS_SUCCESS; 141: }

??? 完成這一過程最主要的調(diào)用是IoEnumerateDeviceObjectList,原型如下,同樣也是Win2K+SP4和WinXP之后才有的調(diào)用.這個函數(shù)能夠枚舉指定驅(qū)動的設(shè)備鏈并返回到一個設(shè)備對象指針數(shù)組當(dāng)中,需要注意的是,此時返回的對象包括文件系統(tǒng)的控制設(shè)備(我們枚舉的是文件系統(tǒng)驅(qū)動的設(shè)備對象),所以在綁定時需要進(jìn)行判斷是否是控制設(shè)備.

1: NTSTATUS 2: IoEnumerateDeviceObjectList( 3: IN PDRIVER_OBJECT DriverObject, 4: IN PDEVICE_OBJECT *DeviceObjectList, 5: IN ULONG DeviceObjectListSize, 6: OUT PULONG ActualNumberDeviceObjects 7: );

??? 在枚舉設(shè)備對象時,除了判斷是否為控制設(shè)備,還需要判斷是否為卷影,卷影是用于磁盤數(shù)據(jù)恢復(fù)的一種特殊設(shè)備,對于卷影我們也是跳過不進(jìn)行綁定.

??? 稍微總結(jié)一下思路:1.注冊文件系統(tǒng)變動回調(diào)函數(shù);2.在回調(diào)函數(shù)中綁定文件系統(tǒng)的控制設(shè)備,綁定控制設(shè)備時需要注意判斷是否是標(biāo)準(zhǔn)文件識別器;3.綁定控制設(shè)備之后,枚舉文件系統(tǒng)驅(qū)動(通過控制設(shè)備對象得到文件系統(tǒng)驅(qū)動對象指針)的設(shè)備鏈,排除卷影和控制設(shè)備本身,綁定其余的卷設(shè)備.

??? 至此,大概的綁定設(shè)備思路就有了,剩下的就是一些實(shí)現(xiàn)細(xì)節(jié),下次再分享..

??? 最后,秉承有圖有碼有真相的原則.附上LOG截圖一張- -

??? to be continue....

轉(zhuǎn)載于:https://www.cnblogs.com/SCUTMSTechClub/archive/2011/03/18/1988386.html

總結(jié)

以上是生活随笔為你收集整理的文件系统过滤驱动开发(一)—Win32底层开发小组的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。