yandong_8212
驱动小牛
驱动小牛
  • 注册日期2006-07-28
  • 最后登录2011-02-11
  • 粉丝0
  • 关注0
  • 积分1046分
  • 威望464点
  • 贡献值1点
  • 好评度173点
  • 原创分0分
  • 专家分1分
阅读:4811回复:11

今天闲来无事,研究了下SFilter,写了点总结,请指正(带源码). (之二)

楼主#
更多 发布于:2009-11-08 15:37
上一篇所使用的例子是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)       对于DosNameDeviceName的解析.
2)       对于IRQL>APC_LEVEL的情况不做处理;
3)       对于出现嵌套的情况,不做处理;
4)       Volume open处理;
5)       对于OPEN ID方式处理;
6)       对于RelatedFileObject处理;
7)       对于非RelatedFileObject处理;
8)       对于不在CREATE Dispatch函数的处理;
9)       去掉末尾的L”\”;

6 手把手教你修改Sfilter
        本教程旨如何在Sfilter模型上进行修改,以达到对文件访问的控制.本文使用的模板为WDK6000Sfilter例子.
6.1 修改成自己的驱动
        增加这节的目的是为了不露馅,呵呵.在商业软件里面,对于文件版本,文件描述,出品公司这些,还是要有所注意,不可能发布一个软件有个驱动叫Sfilter.sys,所以接下来就是对驱动信息的调整.
1)       为了不破坏原有的例子,首先将Sfilter完整拷贝到一个新的文件夹,其中需要包含libSfilter两个文件夹和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.sysFileFilter.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;


//以分配的行号作为AllcTag,方便利用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标记在其他地方获得文件名,但是每次都取查询会影响速度,所以最好还是维护一个列表,标记已打开的文件.标记时可以以FileObjectFCB为索引,这个就看各自的需要.不过我还是推荐使用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_CREATEIRP_MJ_CLOSE
       
1) IRP_MJ_CRETAE中加入:
                  if (NT_SUCCESS(Irp->IoStatus.Status))
                  {
                           InsertOpenedFileCxt(&devExt->NLExtHeader, irpSp->FileObject, fileName, __LINE__);
                           //避免被释放
                           fileName = NULL;
                  }
2)改变IRP_MJ_CLOSEDispatch函数为SfClose,IRP_MJ_CLEANUPDispatch函数为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;
                  }
        }


附件名称/大小 下载次数 最后更新
FileFilter_src.rar (153KB)  102 2009-11-08 15:37
商务MSN:YanDong_8212@163.com
老鼠爱大米
驱动牛犊
驱动牛犊
  • 注册日期2009-11-07
  • 最后登录2009-11-08
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望21点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2009-11-08 15:39
呵呵 不错
neak47
驱动小牛
驱动小牛
  • 注册日期2009-05-25
  • 最后登录2016-01-09
  • 粉丝4
  • 关注0
  • 积分140分
  • 威望1221点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分1分
板凳#
发布于:2009-11-08 15:49
lz...研究的很透彻啊
nth2say
驱动牛犊
驱动牛犊
  • 注册日期2009-10-09
  • 最后登录2014-03-17
  • 粉丝1
  • 关注0
  • 积分28分
  • 威望281点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2009-11-10 14:28
LZ放个wdk6000里的sfilter上来吧,方便比较,不胜感激。。
xuqifeifly
驱动牛犊
驱动牛犊
  • 注册日期2008-09-07
  • 最后登录2016-01-09
  • 粉丝1
  • 关注0
  • 积分34分
  • 威望311点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2009-11-10 17:28
感谢,正需要
yandong_8212
驱动小牛
驱动小牛
  • 注册日期2006-07-28
  • 最后登录2011-02-11
  • 粉丝0
  • 关注0
  • 积分1046分
  • 威望464点
  • 贡献值1点
  • 好评度173点
  • 原创分0分
  • 专家分1分
5楼#
发布于:2009-11-11 10:23
去MS网站下吧,编译环境不对,我给你也编不过。
商务MSN:YanDong_8212@163.com
nth2say
驱动牛犊
驱动牛犊
  • 注册日期2009-10-09
  • 最后登录2014-03-17
  • 粉丝1
  • 关注0
  • 积分28分
  • 威望281点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2009-11-12 10:46
引用第5楼yandong_8212于2009-11-11 10:23发表的  :
去MS网站下吧,编译环境不对,我给你也编不过。



我有3790 和wdk7600,7600里面已经把sfilter给去掉了。。
feng_zhibing
驱动牛犊
驱动牛犊
  • 注册日期2009-12-11
  • 最后登录2009-12-23
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望191点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2009-12-11 14:51
正需要!
rhpeng
驱动牛犊
驱动牛犊
  • 注册日期2009-10-15
  • 最后登录2011-10-02
  • 粉丝0
  • 关注0
  • 积分26分
  • 威望241点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2010-04-15 20:13
顶一个,学习了。。。。
killvxk
论坛版主
论坛版主
  • 注册日期2005-10-03
  • 最后登录2014-04-14
  • 粉丝3
  • 关注1
  • 积分1082分
  • 威望2003点
  • 贡献值0点
  • 好评度1693点
  • 原创分2分
  • 专家分0分
9楼#
发布于:2010-04-24 15:36
我路过一下~~
没有战争就没有进步 X3工作组 为您提供最好的军火
fatepro
驱动牛犊
驱动牛犊
  • 注册日期2011-05-12
  • 最后登录2011-09-07
  • 粉丝0
  • 关注0
  • 积分68分
  • 威望681点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2011-05-14 22:56
路过
sundyhyb
驱动牛犊
驱动牛犊
  • 注册日期2008-08-22
  • 最后登录2013-10-09
  • 粉丝0
  • 关注0
  • 积分30分
  • 威望208点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2012-07-19 16:25
好人楼主!
程序不能下了,能不能再上传一份?
驱网无线,快乐无限
游客

返回顶部