Posted on 2010-02-18 14:57
S.l.e!ep.¢% 閱讀(1324)
評論(0) 編輯 收藏 引用 所屬分類:
Windows WDM
1> ? IFS ? 流程圖 ?
? a.生成一個控制設備.當然此前你必須給控制設置指定名稱. ?
? b.設置Dispatch ? Functions. ? ?
? c.設置Fast ? Io ? Functions. ? ?
? d.編寫一個my_fs_notify回調函數,在其中綁定剛激活的FS ? CDO. ? ?
? e.使用wdff_reg_notify調用注冊這個回調函數。 ?
? f.編寫默認的dispatch ? functions. ? ?
? g.處理IRP_MJ_FILE_SYSTEM_CONTROL,在其中監控Volumne的Mount和Dismount. ? ?
? h.下一步自然是綁定Volumne了. ?
? (全路徑是在 ? FileObject->FileName.Buffer中得到的.) ?
? 2>一些必要知識 ?
? a.幾個概念的區別 ?
? 1.多數的storage ? drivers ? 是PNP管理的,存在一個設備節點(DEVNODE),(It ? is ? important ? to ? note ? that ? file ? systems ? and ? file ? system ? filter ? drivers ? are ? not ? PnP ? device ? drivers;),每個設備節點上維護一個Storage ? Device ? Stacks,這個就是因為每個存儲設備,例如磁盤設備,可能包含一個或者多個邏輯卷(分區或者動態卷),這些卷就是通過這個Storage ? Device ? Stack來保存的。該設備點的信息就是functional ? device ? object ? (FDO)。剩下的就是physical ? device ? objects ? (PDO)代表各個分區。 ?
? ? ? 2.通過下面的方式可以得到卷的名稱 ?
? ? ? The ? Mount ? Manager ? responds ? to ? the ? arrival ? of ? a ? new ? storage ? volume ? by ? querying ? the ? volume ? driver ? for ? the ? following ? information: ? ?
? ? ? ·The ? volume's ? nonpersistent ? device ? object ? name ? (or ? target ? name), ? located ? in ? the ? Device ? directory ? of ? the ? system ? object ? tree ? (for ? example: ? "\Device\HarddiskVolume1") ? ?
? ? ? ·The ? volume's ? globally ? unique ? identifier ? (GUID), ? also ? called ? the ? unique ? volume ? name ? ?
? ? ? ·A ? suggested ? persistent ? symbolic ? link ? name ? for ? the ? volume, ? such ? as ? a ? drive ? letter ? (for ? example, ? "\DosDevices\D:") ? ?
? ? ? 3.文件系統和卷的區別 ?
? ? ? When ? a ? file ? system ? is ? mounted ? on ? a ? storage ? volume, ? it ? creates ? a ? file ? system ? volume ? device ? object ? (VDO) ? to ? represent ? the ? volume ? to ? the ? file ? system. ? The ? file ? system ? VDO ? is ? mounted ? on ? the ? storage ? device ? object ? by ? means ? of ? a ? shared ? object ? called ? a ? volume ? parameter ? block ? (VPB). ?
? ? ? File ? System ? Stacks ? :File ? system ? drivers ? create ? two ? different ? types ? of ? device ? objects: ? control ? device ? objects ? (CDO) ? and ? volume ? device ? objects ? (VDO). ?
? ? ? File ? System ? Control ? Device ? Objects ? (CDO) ?
? ? ? File ? System ? Volume ? Device ? Objects ? (VDO) ?
? 3>代碼分析(詳細參考Sfilter) ?
? 1: ? DriverEntry ? () ?
? { ?
? status ? = ? IoRegisterFsRegistrationChange( ? DriverObject, ? SfFsNotification ? ); ?
? } ? ? ? ? ? ? ? ? ? ?
? SfFsNotification( ? IN ? PDEVICE_OBJECT ? DeviceObject, ? ,//原始文件系統 ?
? ? ? ? ? ? ? ? ? IN ? BOOLEAN ? FsActive) ?
? { ? ?
? SfAttachToFileSystemDevice( ? DeviceObject, ? &name ? ); ?
? } ?
? SfAttachToFileSystemDevice( ? ? ? ? ? ? ?
? IN ? PDEVICE_OBJECT ? DeviceObject,//原始文件系統 ?
? ? ? ? ? ? ? IN ? PUNICODE_STRING ? DeviceName) ?
? { ?
? ? ? status ? = ? IoCreateDevice(... ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &newDeviceObject ? ); ?
? ? ? status ? = ? SfAttachDeviceToDeviceStack( ? newDeviceObject, ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject, ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &devExt->AttachedToDeviceObject ? );//原始的保存} ?
? 2 ? 文件類型分為: ? ?
? (((_type) ? == ? FILE_DEVICE_DISK_FILE_SYSTEM) ? || ? \ ? 磁盤文件系統 ?
? ? ? ((_type) ? == ? FILE_DEVICE_CD_ROM_FILE_SYSTEM) ? || ? \CDROM文件系統 ?
? ? ? ((_type) ? == ? FILE_DEVICE_NETWORK_FILE_SYSTEM ? 網絡文件系統 ?
? 3:當在驅動中調用了 ?
? ? ? status ? = ? IoCreateDevice( ? DriverObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //has ? no ? device ? extension ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &nameString, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FILE_DEVICE_DISK_FILE_SYSTEM, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FILE_DEVICE_SECURE_OPEN, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &gSFilterControlDeviceObject ? ); ?
? 那么發向該設備對象的IRP將能在該驅動(DriverObject)中接收到,當建立多個設備對象的時候,可以通過判斷設備對象來進行是哪個發出的。 ? 同時假設建立的其中一個設備和另外的系統的設備ATTACH了,那么發向原來系統設備對象的IRP也就能在這個驅動中接收到。例如在下面的分發例程中就能得到這些IRP。 ?
? for ? (i ? = ? 0; ? i ? <= ? IRP_MJ_MAXIMUM_FUNCTION; ? i++) ?
? DriverObject->MajorFunction ? = ? SfPassThrough; ?
? DriverObject->MajorFunction[IRP_MJ_CREATE] ? = ? SfCreate; ?
? 4:首先文件系統驅動本身往往生成一個控制設備(CDO),這個控制對象用來和外部的應用進行通訊,來配置驅動的。 ?
? 另一種設備是被這個文件系統Mount的Volume。一個FS可能有多個Volume,也可能一個都沒有(解釋一下,如果你有C:,D:,E:,F:四個分區。C:,D:為NTFS,E:,F:為Fat32.那么C:,D:則是Fat的兩個Volume設備對象. ? )文件系統驅動是針對每個Volume來生成一個DeviceObjec(IoCreateDevice)。 ?
? 5:因為IRP是上層應用到下面內核層的,所以只要我們建立的新設備ATTACH到原始的設備上,將位于綁定的文件對象STACK的上邊,這樣上面來的IRP將能首先被我們新建立的設備對象捕獲。但是對于下面原始設備自己發出的請求,只能使用設置CALLBACK的方法了。 ?
? 6:由于你的驅動將要綁定到文件系統驅動的上邊,文件系統除了處理正常的IRP之外,還要處理所謂的FastIo.FastIo是Cache ? Manager調用所引發的一種沒有irp的請求。因為FAST ? IO是用于CACHE的,不和下面的BASE ? FILE ? SYSTEM直接打交道,但是對于上層來說也是文件系統的訪問,所以也要設置。具體就是先分配一個空間, ?
? PFAST_IO_DISPATCH ? fastIoDispatch ? = ? ExAllocatePoolWithTag() ?
? 把FAST ? IO的函數賦給這個結構,fastIoDispatch->FastIoRead ? = ? SfFastIoRead; ?
? 然后DriverObject->FastIoDispatch ? = ? fastIoDispatch; ?
? 7:irp是從設備棧的頂端開始,逐步向下發送。DevVolumue表示我們實際要過濾的Volume設備,我們只要在這個設備棧的頂端再綁定一個設備,那發送給Volume的請求,自然會先發給我們的設備來處理。IoAttachDeviceToDeviceStack(注意源設備未必直接綁定在目標設備上。它應綁定在目標設備的設備棧的頂端。)比如“C:”這個設備,我已經知道符號連接為“C:”,不難得到設備名。得到設備名后,又不難得到設備。這時候我們IoCreateDevice()生成一個Device ? Object,然后調用IoAttachDeviceToDeviceStack綁定,所有發給“C:”的irp,就必然先發送給我們的驅動,我們也可以捕獲所有對文件的操作了! ?
? 8:以上的方法是靜態的,,如果不想處理動態的Volume,你完全可以這樣做。但是我們這里有更高的要求。當你把一個U盤插入usb口,一個“J:”之類的Volume動態誕生的時候,我們依然要捕獲這個事件,并生成一個Device來綁定它。 ?
? 一個新的存儲媒質被系統發現并在文件系統中生成一個Volume的過程稱為Mounting.其過程開始的時候,FS的CDO將得到一個IRP,其Major ? Function ? Code為IRP_MJ_FILE_SYSTEM_CONTROL,Minor ? Function ? Code為IRP_MN_MOUNT。換句話說,如果我們已經生成了一個設備綁定文件系統的CDO,那么我們就可以得到這樣的IRP,在其中知道一個新的Volume正在Mount.這時候我們可以執行上邊所說的操作。 ? 這就是下面代碼的含義: ?
? DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] ? = ? SfFsControl; ?
? NTSTATUS ?
? SfFsControl ? ( ?
? ? ? IN ? PDEVICE_OBJECT ? DeviceObject, ?
? ? ? IN ? PIRP ? Irp ?
? ) ?
? { ?
? switch ? (irpSp->MinorFunction) ? { ?
? ? ? ? ? case ? IRP_MN_MOUNT_VOLUME: ?
? ? ? ? ? ? ? ? ? return ? SfFsControlMountVolume( ? DeviceObject, ? Irp ? ); ?
? ? ? ? ? case ? IRP_MN_LOAD_FILE_SYSTEM: ?
? ? ? ? ? ? ? ? ? return ? SfFsControlLoadFileSystem( ? DeviceObject, ? Irp ? ); ?
? ? ? ? ? case ? IRP_MN_USER_FS_REQUEST: ?
? ? ? ? ? {}??
//對于USB盤等分析如下: ?
? NTSTATUS ?
? SfFsControlMountVolume ? ( ?
? ? ? IN ? PDEVICE_OBJECT ? DeviceObject, ?
? ? ? IN ? PIRP ? Irp ?
? ? ? ) ?
? { ?
? //首先要保存because ? this ? VPB ? may ? be ? changed ? by ? the ? underlying ? file ? system. ?
? storageStackDeviceObject ? = ? irpSp->Parameters.MountVolume.Vpb->RealDevice; ?
? //判斷不是影子設備 ?
? status ? = ? SfIsShadowCopyVolume ? ( ? storageStackDeviceObject, ? &isShadowCopyVolume ? ); ?
? //建立新的FILTER設備對象,準備附加到MOUNT的設備上 ?
? // ? Since ? the ? device ? object ? we ? are ? going ? to ? attach ? to ? has ? not ? yet ? been ?
? // ? created ? (it ? is ? created ? by ? the ? base ? file ? system) ? we ? are ? going ? to ? use ?
? // ? the ? type ? of ? the ? file ? system ? control ? device ? object. ? We ? are ? assuming ?
? // ? that ? the ? file ? system ? control ? device ? object ? will ? have ? the ? same ? type ?
? // ? as ? the ? volume ? device ? objects ? associated ? with ? it. ?
? status ? = ? IoCreateDevice( ? gSFilterDriverObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof( ? SFILTER_DEVICE_EXTENSION ? ), ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NULL, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject->DeviceType, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &newDeviceObject ? ); ?
? #if ? WINVER ? >= ? 0x0501 ?
? ? ? ? ? //設置事件 ?
? ? ? ? ? KeInitializeEvent( ? &waitEvent, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NotificationEvent, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE ? ); ?
? ? ? ? ? IoCopyCurrentIrpStackLocationToNext ? ( ? Irp ? ); ?
? ? ? ? ? //設置完成例程, ?
? ? ? ? ? IoSetCompletionRoutine( ? Irp, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SfFsControlCompletion, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &waitEvent, ? ? ? //context ? parameter ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TRUE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TRUE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TRUE ? ); ?
? ? ? ? ? //把IRP傳送到下面的設備對象中 ?
? ? ? status ? = ? IoCallDriver( ? devExt->NLExtHeader.AttachedToDeviceObject, ? Irp ? ); ?
? ? ? ? ? //等待完成MOUNT的工作 ?
? ? ? status ? = ? KeWaitForSingleObject( ? &waitEvent, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Executive, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? KernelMode, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NULL ? ); ?
? ? ? ? ? //執行把我們的新設備ATTACH到MOUNT的設備上的功能 ?
? status ? = ? SfFsControlMountVolumeComplete( ? DeviceObject, ? ? ? ? ? Irp,newDeviceObject ? ); ?
? #else ?
? //非WINXP的方式,通過WorkItem來實現 ?
? ExInitializeWorkItem ? () ?
? status ? = ? IoCallDriver( ? devExt->NLExtHeader.AttachedToDeviceObject, ? Irp ? ); ?
? #endif ?
? } ?
? ?
? //完成后,這個函數中做了怎么的處理呢? ?
? NTSTATUS ?
? SfFsControlMountVolumeComplete ? ( ?
? ? ? IN ? PDEVICE_OBJECT ? DeviceObject, ?
? ? ? IN ? PIRP ? Irp, ?
? ? ? IN ? PDEVICE_OBJECT ? NewDeviceObject ?
? ) ?
? { ?
? //首先從newDevExt中找到保存的原來MOUNT對象的VPB,因為在MOUNT的過程中可能被改變。 ?
? newDevExt ? = ? NewDeviceObject->DeviceExtension; ?
? vpb ? = ? newDevExt->NLExtHeader.StorageStackDeviceObject->Vpb; ?
? //如果MOUIN成功,就執行ATTACH ?
? status ? = ? SfAttachToMountedDevice( ? vpb->DeviceObject,NewDeviceObject ? ); ?
? //然后得到新MOUNT設備的DOS名稱LGetDosDeviceName( ? NewDeviceObject,&newDevExt->NLExtHeader ? ); ?
? } ?
? 為什么采用上面的方法呢。就是當發現例如USB插入的時間的時候,這個卷(Volume)還可能沒有被下面的BASE ? FILE ? SYSTEM ? 進行MOUNT而成為一個設備,所以首先要設置一個EVENT事件,然后IoSetCompletionRoutine,把EVENT傳入,然后調用把IRP下發到下面的 ? IoCallDriver,這樣當下面的BASE ? FILE ? SYSTEM對該Volume ? ? ? ? MOUNT成功完成后,將自然調用我們前面設置的SfFsControlCompletion()函數,這樣在該完成函數中僅僅把EVENT ? 信號化,這樣后面的KeWaitForSingleObject就能知道EVENT已經信號狀態了,就知道已經完成了MOUNT的工作,這樣就能調用后面的SfFsControlMountVolumeComplete()函數,在該函數中完成具體的ATTACH工作。 ?
? 9:關于IRP下傳的問題的討論 ?
? 如果不設置完成例程(IoSetCompletionRoutine),直接把IRP下發到設備STACK下面,那么僅僅就是兩步: ?
? ? ? IoSkipCurrentIrpStackLocation( ? Irp ? ); ?
? ? ? IoCallDriver( ? (oDeviceObject, ? Irp ? ); ?
? The ? IoSkipCurrentIrpStackLocation ? macro ? modifies ? the ? system's ? IO_STACK_LOCATION ? array ? pointer, ? so ? that ? when ? the ? current ? driver ? calls ? the ? next-lower ? driver, ? that ? driver ? receives ? the ? same ? IO_STACK_LOCATION ? structure ? that ? the ? current ? driver ? received. ?
? When ? sending ? an ? IRP ? to ? the ? next-lower ? driver, ? your ? driver ? can ? call ? IoSkipCurrentIrpStackLocation ? if ? you ? do ? not ? intend ? to ? provide ? an ? IoCompletion ? routine ? (the ? address ? of ? which ? is ? stored ? in ? the ? driver's ? IO_STACK_LOCATION ? structure). ? If ? you ? call ? IoSkipCurrentIrpStackLocation ? before ? calling ? IoCallDriver, ? the ? next-lower ? driver ? receives ? the ? same ? IO_STACK_LOCATION ? that ? your ? driver ? received. ? ?
? 如果要設置完成例程,那么就需要三步: ?
? IoCopyCurrentIrpStackLocationToNext ? ( ? Irp ? ); ?
? IoSetCompletionRoutine( ? Irp, ? SfFsControlCompletion, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &waitEvent, ? ? ? //context ? parameter ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TRUE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TRUE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TRUE ? ); ?
? IoCallDriver( ? devExt->NLExtHeader.AttachedToDeviceObject, ? Irp ? ); ?
? The ? IoCopyCurrentIrpStackLocationToNext ? routine ? copies ? the ? IRP ? stack ? parameters ? from ? the ? current ? I/O ? stack ? location ? to ? the ? stack ? location ? of ? the ? next-lower ? driver ? and ? allows ? the ? current ? driver ? to ? set ? an ? I/O ? completion ? routine. ?
? A ? driver ? calls ? IoCopyCurrentIrpStackLocationToNext ? to ? copy ? the ? IRP ? parameters ? from ? its ? stack ? location ? to ? the ? next-lower ? driver’s ? stack ? location. ? ?
? After ? calling ? this ? routine, ? a ? driver ? typically ? sets ? an ? I/O ? completion ? routine ? with ? IoSetCompletionRoutine ? before ? passing ? the ? IRP ? to ? the ? next-lower ? driver ? with ? IoCallDriver. ? Drivers ? that ? pass ? on ? their ? IRP ? parameters ? but ? do ? not ? set ? an ? I/O ? completion ? routine ? should ? call ? IoSkipCurrentIrpStackLocation ? instead ? of ? this ? routine. ?
? 10 ? :發現設備加載和枚舉系統的設備 ?
? 如果想知道系統中有那些文件系統,還有就是應該在什么時候綁定它們的控制設備。 ? 將使用IoRegisterFsRegistrationChange(),使用這個函數函數調用注冊一個回調函數。當系統中有任何文件系統被激活或者是被注銷的時候,注冊過的回調函數就會被調用。 ?
? status ? = ? IoRegisterFsRegistrationChange( ? DriverObject, ? SfFsNotification ? ); ?
? //在下面的函數中將執行具體的真正的操作。 ?
? VOID ? SfFsNotification ? ( ?
? ? ? IN ? PDEVICE_OBJECT ? DeviceObject, ?
? ? ? IN ? BOOLEAN ? FsActive ?
? ) ?
? { ?
? ? ? if ? (FsActive) ?
? ? ? ? ? SfAttachToFileSystemDevice( ? DeviceObject, ? devName ? ); ?
? ? ? else ?
? ? ? ? ? SfDetachFromFileSystemDevice( ? DeviceObject ? ); ?
? } ?
? NTSTATUS ?
? SfAttachToFileSystemDevice ? ( ?
? ? ? IN ? PDEVICE_OBJECT ? DeviceObject, ?
? ? ? IN ? PNAME_CONTROL ? DeviceName ?
? ? ? ) ?
? { ?
? //看是否是三種設備文件系統的CDO的設備類型有下邊的幾種可能 ? DISK ? CDROM ? NETWORK
if ? (!IS_DESIRED_DEVICE_TYPE(DeviceObject->DeviceType) ? ?
? ? ? return ? STATUS_SUCCESS; ?
? /*下一個問題是我打算跳過文件系統識別器。文件系統識別器是文件系統驅動的一個很小的替身。為了避免沒有使用到的文件系統驅動占據內核內存,windows系統不加載這些大驅動,而代替以該文件系統驅動對應的文件系統識別器。當新的物理存儲媒介進入系統,io管理器會依次的嘗試各種文件系統對它進行“識別”。識別成功,立刻加載真正的文件系統驅動,對應的文件系統識別器則被卸載掉。對我們來說,文件系統識別器的控制設備看起來就像一個文件系統控制設備。但我們不打算綁定它。 ? ?
? 分辨的方法是通過驅動的名字。凡是文件系統識別器的驅動對象的名字(注意是DriverObject而不是DeviceObject!)都為“\FileSystem\Fs_Rec”. ?
? */ ?
? ?
? if ? (RtlCompareUnicodeString( ? &fsName->Name,&fsrecName, ? TRUE ? ) ? == ? 0) ?
? ? ? ; ?
? //建立新的設備 ?
? ? ? status ? = ? IoCreateDevice( ? gSFilterDriverObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof( ? SFILTER_DEVICE_EXTENSION ? ), ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NULL, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject->DeviceType, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &newDeviceObject ? ); ?
? 生成設備后,為了讓系統看起來,你的設備和原來的設備沒什么區別,你必須設置一些該設備的標志位與你所綁定的設備相同。 ?
? ? ? if ? ( ? FlagOn( ? DeviceObject->Flags, ? DO_BUFFERED_IO ? )) ?
? ? ? ? { ?
? ?
? ? ? ? ? SetFlag( ? newDeviceObject->Flags, ? DO_BUFFERED_IO ? ); ?
? } ?
? ?
? //進行ATTACH的工作 ?
? ? ? status ? = ? SfAttachDeviceToDeviceStack( ? newDeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &devExt->NLExtHeader.AttachedToDeviceObject ? ); ?
? ?
? 同時在WINXP的系統下,枚舉出所有的設備,當發現沒有ATTACH的時候,就進行ATTACH ?
? #if ? WINVER ? >= ? 0x0501 ?
? status ? = ? SfEnumerateFileSystemVolumes( ? DeviceObject ? ); ?
? #endif ?
? ?
? //枚舉設備的函數也是,枚舉出各個設備 ?
? SfEnumerateFileSystemVolumes() ?
? { ?
? EnumerateDeviceObjectList)( ?
? ? ? ? ? ? ? ? ? ? ? ? ? FSDeviceObject->DriverObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? devList, ?
? ? ? ? ? ? ? ? ? ? ? ? ? (numDevices ? * ? sizeof(PDEVICE_OBJECT)), ?
? ? ? ? ? ? ? ? ? ? ? ? ? &numDevices); ? ?
? for ? (i=0; ? i ? < ? numDevices; ? i++) ? ?
? { ?
? ? ? if ? (SfIsAttachedToDevice( ? devList, ? NULL ? )) ? ?
? ? ? ? ? ? ? ? ? ? ? leave; ?
? ? ? status ? = ? IoCreateDevice( ? gSFilterDriverObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof( ? SFILTER_DEVICE_EXTENSION ? ), ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NULL, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? devList->DeviceType, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &newDeviceObject ? ); ?
? status ? = ? SfAttachToMountedDevice( ? devList, ? newDeviceObject ? ); ?
? } ?
? 11.IRP ? 的路徑 ?
? status ? = ? IoCreateDevice( ? gSFilterDriverObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof( ? SFILTER_DEVICE_EXTENSION ? ), ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NULL, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject->DeviceType, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &newDeviceObject ? ); ? ?
? PSFILTER_DEVICE_EXTENSION ? devExt ? = ? newDeviceObject->DeviceExtension; ?
? //返回的設備對象保存在 ? 新建立的設備對象的擴展數據中 ?
? status ? = ? SfAttachDeviceToDeviceStack( ? newDeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &devExt->NLExtHeader.AttachedToDeviceObject ? ); ?
? 因為我們建立的新設備已經綁定到文件系統控制設備上去了。windows發給文件系統的請求發給我們的驅動。如果不能做恰當的處理,我們的系統的就會崩潰。因為建立新設備的時候,設備對象結構擴展是NONEPAGE,所以能保存在整個期間。 ?
? 因為我們在驅動中IoCreateDevice()并ATTACH了到了目標設備對象的TOP,所以原來那些到原始設備的IRP都會到達我們的驅動中,并且我們設置了處理的例程,這樣會到達我們的函數。但是在我們的設備中的函數中,怎么得到原來被ATTACH的設備對象呢,就是我們原來保存在設備對象中的擴展。就是下面的方法: ?
? NTSTATUS ?
? SfCreate ? ( ?
? ? ? IN ? PDEVICE_OBJECT ? DeviceObject, ?
? ? ? IN ? PIRP ? Irp ?
? ) ?
? { ?
? return ? IoCallDriver( ?
? ((PSFILTER_DEVICE_EXTENSION) ? DeviceObject->DeviceExtension)->NLExtHeader.AttachedToDeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Irp ? ); ?
? }???
?
注釋:幾個MAX—FUNCTION的區別 ?
? IRP_MN_MOUNT_VOLUME ?
? IRP_MN_LOAD_FILESYS ?
? 這個功能碼我只做一點點解釋:當一個文件識別器(見上文)決定加載真正的文件系統的時候,會產生一個這樣的irp。 ?
? 12: ? 文件系統和設備、卷的關系和區別 ?
? 我們已經在notify函數中綁定了文件系統驅動的控 ? ?
? // ? 制對象。當文件系統得到實際的介質的時候,會生成新的設備對象, ? ?
? // ? 這種設備稱為卷(Volume),而這種設備是在file_sys中的mount中生 ? ?
? // ? 成的,而且也是unmount中注銷掉的。我們捕獲這樣的操作之后,就必 ? ?
? // ? 須生成我們的設備對象,綁定在這樣的“卷”上,才能綁定對這個卷 ? ?
? // ? 上的文件的操作。 ? ?
? VPB是Volume ? parameter ? block.一個數據結構.它的主要作用是把實際存儲媒介設備對象和文件系統上的卷設備對象聯系起來. ?
? 為什么我們在IoRegisterFsRegistrationChange()中進行一些處理,還要對VOLUME進行處理呢,兩者是不相同的事情,前者是當文件系統被注冊的時候發生,或者是當物理存儲設備被文件系統MOUNT成為VOLUME的時候。 ?
? 13:IRQL和跨越IRQL的限制 ?
? 實際的應用應該是這樣的:所有的dispatch ? functions由于是上層發來的irp而導致的調用,所以應該都是Passive ? Level,在其中你可以調用絕大多數系統調用.而如網卡的OnReceive,硬盤讀寫完畢,返回而導致的完成函數,都有可能在Dispatch級.注意都是有可能,而不是絕對是.但是一旦有可能,我們就應該按就是考慮. ? ?
? // ? Since ? the ? device ? object ? we ? are ? going ? to ? attach ? to ? has ? not ? yet ? been ?
? // ? created ? (it ? is ? created ? by ? the ? base ? file ? system) ? we ? are ? going ? to ? use ?
? // ? the ? type ? of ? the ? file ? system ? control ? device ? object. ? We ? are ? assuming ?
? // ? that ? the ? file ? system ? control ? device ? object ? will ? have ? the ? same ? type ?
? // ? as ? the ? volume ? device ? objects ? associated ? with ? it. ?
? 上面的理解是,當上層發出MOUNT的IRP請求的時候,其實我們將要ATTACH的設備對象還沒有建立,現在得到的是其對應的控制設備對象CDO(control ? device ? object),這個時候我們假設CDO和volume ? device ? objects具有相同的類型。 ?
? 所以我們的方法就是設置一個完成例程,當完成MOUNT的時候,該例程將被調用,在這里完成ATTACH的工作。決定在完成函數中調用 ? IoAttachDeviceToDeviceStack來綁定Volume. ?
? 但是我們的完成例程是運行在DISPATCH_LEVEL上的,而IoAttachDeviceToDeviceStack ? must ? be ? running ? at ? IRQL ? <= ? DISPATCH_LEVEL. ? 實際上前邊說過有IoAttachDeviceToDeviceStackSafe,這個調用可以在Dispatch ? level進行.無奈這個調用僅僅出現在Xp以上的系統中. ?
? 超越中斷級別的限制有幾種方法.第一種是自己生成一個系統線程來完成此事.系統線程將保證在Passive ? Level中運行.另一種方法就是把自己的任務插入Windows工作者線程,這會使你的任務遲早得到執行.如果你的任務比較小,可以實行第二種方法.對系統來說比較省事,對程序員來說則反正都是麻煩. ?
? 14 ? 地址的有效性 ?
? 假設我們現在處理IRP_MJ_READ對應的SFREAD()函數。 ? ?
? 1:IRP下有一個FileObject指針.這個東西指向一個文件對象.你可以得到文件對象的名字,這個名字是沒有盤符的文件全路徑.這可以通過FILEMON的方法。 ?
? 2:盤符如何獲得?因為已經知道了Volume,前邊已經說過盤符不過是Volume的符號連接名,所以也不是很大的問題。 ?
? 3:讀文件的偏移量:irpsp->Parameters.Read.ByteOffset; ? ?
? 4:具體的讀的數據在那里呢? ?
? Depending ? on ? whether ? the ? underlying ? device ? driver ? sets ? up ? the ? target ? device ? object's ? Flags ? with ? DO_BUFFERED_IO ? or ? with ? DO_DIRECT_IO, ? data ? is ? transferred ? into ? one ? of ? the ? following: ? ?
? ·The ? buffer ? at ? Irp->AssociatedIrp.SystemBuffer ? if ? the ? driver ? uses ? buffered ? I/O ? ?
? ·The ? buffer ? described ? by ? the ? MDL ? at ? Irp->MdlAddress ? if ? the ? underlying ? device ? driver ? uses ? direct ? I/O ? (DMA ? or ? PIO) ? ?
? Volume設備出現DO_BUFFERED的情況幾乎沒有,所以DO_DIRECT_IO表示數據應該返回到 ?
? Irp->MdlAddress所指向的MDL所指向的內存.在無標記的情況下,表明數據讀好,請返回到 ? ?
? Irp->UseBuffer中即可.Irp->UseBuffer是一個只在當前線程上下文才有效的地址.如果在前面設置的完成例程,和原來的線程不是在一個上下文中的,所以在完成例程序中得到的該地址是不正確的。要么只能從Irp->MdlAddress中得到數據,如果想要回到當前線程上下文,那么就使用前面的方法,通過等待EVENT的方法。 ?
? 15 ? Mounting ? a ? Volume ?
? 卷的MOUNT的過程最典型的是當打開一個文件或者邏輯卷的請求時候被觸發。The ? volume ? mount ? process ? is ? typically ? triggered ? by ? a ? request ? to ? open ? a ? file ? on ? a ? logical ? volume ? (that ? is, ? a ? partition ? or ? dynamic ? volume) ? as ? follows: ? ?
? 一個用戶應用調用CREATEFILE來打開一個文件,或者內核模式的驅動程序調用ZwCreateFile。 ?
? 1.A ? user ? application ? calls ? CreateFile ? to ? open ? a ? file. ? Or ? a ? kernel-mode ? driver ? calls ? ZwCreateFile ? or ? IoCreateFileSpecifyDeviceObjectHint. ? ?
? I/O管理器決定哪個邏輯卷是請求的目標,并且檢查設備對象,查看是否它已經被MOUNT。如果VPB_MOUNTED表示被設置,則證明卷被文件系統加載了。 ?
? 2.The ? I/O ? Manager ? determines ? which ? logical ? volume ? is ? the ? target ? of ? the ? request ? and ? checks ? its ? device ? object ? to ? see ? whether ? it ? is ? mounted. ? If ? the ? VPB_MOUNTED ? flag ? is ? set, ? the ? volume ? has ? been ? mounted ? by ? a ? file ? system. ? ?
? 如果卷自從系統啟動后沒有被文件系統MOUNT,I/O管理器發送一個卷MOUNT的請求(IRP_MJ_FILE_SYSTEM_CONTROL, ? IRP_MN_MOUNT_VOLUME)到擁有該卷的文件系統。 ?
? 不是所有的內置文件系統都是必須加載的,即使系統啟動或是正常的,如果內置文件系統沒有被加載,那么I/O管理器發送卷MOUNT的請求到文件系統發現器(FsRec)上,它會為文件系統檢查卷的boot ? sector ?
? 3.If ? the ? volume ? has ? not ? been ? mounted ? by ? a ? file ? system ? since ? system ? boot ? (that ? is, ? the ? VPB_MOUNTED ? flag ? is ? not ? set), ? the ? I/O ? Manager ? sends ? a ? volume ? mount ? (IRP_MJ_FILE_SYSTEM_CONTROL, ? IRP_MN_MOUNT_VOLUME) ? request ? to ? each ? file ? system ? that ? might ? claim ? the ? volume. ? ?
? Not ? all ? built-in ? file ? systems ? are ? necessarily ? loaded??