《Windows內核安全與驅動編程》-第十一章文件系統的過濾與監控-day2

文件系統的過濾與監控

文件系統的分發函數

11.2.1 普通的分發函數

​ 上一節僅僅生成了控制設備,開發文件過濾驅動的主要工作還是撰寫分發函數。在 DriverEntry 函數代碼中,DriverObject 是參數驅動對象指針,現在來指定幾個分發函數。SfPassThrough 負責所有不需要的處理,直接下發到下層驅動的IRP。

for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)
	DriverObject->MajorFunction[i] = SfPassThrough;

​ 作爲過濾,一些特殊的分發函數必須特殊處理。爲此,給這些特殊的請求單獨的分發函數,主要包括打開請求(IRP_MJ_CREATE,但本章中暴扣另外兩種主功能號; IRP_MJ_CREATE_NAMED_PIPEIRP_MJ_CREATE_MALSLOT) 、文件系統控制請求(這種控制請求僅在本章出現,主功能號爲 IRP_MJ_FILE_SYSTEM_CONTROL)、清理請求(IRP_MJ_CLEANUP)和關閉請求(IRP_MJ_CLOSE),這些IRP對文件系統來說都很關鍵。

 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;
    DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SfCleanupClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = SfCleanupClose;

​ 首先解決最簡單的過濾,什麼都不處理直接下發:

NT SfPassThrough(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp
)
{
    IoSkipCuttentIrpStackLocation(Irp);
    return IoCallDriver(((PSFILTER_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->AttachedToDeviceObject,Irp);
}

​ 這裏最後的 PSFILTER_DEVICE_EXTENSION 類型設備拓展下的,下層設備 AttachedToDeviceObject 都是我們自定義的過濾設備裏的結構。但是還沒有寫出來,會在後續解決。

​ 到目前爲止,還沒有生成任何過濾設備。只生成了一個簡單的控制設備。

11.2.2 文件過濾的快速IO分發函數

​ 由於該驅動需要綁定到文件系統驅動的上層,文件系統除了處理正常的IRP之外,還要處理所謂的快速IO;除了普通的分發函數以外,還需要爲驅動對象撰寫另一組快速IO分發函數。這組函數的指針在 driver-FastIoDispatch中,而且這裏本來是沒有空間的,所以爲了保存這一數組,需要自己分配空間。

​ 下面使用 ExAllocatePoolWhithTag 分配內存空間。快速IO分發函數表必須在非分頁南村中,所以這裏使用 NonPagedPool

PFAST_IO_DISPATCH fastIoDispatch;
fastIoDispatch = ExAllocatePoolWithTag( NonPagedPool, sizeof( FAST_IO_DISPATCH ), SFLT_POOL_TAG );
    if (!fastIoDispatch) {
	//分配失敗時,刪除山前生成的控制設備
        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;

​ 在介紹該快速IO分發函數的時候,可能會使我們這樣的初學者感到頭痛。爲什麼在前面的串口、鍵盤和硬盤這些過濾驅程序中沒有這麼複雜的接口呢?實際上,驅動對象結構 DRIVER_OBJECT 中既然有快速IO分發函數的設置接口,那麼理論上來說,所有的驅動對象都可以有快速IO分發函數——只是它們可能不會被調用。但是在文件系統中,上層會調用這一函數,所以需要設置。

​ 快速IO分發函數是獨立於普通的處理IRP的分發函數之外的另一組接口。但是它們的作用是一樣的,就是由驅動處理外部給予的請求,而且所請求的處理也基本相同,只是根本沒有IRP,本來應該寫在IRP中的參數,被直接通過函數的參數傳遞進來了。這可以減少分配IRP的效率消耗。

​ 文件系統的普通分發函數和快速IO分發函數都隨時有可能被調用,好的過濾驅動顯然應該同時過濾這兩套接口,但是一般資料都只介紹IRP的過濾方法,快速IO分發函數非常複雜,但是與IRP過濾基本是一一對應的,只要瞭解前者,後者也很容易學會。

​ 在開發學習階段,可以設置所有的快速IO分發函數都返回FALSE並不做任何事。這樣所有的請求都會通過IRP重新發送並被普通分發函數捕獲。有一定的效率損失,但是也可以達到功能需求。

11.2.3 快速IO分發函數的實現

BOOLEAN SfFastIoCheckIfPossible (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN ULONG Length,
    IN BOOLEAN Wait,
    IN ULONG LockKey,
    IN BOOLEAN CheckForReadOperation,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    )
{
        return FALSE;
}

​ 這裏是設置其中一個函數的例子,可以直接返回 FALSE。具體的實現可以再單獨去學習。

總結

這裏主要學了過濾函數的分發函數的設置,其中文件系統中特有的一些快速IO分發函數的瞭解。

明日計劃

驅動編程-設備的綁定前期工作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章