控制設(shè)備(接受我們自己的客服端)----過濾設(shè)備(接受別的進程的IRP) IRP棧每層對應(yīng)的設(shè)備不同
綁定后返回的:最頂層的設(shè)備 看圖 為什么返回最頂層,當(dāng)我們的設(shè)備處理好后要發(fā)給下面的 而下面的第一個就是最頂層的設(shè)備 看圖理解
過濾
分層驅(qū)動中再加一層而不影響它的上下層,以過濾它們之間的數(shù)據(jù),對數(shù)據(jù)或行為進行安全控制。過濾是通過設(shè)備綁定實現(xiàn)的。
圖:
綁定
設(shè)備棧綁定的形式。驅(qū)動自己生成一個設(shè)備(過濾設(shè)備),調(diào)用系統(tǒng)提供的綁定API,綁定到目標(biāo)設(shè)備上。并返回一個在未綁定之前目標(biāo)設(shè)備所在設(shè)備棧的最頂層設(shè)備。這樣發(fā)往下層的IRP或者發(fā)往上層的數(shù)據(jù)都會被過濾設(shè)備截獲。
IoAttachDeviceToDeviceStack( IN PDEVICE_OBJECT SourceDevice, IN PDEVICE_OBJECT TargetDevice );
AttachedDevice需要記錄,以便調(diào)用IoCallDriver()繼續(xù)下發(fā)IRP
為什么要返回一個DEVICE_OBJECT呢?
"并返回一個在未綁定之前目標(biāo)設(shè)備所在設(shè)備棧的最頂層設(shè)備"
一個系統(tǒng)中可能存在多個過濾設(shè)備
------------<-----AttachedDevice
此時最頂層的對象為Filter2Device 返回這個以便IRP下發(fā) 比如放行
圖:
綁定API:
IoAttachDeviceToDeviceStackSafe(2000 SP4以及XP以上) IoAttachDeviceToDeviceStack()
windbg 查看相關(guān)信息:
!devnode 0 1 系統(tǒng)設(shè)備樹
文件系統(tǒng)過濾框架
Filemon //不常見 不能動態(tài)監(jiān)控移動設(shè)備
Sfilter總體流程:
創(chuàng)建控制設(shè)備
創(chuàng)建控制設(shè)備符號鏈接
過濾分發(fā)函數(shù)
Fastio
過濾與綁定
生成一個過濾設(shè)備
IoRegisterFsRegistrationChange(
DriverObject,
SfFsNotification ); (文件系統(tǒng)設(shè)備綁定)
SfFsControl (卷設(shè)備綁定)
一個驅(qū)動,看見幾個文件系統(tǒng)設(shè)備,看見幾個卷設(shè)備,對應(yīng)每一個設(shè)備就生成相應(yīng)設(shè)備附載上去,然后進行相應(yīng)處理。
綁定文件系統(tǒng)是在回調(diào)中(也就是上面的SfFsNotification),綁定卷設(shè)備在分發(fā)函數(shù)中 在綁定文件系統(tǒng)后 在FILR_SYSTEM_COMTEL中就會收到卷設(shè)備創(chuàng)建的信息 就可以綁定卷設(shè)備了 在分發(fā)函數(shù)中創(chuàng)建過濾設(shè)備對象
比如一個U盤插入電腦 ,它第一步需要創(chuàng)建一個文件對象,然后再創(chuàng)建一個卷設(shè)備
我們要動態(tài)Attach到這上面,我們需要Hook這個過程,而這個HOOK過程,我們用回調(diào)的方法
這個回調(diào)的作用是監(jiān)視創(chuàng)建文件設(shè)備行為和綁定文件設(shè)備,綁定文件設(shè)備后,當(dāng)這個U盤要創(chuàng)建卷設(shè)備的時候就會被我攔截到,這個時候我們就可以生成過濾設(shè)備綁定上去了
動態(tài)監(jiān)控卷的掛載(VolumeMounting)概述: 一個新的存儲介質(zhì)被系統(tǒng)發(fā)現(xiàn)并在文件系統(tǒng)中創(chuàng)建一個新的卷Volume的過程被稱為Mounting。其過程是: 文件系統(tǒng)的控制設(shè)備對象(FSCDO)將得到一個IRP,其主功能碼(MajorFunctionCode)為IRP_MJ_FILE_SYSTEM_CONTRO。副功能碼(MinorFunctionCode)為IRP_MN_MOUNT,呵呵,仔細(xì)想一下,不要死板,如果我們創(chuàng)建一個設(shè)備對象,并將其綁定到文件系統(tǒng)控制設(shè)備對象的設(shè)備對象棧上,那么我們的設(shè)備對象不就能接受到這個IRP了嗎!這樣,我們就能時刻的知道新卷的產(chǎn)生了。解決了上面的問題。
這里說說FileMon過濾
FileMon里的方法:
枚舉26個盤符,打開文件,獲得FileObject?DeviceObject.
然后通過自己驅(qū)動生成一個過濾設(shè)備,Attach過濾設(shè)備到DeviceObject上
無法監(jiān)控類似U盤等動態(tài)加載上去的
而IoRegisterFsRegistrationChange是動態(tài)獲取的
Fastio
文件系統(tǒng)除了處理正常的IRP之外,還要處理所謂的FastIo.
FastIo是Cache Manager調(diào)用所引發(fā)的一種沒有irp的請求。換句話說,除了正常的Dispatch Functions之外,你還得為DriverObject撰寫另一組Fast Io Functions.
這組函數(shù)的指針在
driver->FastIoDispatch
代碼:
fastIoDispatch = ExAllocatePoolWithTag( NonPagedPool, sizeof( FAST_IO_DISPATCH ), IoDeleteDevice( gSFilterControlDeviceObject ); return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory( fastIoDispatch, sizeof( FAST_IO_DISPATCH ) ); fastIoDispatch->SizeOfFastIoDispatch = sizeof( FAST_IO_DISPATCH ); fastIoDispatch->FastIoCheckIfPossible = SfFastIoCheckIfPossible; fastIoDispatch->FastIoRead = SfFastIoRead; fastIoDispatch->FastIoWrite = SfFastIoWrite; fastIoDispatch->FastIoQueryBasicInfo = SfFastIoQueryBasicInfo; fastIoDispatch->FastIoQueryStandardInfo = SfFastIoQueryStandardInfo; fastIoDispatch->FastIoLock = SfFastIoLock; fastIoDispatch->FastIoUnlockSingle = SfFastIoUnlockSingle; fastIoDispatch->FastIoUnlockAll = SfFastIoUnlockAll; fastIoDispatch->FastIoUnlockAllByKey = SfFastIoUnlockAllByKey; fastIoDispatch->FastIoDeviceControl = SfFastIoDeviceControl; fastIoDispatch->FastIoDetachDevice = SfFastIoDetachDevice; fastIoDispatch->FastIoQueryNetworkOpenInfo = SfFastIoQueryNetworkOpenInfo; fastIoDispatch->MdlRead = SfFastIoMdlRead; fastIoDispatch->MdlReadComplete = SfFastIoMdlReadComplete; fastIoDispatch->PrepareMdlWrite = SfFastIoPrepareMdlWrite; fastIoDispatch->MdlWriteComplete = SfFastIoMdlWriteComplete; fastIoDispatch->FastIoReadCompressed = SfFastIoReadCompressed; fastIoDispatch->FastIoWriteCompressed = SfFastIoWriteCompressed; fastIoDispatch->MdlReadCompleteCompressed = SfFastIoMdlReadCompleteCompressed; fastIoDispatch->MdlWriteCompleteCompressed = SfFastIoMdlWriteCompleteCompressed; fastIoDispatch->FastIoQueryOpen = SfFastIoQueryOpen; DriverObject->FastIoDispatch = fastIoDispatch;
看看我們的分發(fā)函數(shù):
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = SfPassThrough;//通用分發(fā)函數(shù) 下發(fā)IRP 私用IoSkip 和 IoCallDriver // We will use SfCreate for all the create operations DriverObject->MajorFunction[IRP_MJ_CREATE] = SfCreate; //DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = SfCreate; //DriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = SfCreate; DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = SfFsControl;//注意這個 當(dāng)我們下面綁定了文件系統(tǒng)設(shè)備,我們就會收到這個IRP 在這個IRP處理函數(shù)中 我們就可以//綁定了卷設(shè)備對象了 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SfCleanupClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = SfCleanupClose;
Sfilter代碼通讀分析
將我們驅(qū)動的對象保存起來---等會綁定文件系統(tǒng)設(shè)備的時候要用到
gSFilterDriverObject = DriverObject;
首先我們初始化一個鏈表,這個鏈表用來內(nèi)存管理,防止碎片,等會再SfCreate中有很多數(shù)據(jù),可能需要頻繁的申請內(nèi)存,這樣不便于管理
我們在開頭就初始化這個一個鏈表,當(dāng)需要用到內(nèi)存的時候就到這面來拿
ExInitializeFastMutex( &gSfilterAttachLock ); // Initialize the lookaside list for name buffering. This is used in // several places to avoid having a large name buffer on the stack. It is // also needed by the name lookup routines (NLxxx). ExInitializePagedLookasideList( &gSfNameBufferLookasideList, SFLT_POOL_TAG_NAME_BUFFER,
接下來就是創(chuàng)建設(shè)備對象
首先在
"\\FileSystem\\Filters\\SFilterDrv"
中創(chuàng)建,如果創(chuàng)建失敗就在
"\\FileSystem\\SFilterDrv"
中創(chuàng)建 與NTMod不同的是 NTmodel中我們創(chuàng)建對象的時候?qū)ο笫荱NKNOW_DEVICE 這里我們創(chuàng)建的是磁盤文件系統(tǒng)設(shè)備
RtlInitUnicodeString( &nameString, L"\\FileSystem\\Filters\\SFilterDrv" ); status = IoCreateDevice( DriverObject, 0, //has no device extension FILE_DEVICE_DISK_FILE_SYSTEM, &gSFilterControlDeviceObject );//保存下來 后面判斷是發(fā)給我們的驅(qū)動的還是發(fā)給文件系統(tǒng)的 if (status == STATUS_OBJECT_PATH_NOT_FOUND) { // This must be a version of the OS that doesn't have the Filters // path in its namespace. This was added in Windows XP. // We will try just putting our control device object in the // \FileSystem portion of the object name space. RtlInitUnicodeString( &nameString, L"\\FileSystem\\SFilterDrv" ); status = IoCreateDevice( DriverObject, 0, //has no device extension FILE_DEVICE_DISK_FILE_SYSTEM, &gSFilterControlDeviceObject ); if (!NT_SUCCESS( status )) { KdPrint( ("SFilter!DriverEntry: Error creating control device object \"%wZ\", status=%08x\n", } else if (!NT_SUCCESS( status )) { KdPrint(( "SFilter!DriverEntry: Error creating control device object \"%wZ\", status=%08x\n",
然后就是設(shè)置我們的通信模式了
默認(rèn)是BUFFIO
gSFilterControlDeviceObject->Flags |= DO_BUFFERED_IO; //gSFilterControlDeviceObject是我們保存的我們驅(qū)動的對象
接下去就是初始化分發(fā)函數(shù)了
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = SfPassThrough; // We will use SfCreate for all the create operations DriverObject->MajorFunction[IRP_MJ_CREATE] = SfCreate; //DriverObject->MajorFunction[IRP_MJ_CREATE_NAMED_PIPE] = SfCreate; //DriverObject->MajorFunction[IRP_MJ_CREATE_MAILSLOT] = SfCreate; 注意這個 當(dāng)我們下面綁定了文件系統(tǒng)設(shè)備,我們就會收到這個IRP 在這個IRP處理函數(shù)中 我們就可以//綁定了卷設(shè)備對象了 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = SfFsControl;//卷設(shè)備綁定 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SfCleanupClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = SfCleanupClose;
前面說過了,不但有Dispatch分發(fā)函數(shù) 也有 fastIoDispatch
fastIoDispatch = ExAllocatePoolWithTag( NonPagedPool, sizeof( FAST_IO_DISPATCH ), IoDeleteDevice( gSFilterControlDeviceObject ); return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory( fastIoDispatch, sizeof( FAST_IO_DISPATCH ) ); fastIoDispatch->SizeOfFastIoDispatch = sizeof( FAST_IO_DISPATCH ); fastIoDispatch->FastIoCheckIfPossible = SfFastIoCheckIfPossible; fastIoDispatch->FastIoRead = SfFastIoRead; fastIoDispatch->FastIoWrite = SfFastIoWrite; fastIoDispatch->FastIoQueryBasicInfo = SfFastIoQueryBasicInfo; fastIoDispatch->FastIoQueryStandardInfo = SfFastIoQueryStandardInfo; fastIoDispatch->FastIoLock = SfFastIoLock; fastIoDispatch->FastIoUnlockSingle = SfFastIoUnlockSingle; fastIoDispatch->FastIoUnlockAll = SfFastIoUnlockAll; fastIoDispatch->FastIoUnlockAllByKey = SfFastIoUnlockAllByKey; fastIoDispatch->FastIoDeviceControl = SfFastIoDeviceControl; fastIoDispatch->FastIoDetachDevice = SfFastIoDetachDevice; fastIoDispatch->FastIoQueryNetworkOpenInfo = SfFastIoQueryNetworkOpenInfo; fastIoDispatch->MdlRead = SfFastIoMdlRead; fastIoDispatch->MdlReadComplete = SfFastIoMdlReadComplete; fastIoDispatch->PrepareMdlWrite = SfFastIoPrepareMdlWrite; fastIoDispatch->MdlWriteComplete = SfFastIoMdlWriteComplete; fastIoDispatch->FastIoReadCompressed = SfFastIoReadCompressed; fastIoDispatch->FastIoWriteCompressed = SfFastIoWriteCompressed; fastIoDispatch->MdlReadCompleteCompressed = SfFastIoMdlReadCompleteCompressed; fastIoDispatch->MdlWriteCompleteCompressed = SfFastIoMdlWriteCompleteCompressed; fastIoDispatch->FastIoQueryOpen = SfFastIoQueryOpen; DriverObject->FastIoDispatch = fastIoDispatch;
然后就是初始化一些回調(diào)函數(shù)被設(shè)置在我們的驅(qū)動對象上 也就是注冊回調(diào)函數(shù)
FS_FILTER_CALLBACKS fsFilterCallbacks; if (NULL != gSfDynamicFunctions.RegisterFileSystemFilterCallbacks) { // Setup the callbacks for the operations we receive through // the FsFilter interface. // NOTE: You only need to register for those routines you really // need to handle. SFilter is registering for all routines // simply to give an example of how it is done. fsFilterCallbacks.SizeOfFsFilterCallbacks = sizeof( FS_FILTER_CALLBACKS ); fsFilterCallbacks.PreAcquireForSectionSynchronization = SfPreFsFilterPassThrough; fsFilterCallbacks.PostAcquireForSectionSynchronization = SfPostFsFilterPassThrough; fsFilterCallbacks.PreReleaseForSectionSynchronization = SfPreFsFilterPassThrough; fsFilterCallbacks.PostReleaseForSectionSynchronization = SfPostFsFilterPassThrough; fsFilterCallbacks.PreAcquireForCcFlush = SfPreFsFilterPassThrough; fsFilterCallbacks.PostAcquireForCcFlush = SfPostFsFilterPassThrough; fsFilterCallbacks.PreReleaseForCcFlush = SfPreFsFilterPassThrough; fsFilterCallbacks.PostReleaseForCcFlush = SfPostFsFilterPassThrough; fsFilterCallbacks.PreAcquireForModifiedPageWriter = SfPreFsFilterPassThrough; fsFilterCallbacks.PostAcquireForModifiedPageWriter = SfPostFsFilterPassThrough; fsFilterCallbacks.PreReleaseForModifiedPageWriter = SfPreFsFilterPassThrough; fsFilterCallbacks.PostReleaseForModifiedPageWriter = SfPostFsFilterPassThrough; status = (gSfDynamicFunctions.RegisterFileSystemFilterCallbacks)( DriverObject, if (!NT_SUCCESS( status )) { DriverObject->FastIoDispatch = NULL; ExFreePoolWithTag( fastIoDispatch, SFLT_POOL_TAG_FASTIO ); IoDeleteDevice( gSFilterControlDeviceObject );
接下去就是創(chuàng)建一個回調(diào),監(jiān)視文件系統(tǒng)設(shè)備創(chuàng)建,
在這個回調(diào)中,我們可以監(jiān)控文件系統(tǒng)創(chuàng)建和綁定文件系統(tǒng)設(shè)備
status = IoRegisterFsRegistrationChange( DriverObject, SfFsNotification );//在里面綁定文件系統(tǒng)設(shè)備,也是卷設(shè)備綁定的前提條件 if (!NT_SUCCESS( status )) { KdPrint(( "SFilter!DriverEntry: Error registering FS change notification, status=%08x\n", DriverObject->FastIoDispatch = NULL; ExFreePoolWithTag( fastIoDispatch, SFLT_POOL_TAG_FASTIO ); IoDeleteDevice( gSFilterControlDeviceObject );
然后就是對文件計數(shù)引用
IoGetDeviceObjectPointer函數(shù)的功能是: 它從下層的設(shè)備對象名稱來獲得下層設(shè)備指針。該函數(shù)造成了對下層設(shè)備對象以及下層設(shè)備對象所對應(yīng)的文件對象的引用。 如果本層驅(qū)動在卸載之前對下層的設(shè)備對象的引用還沒有消除,則下層驅(qū)動的卸載會被停止。因此必須要消除對下層設(shè)備對象的引用。 但是程序一般不會直接對下層設(shè)備對象的引用減少。因此只要減少對文件對象的引用就可以減少文件對象和設(shè)備對象兩個對象的引用。 事實上,IoGetDeviceObjectPointer返回的并不是下層設(shè)備對象的指針,而是該設(shè)備堆棧中頂層的設(shè)備對象的指針。 IoGetDeviceObjectPointer函數(shù)的調(diào)用必須在 IRQL=PASSIVE_LEVEL的級別上運行。 PDEVICE_OBJECT rawDeviceObject; // Attach to RawDisk device RtlInitUnicodeString( &nameString, L"\\Device\\RawDisk" ); status = IoGetDeviceObjectPointer( if (NT_SUCCESS( status )) { SfFsNotification( rawDeviceObject, TRUE );//綁定RawDisk 激活這個設(shè)備 然后被我們捕捉到,綁定過濾設(shè)備 ObDereferenceObject( fileObject ); // Attach to the RawCdRom device RtlInitUnicodeString( &nameString, L"\\Device\\RawCdRom" ); status = IoGetDeviceObjectPointer( if (NT_SUCCESS( status )) { SfFsNotification( rawDeviceObject, TRUE );//同上 ObDereferenceObject( fileObject ); // Clear the initializing flag on the control device object since we // have now successfully initialized everything. ClearFlag( gSFilterControlDeviceObject->Flags, DO_DEVICE_INITIALIZING ); DbgPrint("Sfilter installed\n");
去看看SfFsNotification
//回調(diào)例程,當(dāng)文件系統(tǒng)被激活或者撤銷時調(diào)用//在該例程中,完成對文件系統(tǒng)控制設(shè)備對象的綁定.
綁定文件系統(tǒng): 首先,我們需要知道當(dāng)前系統(tǒng)中都有那些文件系統(tǒng),例如:NTFS,F(xiàn)AT32,CDFS。因為,卷設(shè)備對象是由文件系統(tǒng)創(chuàng)建的。 其次,我們要知道什么時候去綁定文件系統(tǒng)。當(dāng)一個卷設(shè)備對象動態(tài)產(chǎn)生的時候,其對應(yīng)的文件系統(tǒng)就被激活。例如,如果一個FAT32的U盤被插入到電腦上,則對應(yīng)的FAT32文件系統(tǒng)就會被激活,并創(chuàng)建一個“J:”的卷設(shè)備對象。 IoRegisterFsRegistrationChange是一個非常有用的系統(tǒng)調(diào)用。這個調(diào)用注冊一個回調(diào)函數(shù),當(dāng)系統(tǒng)中有文件系統(tǒng)被激活或者撤銷時,該回調(diào)函數(shù)就被調(diào)用。OhGood,那么我們就可以在這個回調(diào)函數(shù)中去綁定文件系統(tǒng)的控制設(shè)備對象。 這里要注意:文件系統(tǒng)的加載和卷的掛載是兩碼事,卷的掛載是建立在文件系統(tǒng)被激活的基礎(chǔ)上。當(dāng)一個文件系統(tǒng)被激活后,才能創(chuàng)建卷設(shè)備對象
SfFsNotification是我們要注冊的回調(diào)函數(shù),它調(diào)用SfAttachToFileSystemDevice完成真正的設(shè)備綁定。當(dāng)然,它還有其他功能,代碼說明問題。 SfAttachToFileSystemDevice創(chuàng)建過濾設(shè)備對象,并調(diào)用我們設(shè)備綁定外包函數(shù):SfAttachDeviceToDeviceStack來將過濾設(shè)備對象綁定到文件系統(tǒng)控制設(shè)備對象的設(shè)備棧上。 這樣,我們的過濾設(shè)備對象就能接受到發(fā)送到FSCDO的IRP_MJ_FILE_SYSTEM_CONTRO的請求,動態(tài)監(jiān)控卷的掛載。那么以后的工作就是完成對卷的監(jiān)控綁定了。
回調(diào)例程,當(dāng)文件系統(tǒng)被激活或者撤銷時調(diào)用
//在該例程中,完成對文件系統(tǒng)控制設(shè)備對象的綁定.//
//例程描述:
這個例程在文件系統(tǒng)激活或者銷毀的時被調(diào)用
這個例程創(chuàng)建一個設(shè)備對象將它附加到指定的文件系統(tǒng)控制設(shè)備對象
//的對象棧上,這就允許這個設(shè)備對象過濾所有發(fā)送給文件系統(tǒng)的請求.
//這樣,我們就能獲得一個掛載卷的請求,就可以附加到這個新的卷設(shè)備對象
//的設(shè)備對象棧上//
//參數(shù):
DeviceObject:指向被激活或者撤銷的文件系統(tǒng)的控制設(shè)備對象
FsActive:激活或者撤銷標(biāo)志
// Display the names of all the file system we are notified of devName = NLGetAndAllocateObjectName( DeviceObject, &gSfNameBufferLookasideList ); SF_LOG_PRINT( SFDEBUG_DISPLAY_ATTACHMENT_NAMES, ("SFilter!SfFsNotification: Not attaching to %p, insufficient resources.\n", SF_LOG_PRINT( SFDEBUG_DISPLAY_ATTACHMENT_NAMES, ("SFilter!SfFsNotification: %s %p \"%wZ\" (%s)\n", (FsActive) ? "Activating file system " : "Deactivating file system", GET_DEVICE_TYPE_NAME(DeviceObject->DeviceType)) ); // Handle attaching/detaching from the given file system. SfAttachToFileSystemDevice( DeviceObject, devName ); SfDetachFromFileSystemDevice( DeviceObject ); // We're done with name (SfAttachToFileSystemDevice copies the name to // the device extension) so free it. NLFreeNameControl( devName, &gSfNameBufferLookasideList );
這個綁定了文件設(shè)備對象,這時我們就可以收到IRP_MJ_FILE_SYSTEM_CONTROL IRP 在這個例程里我們就可以實現(xiàn)對卷的綁定
(注意 這里必須綁定了文件設(shè)備后才能收到哦) 看下IRP_MJ_FILE_SYSTEM_CONTROL的例程
switch (irpSp->MinorFunction) { case IRP_MN_MOUNT_VOLUME://設(shè)備在Mount的時候,我們就要進行綁定了 return SfFsControlMountVolume( DeviceObject, Irp ); case IRP_MN_LOAD_FILE_SYSTEM: return SfFsControlLoadFileSystem( DeviceObject, Irp ); case IRP_MN_USER_FS_REQUEST: switch (irpSp->Parameters.FileSystemControl.FsControlCode) { case FSCTL_DISMOUNT_VOLUME: PSFILTER_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension; SF_LOG_PRINT( SFDEBUG_DISPLAY_ATTACHMENT_NAMES, ("SFilter!SfFsControl: Dismounting volume %p \"%wZ\"\n", devExt->NLExtHeader.AttachedToDeviceObject, &devExt->NLExtHeader.DeviceName) ); // Pass all other file system control requests through. IoSkipCurrentIrpStackLocation( Irp ); return IoCallDriver( ((PSFILTER_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->NLExtHeader.AttachedToDeviceObject,
差不多就是這樣,我們來看看其它分發(fā)函數(shù)
比如SfCreate
我們要做的工作就是在分發(fā)函數(shù)里寫代碼
IN PDEVICE_OBJECT DeviceObject, This function filters create/open operations. It simply establishes an I/O completion routine to be invoked if the operation was successful. DeviceObject - Pointer to the target device object of the create/open. Irp - Pointer to the I/O Request Packet that represents the operation. The function value is the status of the call to the file system's entry PNAME_CONTROL fileName = NULL; PSFILTER_DEVICE_EXTENSION devExt = (PSFILTER_DEVICE_EXTENSION)(DeviceObject->DeviceExtension); PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); // If this is for our control device object, don't allow it to be opened. //如果是我們的設(shè)備 返回成功 這個宏判斷設(shè)備對象是不是我們保存那個和是不是我們的驅(qū)動對象 if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) { // Sfilter doesn't allow for any communication through its control // device object, therefore it fails all requests to open a handle // to its control device object. // See the FileSpy sample for an example of how to allow creates to // the filter's control device object and manage communication via //Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return STATUS_INVALID_DEVICE_REQUEST; ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject )); // If debugging is enabled, do the processing required to see the packet // upon its completion. Otherwise, let the request go with no further if (!FlagOn( SfDebug, SFDEBUG_DO_CREATE_COMPLETION | SFDEBUG_GET_CREATE_NAMES| SFDEBUG_DISPLAY_CREATE_NAMES )) { // We don't want to get filenames, display filenames, or // call our completion routine. Don't put us on the stack // and call the next driver. IoSkipCurrentIrpStackLocation( Irp ); return IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->NLExtHeader.AttachedToDeviceObject, if (FlagOn( SfDebug, SFDEBUG_GET_CREATE_NAMES | SFDEBUG_DISPLAY_CREATE_NAMES ) && !FlagOn(devExt->Flags,SFDEVFL_DISABLE_VOLUME)) { // Debugging specifies that we need to get the filename NAME_LOOKUP_FLAGS LookupFlags = 0x00000000; // If DosName has been set, indicate via flags that we // want to use it when getting the full file name. if (devExt->NLExtHeader.DosName.Length != 0) { SetFlag( LookupFlags, NLFL_USE_DOS_DEVICE_NAME ); // Indicate we are in pre-create SetFlag( LookupFlags, NLFL_IN_CREATE ); if (FlagOn( irpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID )) { // The file is being opened by ID, not file name. SetFlag( LookupFlags, NLFL_OPEN_BY_ID ); if (FlagOn( irpSp->Flags, SL_OPEN_TARGET_DIRECTORY )) { // The file's parent directory should be opened SetFlag( LookupFlags, NLFL_OPEN_TARGET_DIR ); // Retrieve the file name. Note that in SFilter we don't do any name status = NLAllocateNameControl( &fileName, &gSfNameBufferLookasideList ); if (NT_SUCCESS( status )) { // We are okay not checking the return value here because // the GetFullPathName function will set the Unicode String // length to 0. So either way, in an error it will print an empty string status = NLGetFullPathName( irpSp->FileObject, &gSfNameBufferLookasideList, if (FlagOn( SfDebug, SFDEBUG_DISPLAY_CREATE_NAMES | SFDEBUG_DO_CREATE_COMPLETION ) && !FlagOn(devExt->Flags,SFDEVFL_DISABLE_VOLUME)) { // Debugging flags indicate we must do completion. // Note that to display file names we must do completion // because we don't know IoStatus.Status and IoStatus.Information // Initialize an event to wait for the completion routine to occur KeInitializeEvent( &waitEvent, NotificationEvent, FALSE ); // Copy the stack and set our Completion routine IoCopyCurrentIrpStackLocationToNext( Irp ); // Call the next driver in the stack. status = IoCallDriver( devExt->NLExtHeader.AttachedToDeviceObject, Irp ); // Wait for the completion routine to be called if (STATUS_PENDING == status) { NTSTATUS localStatus = KeWaitForSingleObject( &waitEvent, ASSERT(STATUS_SUCCESS == localStatus); // Verify the IoCompleteRequest was called ASSERT(KeReadStateEvent(&waitEvent) || !NT_SUCCESS(Irp->IoStatus.Status)); // If debugging indicates we should display file names, do it. if (irpSp->Parameters.Create.Options & FILE_OPEN_BY_FILE_ID) { SF_LOG_PRINT( SFDEBUG_DISPLAY_CREATE_NAMES, ("SFilter!SfCreate: OPENED fo=%p %08x:%08x %wZ (FID)\n", Irp->IoStatus.Information, SF_LOG_PRINT( SFDEBUG_DISPLAY_CREATE_NAMES, ("SFilter!SfCreate: OPENED fo=%p st=%08x:%08x %wZ\n", Irp->IoStatus.Information, // Release the name control structure if we have NLFreeNameControl( fileName, &gSfNameBufferLookasideList ); // Save the status and continue processing the IRP status = Irp->IoStatus.Status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); // Free the name control if we have one NLFreeNameControl( fileName, &gSfNameBufferLookasideList ); // Debugging flags indicate we did not want to display the file name // or call completion routine. // (ie SFDEBUG_GET_CREATE_NAMES && !SFDEBUG_DO_CREATE_COMPLETION) IoSkipCurrentIrpStackLocation( Irp ); return IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->NLExtHeader.AttachedToDeviceObject,
再來看看分發(fā)函數(shù)
非過濾驅(qū)動中的默CommonDispatch
PDEVICE_OBJECT DeviceObject, Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp,IO_NO_INCREMENT);
過濾驅(qū)動中CommonDispatch寫法
IN PDEVICE_OBJECT DeviceObject, PIO_STACK_LOCATION pIrp = IoGetCurrentIrpStackLocation( Irp ); ASSERT(!IS_MY_CONTROL_DEVICE_OBJECT( DeviceObject )); ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject )); if (!IS_MY_DEVICE_OBJECT(DeviceObject) || IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject)) NTSTATUS status = Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest( Irp, IO_NO_INCREMENT ); IoSkipCurrentIrpStackLocation( Irp ); return IoCallDriver( ((PSFILTER_DEVICE_EXTENSION) DeviceObject->DeviceExtension)->NLExtHeader.AttachedToDeviceObject,
一個是結(jié)束IRP 一個是判斷是不是發(fā)給我們驅(qū)動的 如果是就返回?zé)o效的參數(shù),(這里是返回失敗,但在攔截的分發(fā)函數(shù)中是需要放行的這個放行是返回success)
對一個主防來說:
等
對于一個主防來說 一般是攔截創(chuàng)建 和 關(guān)閉 為什么要攔截關(guān)閉呢 一個人現(xiàn)在是好人,但他不一定一輩子都是好人
創(chuàng)建文件 我們放了,然后它寫入了一個shellcode 如果我們攔截寫的話 一個一個的攔截 效果并不好 在關(guān)閉的時候我們就可以一次性知道
深入理解下設(shè)備對象
設(shè)備對象類別
Sfilter自己的設(shè)備
控制設(shè)備
過濾設(shè)備
其它設(shè)備
文件系統(tǒng)設(shè)備
卷設(shè)備
設(shè)備類別
FILE_DEVICE_DISK_FILE_SYSTEM
#define IS_MY_DEVICE_OBJECT(_devObj) \ (((_devObj) != NULL) && \ ((_devObj)->DriverObject == gSFilterDriverObject) && \ ((_devObj)->DeviceExtension != NULL)) #define IS_MY_CONTROL_DEVICE_OBJECT(_devObj) \ (((_devObj) == gSFilterControlDeviceObject) ? \ (ASSERT(((_devObj)->DriverObject == gSFilterDriverObject) && \ ((_devObj)->DeviceExtension == NULL)), TRUE) : \ #define IS_DESIRED_DEVICE_TYPE(_type) \ (((_type) == FILE_DEVICE_DISK_FILE_SYSTEM) || \ ((_type) == FILE_DEVICE_CD_ROM_FILE_SYSTEM) || \ ((_type) == FILE_DEVICE_NETWORK_FILE_SYSTEM))
三種類型的設(shè)備處理
NTSTATUS FilterXXX(PDEVICE_OBJECT DeviceObject, PIRP pIrp)//過濾設(shè)備 NTSTATUS Status = STATUS_SUCCESS; IO_STACK_LOCATION* lpIrpStack = IoGetCurrentIrpStackLocation(pIrp); if (IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject))//控制設(shè)備 pIrp->IoStatus.Status = Status; pIrp->IoStatus.Information = ulInfomation; IoCompleteRequest(lpIrp, IO_NO_INCREMENT); else if (!IS_MY_DEVICE_OBJECT(DeviceObject)) pIrp->IoStatus.Status = Status = STATUS_INVALID_PARAMETER; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); IoSkipCurrentIrpStackLocation( pIrp ); Status = IoCallDriver(((PSFILTER_DEVICE_EXTENSION)->DeviceExtension)DeviceObject->NLExtHeader.AttachedToDeviceObject, pIrp);
重要問題:文件路徑的解析與保存
Namelookup.c(構(gòu)造IRP,不能用 ObQueryNameString)
NLGetFullPathName()?
NLPQueryFileSystemForFileName()?IRP查詢
在SfCreate里查詢名字,通過FILE_OBJECT與Name保存起來。供其它過濾函數(shù)中查詢使用。
保存在哪里?
List_Entry
HASH
TREE
Sfilter安裝測試
原始的Sfilter框架,不支持通信
sfCreate中對自己的控制設(shè)備,返回成功
符號鏈接的創(chuàng)建(框架中沒有)
GroupOrder:"FSFilter Activity Monitor“ L\\FileSystem\\SFilterDrv DeviceObject?Flags |= DO_BUFFERED_IO
不要在release版本使用DriverUnload。BSOD
既然是過濾 那么就有放和禁
FilterCreate:
放:
內(nèi)核過來的
Irp->RequestorMode == KernelMode 本進程的
FilterDeviceIoctrl中 PsGetCurrentProcessId() 系統(tǒng)進程的
DriverEntry里:PsGetCurrentProcessId() 文件夾
ulOptions = IrpStack->Parameters.Create.Options ; FlagOn(IrpStack->FileObject->Flags, FO_VOLUME_OPEN) || FlagOn(ulOptions, FILE_DIRECTORY_FILE) || FlagOn(IrpStack->Flags, SL_OPEN_PAGING_FILE)
分頁IO
(Irp->Flags & IRP_PAGING_IO) || (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) KeGetCurrentIrql() > APC_LEVEL
如何放?
IoSkipCurrentIrpStackLocation( lpIrp );
禁:自定義啦 比如禁止在driver目錄寫入sys文件
拿文件名/長短名轉(zhuǎn)化 短文轉(zhuǎn)長名
匹配規(guī)則
FsRtlIsNameInExpression
彈框
攔
STATUS_ACCESS_DENIED
放
Pending完成例程
加入表中,供其它Filter函數(shù)使用
FilterWrite:
放:
本進程
系統(tǒng)進程
分頁IO
從表中根據(jù)file_object沒有找到的
匹配規(guī)則
彈框
攔截
放
效率
多次寫?
FilterSetInfo:攔截刪除,重命名等
IrpStack->Parameters.SetFile.FileInformationClass
FileRenameInformation//重命名
如何拿重命名之后的文件名?
IrpSp->Parameters.SetFile.FileObject//測試無效
IrpSp->FileObject//測試無效
Irp->AssociatedIrp.SystemBuffer;//有效
//R3UserResult = hipsGetResultFromUser(szOper, lpNameControl->Name.Buffer, ((PFILE_RENAME_INFORMATION)(lpIrp->AssociatedIrp.SystemBuffer))->FileName, User_DefaultNon); if(R3UserResult == User_Block) <span style="white-space:pre"></span>goto Ex; DbgPrint("%ws\n",((PFILE_RENAME_INFORMATION)(lpIrp->AssociatedIrp.SystemBuffer))->FileName);
fileObject->DeviceObject
RtlVolumeDeviceToDosName
ObQueryNameString
IoQueryFileDosDeviceName
FileDispositionInformation//刪除
刪除
例子: 這個例子中還沒拿到重命名后的文件名 和將重命名后的文件名傳給R3 (hipsGetResultFromUser的第三個參數(shù))
sfSetInformation(PDEVICE_OBJECT lpDevice, PIRP lpIrp) NTSTATUSStatus= STATUS_SUCCESS; UNICODE_STRINGustrRule= {0}; PLIST_ENTRYCurrentList= NULL; USER_RESULTR3UserResult= User_Pass; PNAME_CONTROLlpNameControl= NULL; BOOLEANbNeedPostOp= FALSE; IO_STACK_LOCATION*lpIrpStack= IoGetCurrentIrpStackLocation(lpIrp); PFILE_OBJECTlpFileObject= lpIrpStack->FileObject; if (IS_MY_CONTROL_DEVICE_OBJECT(lpDevice)) lpIrp->IoStatus.Status = Status; lpIrp->IoStatus.Information = ulInfomation; IoCompleteRequest(lpIrp, IO_NO_INCREMENT); else if (!IS_MY_DEVICE_OBJECT(lpDevice)) lpIrp->IoStatus.Status = Status = STATUS_INVALID_PARAMETER; lpIrp->IoStatus.Information = 0; IoCompleteRequest(lpIrp, IO_NO_INCREMENT); PSFILTER_DEVICE_EXTENSION lpDevExt = (PSFILTER_DEVICE_EXTENSION)(lpDevice->DeviceExtension); if (PsGetCurrentProcessId() == g_hSystemProcID) pTwoWay = Find((DWORD)lpFileObject, g_pHashTable); lpNameControl = pTwoWay->data.lpNameControl; if (lpIrpStack->Parameters.SetFile.FileInformationClass == FileRenameInformation || lpIrpStack->Parameters.SetFile.FileInformationClass == FileBasicInformation || lpIrpStack->Parameters.SetFile.FileInformationClass == FileAllocationInformation || lpIrpStack->Parameters.SetFile.FileInformationClass == FileEndOfFileInformation || lpIrpStack->Parameters.SetFile.FileInformationClass == FileDispositionInformation) switch (lpIrpStack->Parameters.SetFile.FileInformationClass) case FileAllocationInformation: case FileEndOfFileInformation: case FileRenameInformation: case FileBasicInformation: szOper = L"設(shè)置基礎(chǔ)信息"; case FileDispositionInformation: RtlInitUnicodeString(&ustrRule, L"C:\\WINDOWS\\SYSTEM32\\*\\*.SYS"); if (!IsPatternMatch(&ustrRule, &lpNameControl->Name, TRUE)) if (lpIrpStack->Parameters.SetFile.FileInformationClass == FileRenameInformation) R3UserResult = hipsGetResultFromUser(szOper, lpNameControl->Name.Buffer, NULL, User_DefaultNon); if (R3UserResult == User_Block) lpIrp->IoStatus.Information = 0; lpIrp->IoStatus.Status = STATUS_ACCESS_DENIED; IoCompleteRequest(lpIrp, IO_NO_INCREMENT); Status = STATUS_ACCESS_DENIED; IoCopyCurrentIrpStackLocationToNext(lpIrp); KeInitializeEvent(&waitEvent, IoSetCompletionRoutine(lpIrp, ((PSFILTER_DEVICE_EXTENSION)lpDevice->DeviceExtension)->NLExtHeader.AttachedToDeviceObject, if (Status == STATUS_PENDING) Status = KeWaitForSingleObject(&waitEvent, Status = lpIrp->IoStatus.Status; IoCompleteRequest(lpIrp, IO_NO_INCREMENT);
參考:
http://blog.csdn.net/cosmoslife/article/details/7727688
http://bbs./archive/index.php?t-152338.html
|