驱动小牛
|
阅读:4811回复:11
今天闲来无事,研究了下SFilter,写了点总结,请指正(带源码). (之二)
上一篇所使用的例子是DDK3790的,今天参看了下WDK6000的例子,发现6000里面改动了不少. 所以,今天又闲来无事,写了点WDK6000的心得.
5.1 改动的数据结构及宏定义 1) typedef struct _SFILTER_DEVICE_EXTENSION { // // NL_DEVICE_EXTENSION_HEADER contains all the fields that are needed by // the name lookup library. It happens to contain all fields SFilter needs // for its device extension. // NL_DEVICE_EXTENSION_HEADER NLExtHeader; // // Local flags for this device // ULONG Flags; } SFILTER_DEVICE_EXTENSION, *PSFILTER_DEVICE_EXTENSION; 区别与之前版本的例子,该版本将Extension都封装到了NL_DEVICE_EXTENSION_HEADER该结构中新增了DosName,用于保存盘符,初始化时通过NLGetDosDeviceName启动一个工作线程获取;同时新增了Flags字段.该字段如果设置为SFDEVFL_DISABLE_VOLUME (0x00000001),就屏蔽了所有的调试选项. 2) CONSTANT_UNICODE_STRING,这个宏即使根据 typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING; 的格式将常量序列化为 UNICODE_STRING,这个宏很值得借鉴. 5.2 基本函数分析 1) DriverEntry 和之前版本基本一样,除了新增了一个gSfNameBufferLookasideList 旁式列表用于对于NAME_CONTROL结构,对于该结构的处理还是体现了作者的精细,通常情况下是用SmallBuffer,只有当大于这个长度时,才会另行申请空间. 5.3 跟名称相关的函数 首先来说一下NAME_LOOKUP_FLAGS这个结构的一些定义和使用. NLFL_USE_DOS_DEVICE_NAME:当NLExtHeader.DosName有值时,就设置这个标记; NLFL_IN_CREATE:表示是在CREATE时获取文件名; NLFL_OPEN_BY_ID: FlagOn( irpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID )时设置,表示是以文件ID方式打开文件; NLFL_OPEN_TARGET_DIR: FlagOn( irpSp->Flags, SL_OPEN_TARGET_DIRECTORY ),该文件的父文件夹应该被打开; 接下来说一下,具体分析流程: 1) 对于DosName和DeviceName的解析. 2) 对于IRQL>APC_LEVEL的情况不做处理; 3) 对于出现嵌套的情况,不做处理; 4) Volume open处理; 5) 对于OPEN ID方式处理; 6) 对于RelatedFileObject处理; 7) 对于非RelatedFileObject处理; 8) 对于不在CREATE Dispatch函数的处理; 9) 去掉末尾的L”\”; 6 手把手教你修改Sfilter 本教程旨如何在Sfilter模型上进行修改,以达到对文件访问的控制.本文使用的模板为WDK6000的Sfilter例子. 6.1 修改成自己的驱动 增加这节的目的是为了不露馅,呵呵.在商业软件里面,对于文件版本,文件描述,出品公司这些,还是要有所注意,不可能发布一个软件有个驱动叫Sfilter.sys吧,所以接下来就是对驱动信息的调整. 1) 为了不破坏原有的例子,首先将Sfilter完整拷贝到一个新的文件夹,其中需要包含lib和Sfilter两个文件夹和dir文件; 2) 修改生成的驱动路径和名称:将dir中的”filespy\”一行去掉,并修改Sfilter\source为: TARGETNAME=FileFilter TARGETTYPE=DRIVER DRIVERTYPE=FS LINKER_FLAGS=/map TARGETPATH=..\bin TARGETLIBS=$(OBJ_PATH)\..\lib\$(O)\namelookup.lib \ $(DDK_LIB_PATH)\ntstrsafe.lib INCLUDES=..\lib SOURCES=sfilter.c \ sfilter.rc 3) 修改驱动的描述信息:将Sfilter\sfilter.rc改为 #include <windows.h> #include <ntverp.h> #define VER_FILETYPE VFT_DRV #define VER_FILESUBTYPE VFT2_DRV_SYSTEM #define VER_FILEDESCRIPTION_STR "YD File Filter Driver" #define VER_INTERNALNAME_STR "FileFilter.sys" #include "common.ver" 1) 编译驱动,编译后的驱动位置在FileFilter\bin\i386(注意,我添加了TARGETPATH)2) 修改INF文件:将sfilter.inf拷贝到FileFilter\bin\i386\FileFilter.inf,将所有的SFilter替换成FileFilter除了LoadOrderGroup = "FSFilter Activity Monitor" 3) 将FileFilter.sys和FileFilter.inf拷贝到虚拟机安装调试,并将注册表Services\FileFilter下的DebugFlags修改为0xffffffff,开启所有调试功能,并重启电脑. 4) 重启电脑后,开启DebugView查看系统日志,本文档就不对虚拟机双机调试做说明, 具体请参考相关文档. 6.2 增加自己的数据结构 在namelookup.h中加入 1) 文件列表结构 在NL_DEVICE_EXTENSION_HEADER中新增: LIST_ENTRY OpenedFileList; KMUTEX OpenedFileListLock; 2)已打开文件描述 extern PAGED_LOOKASIDE_LIST gSfNameBufferLookasideList; typedef struct _OPENED_FILE_CXT { LIST_ENTRY Acr; PFILE_OBJECT FileObject; PNAME_CONTROL pFileNameCtrl; }OPENED_FILE_CXT, *POPENED_FILE_CXT; 3)新增分配和释放函数,这样处理的好处是,以后可能会对该结构采用look aside list方式分配. POPENED_FILE_CXT FilterAllocateOpenedFileCxt(ULONG InputLine) { ULONG Line = 0; CHAR *p = (CHAR *)&InputLine; //以分配的行号作为Allc的Tag,方便利用pooltag查询内存泄露点.如果分配的行号是1024,那么最终在Pooltag 中显示的是’1024’,如果行号超过10345,则显示为’A345’ if (Line > 10000) { p[3] = (CHAR)(Line %10 + '0'); p[2] = (CHAR)(Line / 10 % 10 + '0'); p[1] = (CHAR)(Line / 100 % 10 + '0'); p[0] = (CHAR)(Line / 1000 - 10 + 'A'); } else { p[3] = (CHAR)(Line %10 + '0'); p[2] = (CHAR)(Line / 10 % 10 + '0'); p[1] = (CHAR)(Line / 100 % 10 + '0'); p[0] = (CHAR)(Line / 1000 % 10 + '0'); } pCxt = ExAllocatePoolWithTag(NonPagedPool, sizeof(OPENED_FILE_CXT), Line); if (pCxt) { RtlZeroMemory(pCxt, sizeof(OPENED_FILE_CXT)); } return pCxt; } //以指针的指针传入,方便指针清零. VOID FilterFreeOpenedFileCxt(POPENED_FILE_CXT *ppOpenedFileCxt) { ASSERT(ppOpenedFileCxt); ASSERT(*ppOpenedFileCxt); NLFreeNameControl( (*ppOpenedFileCxt)->pFileNameCtrl, &gSfNameBufferLookasideList ); (*ppOpenedFileCxt)->pFileNameCtrl = NULL; ExFreePool(*ppOpenedFileCxt); *ppOpenedFileCxt = NULL; } 6.3 维护已打开文件列表 虽然可以通过屏蔽NL_IN_CREATE标记在其他地方获得文件名,但是每次都取查询会影响速度,所以最好还是维护一个列表,标记已打开的文件.标记时可以以FileObject或FCB为索引,这个就看各自的需要.不过我还是推荐使用FileObject,为什么呢?因为有的文件系统并不是一个一个文件用一个FCB,比如昆腾的stornext. 1) 搜索整个工程中的IoCreateDevice,如果DeviceObject带有DeviceExtension,那么加上下面两句 InitializeListHead(&newDevExt->NLExtHeader.OpenedFileList); KeInitializeMutex(&newDevExt->NLExtHeader.OpenedFileListLock, 0); 初始化文件列表及其锁资源. 2)在namelookup.h中加入,两个获取和释放锁的宏: #define FilterAcquireMutex(p) \ KeWaitForMutexObject((p), Executive, KernelMode, FALSE, NULL); #define FilterReleaseMutex(p) \ KeReleaseMutex((p), FALSE); 3) 在NLCleanupDeviceExtensionHeader中,开头加入释放资源的语句: POPENED_FILE_CXT pOpenedFileCxt = NULL; FilterAcquireMutex(&NLExtHeader->OpenedFileListLock); while (!IsListEmpty(&NLExtHeader->OpenedFileList)) { pOpenedFileCxt = (POPENED_FILE_CXT)RemoveHeadList(&NLExtHeader->OpenedFileList); FreeOpenedFileCxt(&pOpenedFileCxt); } FilterRleaseMutex(&NLExtHeader->OpenedFileListLock); 其中FreeOpenedFileCxt(&pOpenedFileCxt);是释放函数 4)新增插入,查找,删除函数 VOID InsertOpenedFileCxt(PNL_DEVICE_EXTENSION_HEADER pExt, PFILE_OBJECT FileObject, PNAME_CONTROL pNameCtrl, ULONG uLine) { POPENED_FILE_CXT pOpenedFileCxt = NULL; ASSERT(pExt); ASSERT(FileObject); ASSERT(pNameCtrl); pOpenedFileCxt = FilterAllocateOpenedFileCxt(uLine); if (NULL == pOpenedFileCxt) { ASSERT(0); return; } pOpenedFileCxt->FileObject = FileObject; pOpenedFileCxt->pFileNameCtrl = pNameCtrl; FilterAcquireMutex(&pExt->OpenedFileListLock); InsertHeadList(&pExt->OpenedFileList, &pOpenedFileCxt->Acr); FilterReleaseMutex(&pExt->OpenedFileListLock); } POPENED_FILE_CXT FindOpenedFileCxt(PNL_DEVICE_EXTENSION_HEADER pExt, PFILE_OBJECT FileObject) { POPENED_FILE_CXT pOpenedFileCxtRet = NULL; PLIST_ENTRY p = NULL; ASSERT(pExt); ASSERT(FileObject); FilterAcquireMutex(&pExt->OpenedFileListLock); for (p=pExt->OpenedFileList.Flink; p!=&pExt->OpenedFileList; p=p->Flink) { POPENED_FILE_CXT pTempCxt = (POPENED_FILE_CXT)p; if (pTempCxt->FileObject == FileObject) { pOpenedFileCxtRet = pTempCxt; break; } } FilterReleaseMutex(&pExt->OpenedFileListLock); return pOpenedFileCxtRet; } VOID RemoveOpenedFileCxt(PNL_DEVICE_EXTENSION_HEADER pExt, PFILE_OBJECT FileObject) { PLIST_ENTRY p = NULL; ASSERT(pExt); ASSERT(FileObject); FilterAcquireMutex(&pExt->OpenedFileListLock); for (p=pExt->OpenedFileList.Flink; p!=&pExt->OpenedFileList; p=p->Flink) { POPENED_FILE_CXT pTempCxt = (POPENED_FILE_CXT)p; if (pTempCxt->FileObject == FileObject) { RemoveEntryList(&pTempCxt->Acr); FilterFreeOpenedFileCxt(&pTempCxt); break; } } FilterReleaseMutex(&pExt->OpenedFileListLock); } 6.4 在Dispatch函数中加入对文件列表的维护,IRP_MJ_CREATE和IRP_MJ_CLOSE中 1) IRP_MJ_CRETAE中加入: if (NT_SUCCESS(Irp->IoStatus.Status)) { InsertOpenedFileCxt(&devExt->NLExtHeader, irpSp->FileObject, fileName, __LINE__); //避免被释放 fileName = NULL; } 2)改变IRP_MJ_CLOSE的Dispatch函数为SfClose,IRP_MJ_CLEANUP的Dispatch函数为SfCleanup.SfCleanup用原来的SfCleanupClose替代,在SfClose中加入: pOpenedFileCxt = FindOpenedFileCxt(&devExt->NLExtHeader, irpSp->FileObject); if (pOpenedFileCxt) { DbgPrint("Close file<%wZ>\n", &pOpenedFileCxt->pFileNameCtrl->Name); RemoveOpenedFileCxt(&devExt->NLExtHeader, irpSp->FileObject); } 至此,可以编译并测试驱动工作是否正常,查看工具仍然是DebView. 备注,由于sfilter是随机启动,如果程序有BUG,很可能导致系统无法启动,所以最好先在虚拟机里面进行调试,同时学会用VM\Snapshot 功能,该功能相当有用. 6.5 应用举例 1) 通过驱动屏蔽Autorun,在Create的函数中禁止打开和创建autorun.inf起到屏蔽Autorun的目的. { UNICODE_STRING usAutorun = CONSTANT_UNICODE_STRING(L"*AUTORUN.INF"); if (FsRtlIsNameInExpression(&usAutorun, &fileName->Name, TRUE , NULL)) { if (fileName != NULL) { NLFreeNameControl( fileName, &gSfNameBufferLookasideList ); } status = Irp->IoStatus.Status = STATUS_ACCESS_DENIED; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return status; } } |
|
沙发#
发布于:2009-11-08 15:39
呵呵 不错
|
|
板凳#
发布于:2009-11-08 15:49
lz...研究的很透彻啊
|
|
地板#
发布于:2009-11-10 14:28
LZ放个wdk6000里的sfilter上来吧,方便比较,不胜感激。。
|
|
地下室#
发布于:2009-11-10 17:28
感谢,正需要
|
|
驱动小牛
|
5楼#
发布于:2009-11-11 10:23
去MS网站下吧,编译环境不对,我给你也编不过。
|
|
6楼#
发布于:2009-11-12 10:46
|
|
7楼#
发布于:2009-12-11 14:51
正需要!
|
|
8楼#
发布于:2010-04-15 20:13
顶一个,学习了。。。。
|
|
9楼#
发布于:2010-04-24 15:36
我路过一下~~
|
|
|
10楼#
发布于:2011-05-14 22:56
路过
|
|
11楼#
发布于:2012-07-19 16:25
好人楼主!
程序不能下了,能不能再上传一份? |
|
|