Posted on 2010-02-18 14:57
S.l.e!ep.¢% 閱讀(1335)
評論(0) 編輯 收藏 引用 所屬分類:
Windows WDM
1> ? IFS ? 流程圖 ?
? 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)用注冊這個(gè)回調(diào)函數(shù)。 ?
? f.編寫默認(rèn)的dispatch ? functions. ? ?
? g.處理IRP_MJ_FILE_SYSTEM_CONTROL,在其中監(jiān)控Volumne的Mount和Dismount. ? ?
? h.下一步自然是綁定Volumne了. ?
? (全路徑是在 ? FileObject->FileName.Buffer中得到的.) ?
? 2>一些必要知識 ?
? a.幾個(gè)概念的區(qū)別 ?
? 1.多數(shù)的storage ? drivers ? 是PNP管理的,存在一個(gè)設(shè)備節(jié)點(diǎn)(DEVNODE),(It ? is ? important ? to ? note ? that ? file ? systems ? and ? file ? system ? filter ? drivers ? are ? not ? PnP ? device ? drivers;),每個(gè)設(shè)備節(jié)點(diǎn)上維護(hù)一個(gè)Storage ? Device ? Stacks,這個(gè)就是因?yàn)槊總€(gè)存儲設(shè)備,例如磁盤設(shè)備,可能包含一個(gè)或者多個(gè)邏輯卷(分區(qū)或者動(dòng)態(tài)卷),這些卷就是通過這個(gè)Storage ? Device ? Stack來保存的。該設(shè)備點(diǎn)的信息就是functional ? device ? object ? (FDO)。剩下的就是physical ? device ? objects ? (PDO)代表各個(gè)分區(qū)。 ?
? ? ? 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.文件系統(tǒng)和卷的區(qū)別 ?
? ? ? 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>代碼分析(詳細(xì)參考Sfilter) ?
? 1: ? DriverEntry ? () ?
? { ?
? status ? = ? IoRegisterFsRegistrationChange( ? DriverObject, ? SfFsNotification ? ); ?
? } ? ? ? ? ? ? ? ? ? ?
? SfFsNotification( ? IN ? PDEVICE_OBJECT ? DeviceObject, ? ,//原始文件系統(tǒng) ?
? ? ? ? ? ? ? ? ? IN ? BOOLEAN ? FsActive) ?
? { ? ?
? SfAttachToFileSystemDevice( ? DeviceObject, ? &name ? ); ?
? } ?
? SfAttachToFileSystemDevice( ? ? ? ? ? ? ?
? IN ? PDEVICE_OBJECT ? DeviceObject,//原始文件系統(tǒng) ?
? ? ? ? ? ? ? IN ? PUNICODE_STRING ? DeviceName) ?
? { ?
? ? ? status ? = ? IoCreateDevice(... ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &newDeviceObject ? ); ?
? ? ? status ? = ? SfAttachDeviceToDeviceStack( ? newDeviceObject, ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject, ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &devExt->AttachedToDeviceObject ? );//原始的保存} ?
? 2 ? 文件類型分為: ? ?
? (((_type) ? == ? FILE_DEVICE_DISK_FILE_SYSTEM) ? || ? \ ? 磁盤文件系統(tǒng) ?
? ? ? ((_type) ? == ? FILE_DEVICE_CD_ROM_FILE_SYSTEM) ? || ? \CDROM文件系統(tǒng) ?
? ? ? ((_type) ? == ? FILE_DEVICE_NETWORK_FILE_SYSTEM ? 網(wǎng)絡(luò)文件系統(tǒng) ?
? 3:當(dāng)在驅(qū)動(dòng)中調(diào)用了 ?
? ? ? status ? = ? IoCreateDevice( ? DriverObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //has ? no ? device ? extension ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &nameString, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FILE_DEVICE_DISK_FILE_SYSTEM, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FILE_DEVICE_SECURE_OPEN, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &gSFilterControlDeviceObject ? ); ?
? 那么發(fā)向該設(shè)備對象的IRP將能在該驅(qū)動(dòng)(DriverObject)中接收到,當(dāng)建立多個(gè)設(shè)備對象的時(shí)候,可以通過判斷設(shè)備對象來進(jìn)行是哪個(gè)發(fā)出的。 ? 同時(shí)假設(shè)建立的其中一個(gè)設(shè)備和另外的系統(tǒng)的設(shè)備ATTACH了,那么發(fā)向原來系統(tǒng)設(shè)備對象的IRP也就能在這個(gè)驅(qū)動(dòng)中接收到。例如在下面的分發(fā)例程中就能得到這些IRP。 ?
? for ? (i ? = ? 0; ? i ? <= ? IRP_MJ_MAXIMUM_FUNCTION; ? i++) ?
? DriverObject->MajorFunction ? = ? SfPassThrough; ?
? DriverObject->MajorFunction[IRP_MJ_CREATE] ? = ? SfCreate; ?
? 4:首先文件系統(tǒng)驅(qū)動(dòng)本身往往生成一個(gè)控制設(shè)備(CDO),這個(gè)控制對象用來和外部的應(yīng)用進(jìn)行通訊,來配置驅(qū)動(dòng)的。 ?
? 另一種設(shè)備是被這個(gè)文件系統(tǒng)Mount的Volume。一個(gè)FS可能有多個(gè)Volume,也可能一個(gè)都沒有(解釋一下,如果你有C:,D:,E:,F:四個(gè)分區(qū)。C:,D:為NTFS,E:,F:為Fat32.那么C:,D:則是Fat的兩個(gè)Volume設(shè)備對象. ? )文件系統(tǒng)驅(qū)動(dòng)是針對每個(gè)Volume來生成一個(gè)DeviceObjec(IoCreateDevice)。 ?
? 5:因?yàn)镮RP是上層應(yīng)用到下面內(nèi)核層的,所以只要我們建立的新設(shè)備ATTACH到原始的設(shè)備上,將位于綁定的文件對象STACK的上邊,這樣上面來的IRP將能首先被我們新建立的設(shè)備對象捕獲。但是對于下面原始設(shè)備自己發(fā)出的請求,只能使用設(shè)置CALLBACK的方法了。 ?
? 6:由于你的驅(qū)動(dòng)將要綁定到文件系統(tǒng)驅(qū)動(dòng)的上邊,文件系統(tǒng)除了處理正常的IRP之外,還要處理所謂的FastIo.FastIo是Cache ? Manager調(diào)用所引發(fā)的一種沒有irp的請求。因?yàn)镕AST ? IO是用于CACHE的,不和下面的BASE ? FILE ? SYSTEM直接打交道,但是對于上層來說也是文件系統(tǒng)的訪問,所以也要設(shè)置。具體就是先分配一個(gè)空間, ?
? PFAST_IO_DISPATCH ? fastIoDispatch ? = ? ExAllocatePoolWithTag() ?
? 把FAST ? IO的函數(shù)賦給這個(gè)結(jié)構(gòu),fastIoDispatch->FastIoRead ? = ? SfFastIoRead; ?
? 然后DriverObject->FastIoDispatch ? = ? fastIoDispatch; ?
? 7:irp是從設(shè)備棧的頂端開始,逐步向下發(fā)送。DevVolumue表示我們實(shí)際要過濾的Volume設(shè)備,我們只要在這個(gè)設(shè)備棧的頂端再綁定一個(gè)設(shè)備,那發(fā)送給Volume的請求,自然會先發(fā)給我們的設(shè)備來處理。IoAttachDeviceToDeviceStack(注意源設(shè)備未必直接綁定在目標(biāo)設(shè)備上。它應(yīng)綁定在目標(biāo)設(shè)備的設(shè)備棧的頂端。)比如“C:”這個(gè)設(shè)備,我已經(jīng)知道符號連接為“C:”,不難得到設(shè)備名。得到設(shè)備名后,又不難得到設(shè)備。這時(shí)候我們IoCreateDevice()生成一個(gè)Device ? Object,然后調(diào)用IoAttachDeviceToDeviceStack綁定,所有發(fā)給“C:”的irp,就必然先發(fā)送給我們的驅(qū)動(dòng),我們也可以捕獲所有對文件的操作了! ?
? 8:以上的方法是靜態(tài)的,,如果不想處理動(dòng)態(tài)的Volume,你完全可以這樣做。但是我們這里有更高的要求。當(dāng)你把一個(gè)U盤插入usb口,一個(gè)“J:”之類的Volume動(dòng)態(tài)誕生的時(shí)候,我們依然要捕獲這個(gè)事件,并生成一個(gè)Device來綁定它。 ?
? 一個(gè)新的存儲媒質(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。換句話說,如果我們已經(jīng)生成了一個(gè)設(shè)備綁定文件系統(tǒng)的CDO,那么我們就可以得到這樣的IRP,在其中知道一個(gè)新的Volume正在Mount.這時(shí)候我們可以執(zhí)行上邊所說的操作。 ? 這就是下面代碼的含義: ?
? 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; ?
? //判斷不是影子設(shè)備 ?
? status ? = ? SfIsShadowCopyVolume ? ( ? storageStackDeviceObject, ? &isShadowCopyVolume ? ); ?
? //建立新的FILTER設(shè)備對象,準(zhǔn)備附加到MOUNT的設(shè)備上 ?
? // ? 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 ?
? ? ? ? ? //設(shè)置事件 ?
? ? ? ? ? KeInitializeEvent( ? &waitEvent, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NotificationEvent, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE ? ); ?
? ? ? ? ? IoCopyCurrentIrpStackLocationToNext ? ( ? Irp ? ); ?
? ? ? ? ? //設(shè)置完成例程, ?
? ? ? ? ? IoSetCompletionRoutine( ? Irp, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SfFsControlCompletion, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &waitEvent, ? ? ? //context ? parameter ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TRUE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TRUE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TRUE ? ); ?
? ? ? ? ? //把IRP傳送到下面的設(shè)備對象中 ?
? ? ? status ? = ? IoCallDriver( ? devExt->NLExtHeader.AttachedToDeviceObject, ? Irp ? ); ?
? ? ? ? ? //等待完成MOUNT的工作 ?
? ? ? status ? = ? KeWaitForSingleObject( ? &waitEvent, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Executive, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? KernelMode, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NULL ? ); ?
? ? ? ? ? //執(zhí)行把我們的新設(shè)備ATTACH到MOUNT的設(shè)備上的功能 ?
? status ? = ? SfFsControlMountVolumeComplete( ? DeviceObject, ? ? ? ? ? Irp,newDeviceObject ? ); ?
? #else ?
? //非WINXP的方式,通過WorkItem來實(shí)現(xiàn) ?
? ExInitializeWorkItem ? () ?
? status ? = ? IoCallDriver( ? devExt->NLExtHeader.AttachedToDeviceObject, ? Irp ? ); ?
? #endif ?
? } ?
? ?
? //完成后,這個(gè)函數(shù)中做了怎么的處理呢? ?
? NTSTATUS ?
? SfFsControlMountVolumeComplete ? ( ?
? ? ? IN ? PDEVICE_OBJECT ? DeviceObject, ?
? ? ? IN ? PIRP ? Irp, ?
? ? ? IN ? PDEVICE_OBJECT ? NewDeviceObject ?
? ) ?
? { ?
? //首先從newDevExt中找到保存的原來MOUNT對象的VPB,因?yàn)樵贛OUNT的過程中可能被改變。 ?
? newDevExt ? = ? NewDeviceObject->DeviceExtension; ?
? vpb ? = ? newDevExt->NLExtHeader.StorageStackDeviceObject->Vpb; ?
? //如果MOUIN成功,就執(zhí)行ATTACH ?
? status ? = ? SfAttachToMountedDevice( ? vpb->DeviceObject,NewDeviceObject ? ); ?
? //然后得到新MOUNT設(shè)備的DOS名稱LGetDosDeviceName( ? NewDeviceObject,&newDevExt->NLExtHeader ? ); ?
? } ?
? 為什么采用上面的方法呢。就是當(dāng)發(fā)現(xiàn)例如USB插入的時(shí)間的時(shí)候,這個(gè)卷(Volume)還可能沒有被下面的BASE ? FILE ? SYSTEM ? 進(jìn)行MOUNT而成為一個(gè)設(shè)備,所以首先要設(shè)置一個(gè)EVENT事件,然后IoSetCompletionRoutine,把EVENT傳入,然后調(diào)用把IRP下發(fā)到下面的 ? IoCallDriver,這樣當(dāng)下面的BASE ? FILE ? SYSTEM對該Volume ? ? ? ? MOUNT成功完成后,將自然調(diào)用我們前面設(shè)置的SfFsControlCompletion()函數(shù),這樣在該完成函數(shù)中僅僅把EVENT ? 信號化,這樣后面的KeWaitForSingleObject就能知道EVENT已經(jīng)信號狀態(tài)了,就知道已經(jīng)完成了MOUNT的工作,這樣就能調(diào)用后面的SfFsControlMountVolumeComplete()函數(shù),在該函數(shù)中完成具體的ATTACH工作。 ?
? 9:關(guān)于IRP下傳的問題的討論 ?
? 如果不設(shè)置完成例程(IoSetCompletionRoutine),直接把IRP下發(fā)到設(shè)備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. ? ?
? 如果要設(shè)置完成例程,那么就需要三步: ?
? 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 ? :發(fā)現(xiàn)設(shè)備加載和枚舉系統(tǒng)的設(shè)備 ?
? 如果想知道系統(tǒng)中有那些文件系統(tǒng),還有就是應(yīng)該在什么時(shí)候綁定它們的控制設(shè)備。 ? 將使用IoRegisterFsRegistrationChange(),使用這個(gè)函數(shù)函數(shù)調(diào)用注冊一個(gè)回調(diào)函數(shù)。當(dāng)系統(tǒng)中有任何文件系統(tǒng)被激活或者是被注銷的時(shí)候,注冊過的回調(diào)函數(shù)就會被調(diào)用。 ?
? status ? = ? IoRegisterFsRegistrationChange( ? DriverObject, ? SfFsNotification ? ); ?
? //在下面的函數(shù)中將執(zhí)行具體的真正的操作。 ?
? 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 ?
? ? ? ) ?
? { ?
? //看是否是三種設(shè)備文件系統(tǒng)的CDO的設(shè)備類型有下邊的幾種可能 ? DISK ? CDROM ? NETWORK
if ? (!IS_DESIRED_DEVICE_TYPE(DeviceObject->DeviceType) ? ?
? ? ? return ? STATUS_SUCCESS; ?
? /*下一個(gè)問題是我打算跳過文件系統(tǒng)識別器。文件系統(tǒng)識別器是文件系統(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)對應(yīng)的文件系統(tǒng)識別器。當(dāng)新的物理存儲媒介進(jìn)入系統(tǒng),io管理器會依次的嘗試各種文件系統(tǒng)對它進(jìn)行“識別”。識別成功,立刻加載真正的文件系統(tǒng)驅(qū)動(dòng),對應(yīng)的文件系統(tǒng)識別器則被卸載掉。對我們來說,文件系統(tǒng)識別器的控制設(shè)備看起來就像一個(gè)文件系統(tǒng)控制設(shè)備。但我們不打算綁定它。 ? ?
? 分辨的方法是通過驅(qū)動(dòng)的名字。凡是文件系統(tǒng)識別器的驅(qū)動(dòng)對象的名字(注意是DriverObject而不是DeviceObject!)都為“\FileSystem\Fs_Rec”. ?
? */ ?
? ?
? if ? (RtlCompareUnicodeString( ? &fsName->Name,&fsrecName, ? TRUE ? ) ? == ? 0) ?
? ? ? ; ?
? //建立新的設(shè)備 ?
? ? ? status ? = ? IoCreateDevice( ? gSFilterDriverObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof( ? SFILTER_DEVICE_EXTENSION ? ), ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NULL, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject->DeviceType, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FALSE, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &newDeviceObject ? ); ?
? 生成設(shè)備后,為了讓系統(tǒng)看起來,你的設(shè)備和原來的設(shè)備沒什么區(qū)別,你必須設(shè)置一些該設(shè)備的標(biāo)志位與你所綁定的設(shè)備相同。 ?
? ? ? if ? ( ? FlagOn( ? DeviceObject->Flags, ? DO_BUFFERED_IO ? )) ?
? ? ? ? { ?
? ?
? ? ? ? ? SetFlag( ? newDeviceObject->Flags, ? DO_BUFFERED_IO ? ); ?
? } ?
? ?
? //進(jìn)行ATTACH的工作 ?
? ? ? status ? = ? SfAttachDeviceToDeviceStack( ? newDeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &devExt->NLExtHeader.AttachedToDeviceObject ? ); ?
? ?
? 同時(shí)在WINXP的系統(tǒng)下,枚舉出所有的設(shè)備,當(dāng)發(fā)現(xiàn)沒有ATTACH的時(shí)候,就進(jìn)行ATTACH ?
? #if ? WINVER ? >= ? 0x0501 ?
? status ? = ? SfEnumerateFileSystemVolumes( ? DeviceObject ? ); ?
? #endif ?
? ?
? //枚舉設(shè)備的函數(shù)也是,枚舉出各個(gè)設(shè)備 ?
? 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; ?
? //返回的設(shè)備對象保存在 ? 新建立的設(shè)備對象的擴(kuò)展數(shù)據(jù)中 ?
? status ? = ? SfAttachDeviceToDeviceStack( ? newDeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &devExt->NLExtHeader.AttachedToDeviceObject ? ); ?
? 因?yàn)槲覀兘⒌男略O(shè)備已經(jīng)綁定到文件系統(tǒng)控制設(shè)備上去了。windows發(fā)給文件系統(tǒng)的請求發(fā)給我們的驅(qū)動(dòng)。如果不能做恰當(dāng)?shù)奶幚恚覀兊南到y(tǒng)的就會崩潰。因?yàn)榻⑿略O(shè)備的時(shí)候,設(shè)備對象結(jié)構(gòu)擴(kuò)展是NONEPAGE,所以能保存在整個(gè)期間。 ?
? 因?yàn)槲覀冊隍?qū)動(dòng)中IoCreateDevice()并ATTACH了到了目標(biāo)設(shè)備對象的TOP,所以原來那些到原始設(shè)備的IRP都會到達(dá)我們的驅(qū)動(dòng)中,并且我們設(shè)置了處理的例程,這樣會到達(dá)我們的函數(shù)。但是在我們的設(shè)備中的函數(shù)中,怎么得到原來被ATTACH的設(shè)備對象呢,就是我們原來保存在設(shè)備對象中的擴(kuò)展。就是下面的方法: ?
? NTSTATUS ?
? SfCreate ? ( ?
? ? ? IN ? PDEVICE_OBJECT ? DeviceObject, ?
? ? ? IN ? PIRP ? Irp ?
? ) ?
? { ?
? return ? IoCallDriver( ?
? ((PSFILTER_DEVICE_EXTENSION) ? DeviceObject->DeviceExtension)->NLExtHeader.AttachedToDeviceObject, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Irp ? ); ?
? }???
?
注釋:幾個(gè)MAX—FUNCTION的區(qū)別 ?
? IRP_MN_MOUNT_VOLUME ?
? IRP_MN_LOAD_FILESYS ?
? 這個(gè)功能碼我只做一點(diǎn)點(diǎn)解釋:當(dāng)一個(gè)文件識別器(見上文)決定加載真正的文件系統(tǒng)的時(shí)候,會產(chǎn)生一個(gè)這樣的irp。 ?
? 12: ? 文件系統(tǒng)和設(shè)備、卷的關(guān)系和區(qū)別 ?
? 我們已經(jīng)在notify函數(shù)中綁定了文件系統(tǒng)驅(qū)動(dòng)的控 ? ?
? // ? 制對象。當(dāng)文件系統(tǒng)得到實(shí)際的介質(zhì)的時(shí)候,會生成新的設(shè)備對象, ? ?
? // ? 這種設(shè)備稱為卷(Volume),而這種設(shè)備是在file_sys中的mount中生 ? ?
? // ? 成的,而且也是unmount中注銷掉的。我們捕獲這樣的操作之后,就必 ? ?
? // ? 須生成我們的設(shè)備對象,綁定在這樣的“卷”上,才能綁定對這個(gè)卷 ? ?
? // ? 上的文件的操作。 ? ?
? VPB是Volume ? parameter ? block.一個(gè)數(shù)據(jù)結(jié)構(gòu).它的主要作用是把實(shí)際存儲媒介設(shè)備對象和文件系統(tǒng)上的卷設(shè)備對象聯(lián)系起來. ?
? 為什么我們在IoRegisterFsRegistrationChange()中進(jìn)行一些處理,還要對VOLUME進(jìn)行處理呢,兩者是不相同的事情,前者是當(dāng)文件系統(tǒng)被注冊的時(shí)候發(fā)生,或者是當(dāng)物理存儲設(shè)備被文件系統(tǒng)MOUNT成為VOLUME的時(shí)候。 ?
? 13:IRQL和跨越IRQL的限制 ?
? 實(shí)際的應(yīng)用應(yīng)該是這樣的:所有的dispatch ? functions由于是上層發(fā)來的irp而導(dǎo)致的調(diào)用,所以應(yīng)該都是Passive ? Level,在其中你可以調(diào)用絕大多數(shù)系統(tǒng)調(diào)用.而如網(wǎng)卡的OnReceive,硬盤讀寫完畢,返回而導(dǎo)致的完成函數(shù),都有可能在Dispatch級.注意都是有可能,而不是絕對是.但是一旦有可能,我們就應(yīng)該按就是考慮. ? ?
? // ? 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. ?
? 上面的理解是,當(dāng)上層發(fā)出MOUNT的IRP請求的時(shí)候,其實(shí)我們將要ATTACH的設(shè)備對象還沒有建立,現(xiàn)在得到的是其對應(yīng)的控制設(shè)備對象CDO(control ? device ? object),這個(gè)時(shí)候我們假設(shè)CDO和volume ? device ? objects具有相同的類型。 ?
? 所以我們的方法就是設(shè)置一個(gè)完成例程,當(dāng)完成MOUNT的時(shí)候,該例程將被調(diào)用,在這里完成ATTACH的工作。決定在完成函數(shù)中調(diào)用 ? IoAttachDeviceToDeviceStack來綁定Volume. ?
? 但是我們的完成例程是運(yùn)行在DISPATCH_LEVEL上的,而IoAttachDeviceToDeviceStack ? must ? be ? running ? at ? IRQL ? <= ? DISPATCH_LEVEL. ? 實(shí)際上前邊說過有IoAttachDeviceToDeviceStackSafe,這個(gè)調(diào)用可以在Dispatch ? level進(jìn)行.無奈這個(gè)調(diào)用僅僅出現(xiàn)在Xp以上的系統(tǒng)中. ?
? 超越中斷級別的限制有幾種方法.第一種是自己生成一個(gè)系統(tǒng)線程來完成此事.系統(tǒng)線程將保證在Passive ? Level中運(yùn)行.另一種方法就是把自己的任務(wù)插入Windows工作者線程,這會使你的任務(wù)遲早得到執(zhí)行.如果你的任務(wù)比較小,可以實(shí)行第二種方法.對系統(tǒng)來說比較省事,對程序員來說則反正都是麻煩. ?
? 14 ? 地址的有效性 ?
? 假設(shè)我們現(xiàn)在處理IRP_MJ_READ對應(yīng)的SFREAD()函數(shù)。 ? ?
? 1:IRP下有一個(gè)FileObject指針.這個(gè)東西指向一個(gè)文件對象.你可以得到文件對象的名字,這個(gè)名字是沒有盤符的文件全路徑.這可以通過FILEMON的方法。 ?
? 2:盤符如何獲得?因?yàn)橐呀?jīng)知道了Volume,前邊已經(jīng)說過盤符不過是Volume的符號連接名,所以也不是很大的問題。 ?
? 3:讀文件的偏移量:irpsp->Parameters.Read.ByteOffset; ? ?
? 4:具體的讀的數(shù)據(jù)在那里呢? ?
? 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設(shè)備出現(xiàn)DO_BUFFERED的情況幾乎沒有,所以DO_DIRECT_IO表示數(shù)據(jù)應(yīng)該返回到 ?
? Irp->MdlAddress所指向的MDL所指向的內(nèi)存.在無標(biāo)記的情況下,表明數(shù)據(jù)讀好,請返回到 ? ?
? Irp->UseBuffer中即可.Irp->UseBuffer是一個(gè)只在當(dāng)前線程上下文才有效的地址.如果在前面設(shè)置的完成例程,和原來的線程不是在一個(gè)上下文中的,所以在完成例程序中得到的該地址是不正確的。要么只能從Irp->MdlAddress中得到數(shù)據(jù),如果想要回到當(dāng)前線程上下文,那么就使用前面的方法,通過等待EVENT的方法。 ?
? 15 ? Mounting ? a ? Volume ?
? 卷的MOUNT的過程最典型的是當(dāng)打開一個(gè)文件或者邏輯卷的請求時(shí)候被觸發(fā)。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: ? ?
? 一個(gè)用戶應(yīng)用調(diào)用CREATEFILE來打開一個(gè)文件,或者內(nèi)核模式的驅(qū)動(dòng)程序調(diào)用ZwCreateFile。 ?
? 1.A ? user ? application ? calls ? CreateFile ? to ? open ? a ? file. ? Or ? a ? kernel-mode ? driver ? calls ? ZwCreateFile ? or ? IoCreateFileSpecifyDeviceObjectHint. ? ?
? I/O管理器決定哪個(gè)邏輯卷是請求的目標(biāo),并且檢查設(shè)備對象,查看是否它已經(jīng)被MOUNT。如果VPB_MOUNTED表示被設(shè)置,則證明卷被文件系統(tǒng)加載了。 ?
? 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. ? ?
? 如果卷自從系統(tǒng)啟動(dòng)后沒有被文件系統(tǒng)MOUNT,I/O管理器發(fā)送一個(gè)卷MOUNT的請求(IRP_MJ_FILE_SYSTEM_CONTROL, ? IRP_MN_MOUNT_VOLUME)到擁有該卷的文件系統(tǒng)。 ?
? 不是所有的內(nèi)置文件系統(tǒng)都是必須加載的,即使系統(tǒng)啟動(dòng)或是正常的,如果內(nèi)置文件系統(tǒng)沒有被加載,那么I/O管理器發(fā)送卷MOUNT的請求到文件系統(tǒng)發(fā)現(xiàn)器(FsRec)上,它會為文件系統(tǒng)檢查卷的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??