Archive for the ‘文件过滤驱动’ Category

用LIST_ENTRY双向链表实现文件操作的监控 ,写于08年

星期五, 十二月 4th, 2009

 这两个星期天天都在搞这个,无数个错误被修正过后,做些笔记以备以后查阅。

        为了实现机密文档的保护,文档管理系统必须对所有打开的文件进行监控,因此我们的过滤驱动需要知道当前运行时刻有几个文件被打开,它们分别被打开了几次(同一个文件可能被多次打开)。

            用户态和内核态之间的关系

                         用户态调用CreateFile函数,子系统将请求发给IO管理器,IO管理器会用该函数的

                 参数生成一个IRP,将此IRP发往底层。过滤驱动截获到IRP,开始对其操作。过滤驱动

                 操作完了之后会继续往下发,就是调用更下层驱动程序。当下层所有操作完成之后,底

                 层的完成信息会向上反。这有点像函数的嵌套调用,从最内层函数开始一级一级的返回,

                 但这只是像。下面是过滤驱动截获返回的CreateFile时的操作。

处理IRP_MJ_CREATE的核心代码():

         {
    //返回的FsContext为空时,不予以处理
    if(FileObject->FsContext == NULL)
    {
     ////////////////////////////////////////DbgPrint("\n\n\n SfCreate: FileObject->FsContext 为 NULL\n\n\n");
     status = Irp->IoStatus.Status;

     DbgPrint("\n SfCreate() : 建立链表的第一个节点时遭遇 FsContext 为 NULL   \n",status);

     IoCompleteRequest( Irp, IO_NO_INCREMENT );
     return status;
    }

      //第一次打开链表时,链表为空,上面for语句无法运行

    if(IsListEmpty(&my_list_head))
    {
     PFILE_CONTEXT FileCtx = (PFILE_CONTEXT)ExAllocatePoolWithTag(PagedPool,sizeof(FILE_CONTEXT),SFLT_POOL_TAG);
     if(FileCtx == NULL)
      return STATUS_INSUFFICIENT_RESOURCES;

     FileCtx->FsContext = FileObject->FsContext;
     FileCtx->RefCount = 1;

     ExInterlockedInsertTailList(&my_list_head,&FileCtx->ListEntry,&my_list_lock);//多线程安全插入方式

     DbgPrint("\n\n SfCreate() : 创建链表的第一个节点:\n ");
     DbgPrint("SfCreate() : 第一个节点中 FileCtx->FsContext: %x , FileCtx->RefCount: %u \n\n\n",FileCtx->FsContext,FileCtx->RefCount);

     status = Irp->IoStatus.Status;
     IoCompleteRequest( Irp, IO_NO_INCREMENT );
     return status;
    }

    //搜索链表,查看文件是否已经打开(链表非空时,此搜索才可以进行)
    for(p=my_list_head.Flink; p!=&my_list_head; p=p->Flink)
    {
     PFILE_CONTEXT Elem = CONTAINING_RECORD(p,FILE_CONTEXT,ListEntry);

     //文件已打开,计数器加一
     if(Elem->FsContext == FileObject->FsContext)
     {
      KIRQL irql;
     
      DbgPrint("\n\n\nSfCreate() : 遇到已打开过的文件 , 打印Elem节点信息如下 :\n ListEntry: %s, FsContext: %x, RefCount: %u\n",Elem->ListEntry,Elem->FsContext,Elem->RefCount);

      if( FileObject->FsContext == NULL)
       DbgPrint( "SfCreate() : FileObject->FsContext 为 空");

      KeAcquireSpinLock(&my_list_lock,&irql);          
      Elem->RefCount += 1;    
      KeReleaseSpinLock(&my_list_lock,irql);

      ////////////////////////////////////////DbgPrint("\n文件第 %u 次打开\n",Elem->RefCount);

      status = Irp->IoStatus.Status;
      IoCompleteRequest( Irp, IO_NO_INCREMENT );
      return status;
     } 
    }


    //文件未打开,填充节点并插入链表

    { 
     //节点内存分配
     PFILE_CONTEXT FileCtx = (PFILE_CONTEXT)ExAllocatePoolWithTag(PagedPool,sizeof(FILE_CONTEXT),SFLT_POOL_TAG);
     if(FileCtx == NULL)
     {
      DbgPrint("\n\n SfCreate() : 文件第一次打开时,内存分配失败");
      return STATUS_INSUFFICIENT_RESOURCES;
     }

     //节点内容填充
     FileCtx->FsContext = FileObject->FsContext;
     FileCtx->RefCount = 1;

     //插入节点到链表
     ExInterlockedInsertTailList(&my_list_head,&FileCtx->ListEntry,&my_list_lock);//多线程安全插入方式
    }
   }      

大体思路说明:

        获取文件对象,确认它是对一个文件的操作(不是就就忽略,直接返回)。然后获取其FsContext,这是文件的全局唯一标识,一个文件不管打开多少次,它只有一个FsContext,不同文件的FsContext也不一样。如果链表为空,直接用这个FsContext填充数据结构,创立一个节点,然后插入链表,之后返回。如果链表不为空,则遍历搜索链表,如果查找到FsContext值一样的节点则说明该文件打开过,只需将该节点数据结构中的RefCount++。如果链表中没有搜索到相应节点,那么就要新建一个节点插入链表。

         既然监控就不能只监控打开的,自然也要监控关闭的。

         当关闭一个文件窗口的时候,IO管理器会发送一个IRP_MJ_CLEANUP。在处理这个消息的时候,我们需要做的仅仅是从链表中找到那个文件,将其RefCount–。当RefCount值为0的时候,IO管理器就会发送一个IRP_MJ_CLOSE,截获到这个消息,我们就可以将这个文件对应的节点从链表中删除了。

        OK!That’s all.

关键用法

    A.链表的遍历搜索

                   if(IsListEmpty(&my_list_head))       {    插入第一个节点 返回     }

                   for(p=my_list_head.Flink; p!=&my_list_head; p=p->Flink)    

                  从循环体内推出说明没找到,这就需要我们新建节点了

 

                  关键是要优先处理空链表的情况

    B.链表的插入删除操作

                      ExInterlockedInsertTailList(&my_list_head,&FileCtx->ListEntry,&my_list_lock);

                      删除LST_ENTRY p所指向的节点,第一个参数需要用前一个节点的LIST_ENTRY

                       ExInterlockedRemoveHeadList(p->Blink,&my_list_lock);

    C.IRQL锁与互斥体

                     KeAcquireSpinLock(&my_list_lock,&Irql);
                     Elem->RefCount -= 1;
                     KeReleaseSpinLock(&my_list_lock,Irql);

                     它通过提高IRQL来使其他线程无法执行,解决同步问题

                       ExAcquireFastMutex( &gSfilterAttachLock );                                       

                      ExReleaseFastMutex( &gSfilterAttachLock );

                      这个要相对轻量级

windows数据类型

星期一, 十月 20th, 2008
ATOM                   原子(原子表中的一个字符串的参考) 
BOOL                   布尔变量 
BOOLEAN                布尔变量 
BYTE                   字节(8位) 
CCHAR                  Windows字符 
CHAR                   Windows字符 
COLORREF               红、绿、蓝(RGB)彩色值(32位) 
Const                  变量,该变量的值在执行期间保持为常量 
CRITICAL_SECTION       临界段对象 
CTRYID                 国名标识符 
DLGPROC                指向一个对话框过程的指针 
DWORD                  双字(32位) 
ENHMFENUMPROC          指向一个应用程序定义的回调函数的指针,该回调函数枚举增强的元文件记录 
ENUMRESLANGPROC        指向一个应用程序定义的回调函数的指针,该回调函数枚举资源语言。 
ENUMRESNAMEPROC        指向一个应用程序定义的回调函数的指针,该回调函数枚举资源名称。 
ENUMRESTYPEPROC        指向一个应用程序定义的回调函数的指针,该回调函数枚举资源类型。  
FARPROC                指向一个回调函数的指针 
FLOAT                  浮点变量 
FMORDER                32位字体映射值的数组 
FONTENUMPROC           指向一个应用程序定义的回调函数的指针,该回调函数枚举字体 
GOBJENUMPROC           指向一个应用程序定义的回调函数的指针,该回调函数枚举图形设备接口(GDI)对象 
HACCEL                 加速键表句柄 
HANDLE                 对象的句柄 
HBITMAP                位图句柄 
HBRUSH                 画刷句柄 
HCONV                  动态数据交换(DDE)会话句柄 
HCONVLIST              DDE会话句柄 
HCURSOR                光标句柄 
HDC                    设备描述表(DC)句柄 
HDDEDATA               DDE数据句柄 
HDLG                   对话框句柄 
HDWP                   延期窗口位置结构句柄 
HENHMETAFILE           增强原文件句柄 
HFILE                  文件句柄 
HFONT                  字体句柄 
HGDIOBJ                GDI对象句柄 
HGLOBAL                全局内存块句柄 
HHOOK                  钩子句柄 
HICON                  图标句柄 
HINSTANCE              实例句柄 
HKEY                   登记关键字句柄 
HLOCAL                 局部内存块句柄 
HMEMU                  菜单句柄 
HMETAFILE              元文件句柄 
HMIDIIN                乐器的数字化接口(MIDI)输入文件句柄 
HMIDIOUT               MIDI输出文件句柄 
HMMIO                  文件句柄 
HOOKPROC               指向一个应用程序定义的钩子函数的指针 
HPALETTE               调色板句柄 
HPEN                   画笔句柄 
HRGN                   域句柄 
HRSRC                  资源句柄 
HSZ                    DDE字符串句柄 
HWAVEIN                波形输入文件句柄 
HWAVEOUT               波形输出文件句柄 
HWINSTA                工作站句柄 
HWND                   窗口句柄 
INT                    符号整数 
LANGID                 语言标识符 
LCID                   所在国(Locale)标识符 
LCTYPE                 所在国类型 
LINEDDAPROC            指向一个回调函数的指针,该回调函数处理行坐标 
LONG                   32位符号整数 
LP                     指向一个以"NULL"结束的Unicode(TM)字符串的指针 
LPARAM                 32位消息参数 
LPBOOL                 指向一个布尔变量的指针 
LPBYTE                 指向一个字节的指针 
LPCCH                  指向一个Windows字符常量的指针 
LPCCHOOKPROC           指向一个应用程序定义的钩子函数的指针 
LPCFHOOLPROC           指向一个应用程序定义的钩子函数的指针 
LPCH                   指向一个Windows字符的指针 
LPCOLORREF             指向一个COLORREF值的指针 
LPCRITICAL_SECTION     指向一个临界段对象的指针 
LPCSTR                 指向一个以"NULL"结束的WINDOWS字符串常量的指针 
LPCTSTR                指向一个以"NULL"结束的Unicode或Windows字符串常量的指针        
LPCWCH                 指向一个以"NULL"指向一个以"NULL"结束的Unicode字符常量的指针   
LPCWSTR                指向一个以"NULL"指向一个以"NULL"结束的Unicode字符串常量的指针  
LPDWORD                指向一个无符号双字(32位)的指针                 
LPFRHOOLPROC           指向一个应用程序定义的钩子函数的指针 
LPHANDLE               指向一个句柄的指针 
LOHANDLER_FUNCTION     指向一个处理程序函数的指针 
LPHWAVEIN              指向一个波形输入文件句柄的指针 
LPHWAVEOUT             指向一个波形输出文件句柄的指针 
LPINT                  指向一个符号整数的指针 
LPLONG                 指向一个符号长整数(32位)的指针 
LPOFNHOOKPROC          指向一个应用程序定义的钩子函数的指针 
LPPRINTHOOKPROC        指向一个应用程序定义的钩子函数的指针 
LPSETUPHOOKPROC        指向一个应用程序定义的钩子函数的指针 
LPTSTR                 指向一个以NULL结束的Unicode或Windows字符串的指针 
LRESULT                消息处理的符号结果 
LPVOID                 指向任何类型的指针 
LPWSTR                 指向一个以"NULL"结束的Unicode字符串的指针 
LUID                   局部唯一的标识符 
MCIDEVICEID            媒体控制接口(MCI)设备标识符 
MFENUMPROC             指向一个应用程序定义的回调函数的指针,该回调函数枚举元文件记录 
MMRESULT               多媒体消息的处理结果 
NPSTR                  指向一个以"NULL"结束的Windows字符串的指针 
NWPSTR                 指向一个以"NULL"结束的Unicode字符串的指针 
PBOOL                  指向一个布尔变量的指针 
PBYTE                  指向一个字节的指针 
PCCH                   指向一个Windows字符常量的指针 
PCH                    指向一个Windows字符的指针 
PCHAR                  指向一个Windows字符的指针 
PCRITICAL_SECTION      指向一个临界段对象的指针 
PCSTR                  指向一个以"NULL"结束的Windows字符串常量的指针 
PCWCH &nb
sp;                指向一个Unicode字符常量的指针 
PCWSTR                 指向一个以"NULL"结束的Unicode字符串常量的指针 
PDWORD                 指向一个无符号双字的指针 
PFLOAT                 指向一个浮点变量的指针 
PFNCALLBACK            指向一个回调函数的指针 
PHANDLE                指向一个句柄的指针 
PHANDLER_ROUTINE       指向一个处理程序的指针 
PHKEY                  指向一个登记关键字的指针 
PINT                   指向一个符号整数的指针 
PLONG                  指向一个符号长整数的指针 
PLUID                  指向一个局部唯一的表示符(LUID)的指针 
PROPENUMPROC           指向一个应用程序定义的回调函数的指针,该回调函数枚举窗口特征 
PSHORT                 指向一个符号短整数的指针 
PSID                   指向一个加密标识符(SID)的指针 
PSTR                   指向一个以"NULL"结束的Windows字符串的指针 
PSZ                    指向一个以"NULL"结束的Windows字符串的指针 
PTCH                   指向一个Windows或Unicode字符的指针 
PTCHAR                 指向一个Windows或Unicode字符的指针 
PTSTR                  指向一个以"NULL"结束的Windows或Unicode字符串的指针 
PUCHAR                 指向一个无符号Windows字符的指针 
PUINT                  指向一个无符号整数的指针 
PULONG                 指向一个无符号长整数的指针 
PUSHORT                指向一个无符号短整数的指针 
PVOID                  指向任何类型的指针 
PWCH                   指向一个Unicode字符的指针 
PWCHAR                 指向一个Unicode字符的指针 
PWORD                  指向一个无符号字的指针 
PWSTR                  指向一个以"NULL"结束的Unicode字符串的指针 
REGSAM                 登记关键字的加密掩码 
SC_HANDLE              服务句柄 
SERVICE_STATUS_HANDLE  服务状态值句柄 
SHORT                  短整数 
SPHANDLE               指向一个句柄的指针 
TCHAR                  Unicode或Windows字符 
TIMERPROC              指向一个应用程序定义的定时器回调函数的指针 
UCHAR                  无符号Windows字符 
UINT                   无符号整数 
ULONG                  无符号长整数 
USHORT                 无符号短整数 
VOID                   任何类型 
WCHAR                  Unicode字符 
WNDENUMPROC            指向一个应用程序定义的回调函数的指针,该回调函数枚举窗口 
WNDPROC                指向一个应用程序定义的窗口过程的指针 
WORD                   无符号字(16位) 
WPARAM                 32位消息参数 
YIELDPROC              指向一个输出回调函数的指

20081016实验测试报告—-打印当前进程名

星期四, 十月 16th, 2008

模块:sfcreate

核心代码:

                pEProcess = PsGetCurrentProcess();

ProcessName = (PTSTR)((ULONG)pEProcess+0×174);

代码功能:打印IRP当前进程名字

状况:1.系统自身启动时,IRP信息打印正常,IRP处理正常
            2.不开windbg,系统可以正常启动。进入系统后,可以用debugview看到irp打印信息,一切正常。
错误:当加载到进入VMwareService.e,该访问不停的进行,SfCreate模块返回值始终为0.调试信息打印如下:                          

进入  CREATE正式  处理

进入  退出CREATE  处理

进入  CREATE完成函数  处理

返回  CREATE正式  处理
SFilter!SfDisplayCreateFileName: Opened 00000000:00000001 \Device\HarddiskVolume1\Program Files\VMware\VMware Tools
SfCreate :  正在运行的进程是 [VMwareService.e]


错误成因:未知,但一定与vm tool有关

错误原因分析:
                    第一:该操作因为某种原因不能够完成,但是系统必须加载它,于是不停的重发该IRP
                    第二:该操作下发IRP时发生重入,于是IRP在磁盘上方徘徊,无法下发。
 
 
解决方法:
              卸载vm tool。卸载以后,系统可以正常启动,windbg可以正常打印信息
 
 
 
运行总结:
               由于打印了系统每一个irp的进程,系统运行速度极慢。
               为了便于测试,下一步我会只打印notepad.exe的IRP信息。一方面提高测试系统的运行效率,另一方面,更直观的反应我们所关心的操作。
 
 
 
 
վ:Ħ Ϻgay ŰĦ Ϻ տ ɽ ɽ ŰĦ Ϻ˹˾ ŰĦ ϺŰĦ ˹˾ ݰĦ ŰĦ Ħ ϺĦ ͬ־ Ѽ˹˾ ŰĦ ϺѼ ɳ᳡ shenzhen massage ŰĦ ͬ־ Ϸʿյά ϲŰĦ 人˿ఴĦ ɽ˹˾ Ϻ Ѽ˿ Ħ ֣ŰĦ ˹˾ ݼѼ Ϻ ǿ Ϻ ڰ᳡۸ °˾
ӣǵɽǵݸǵ麣ǵɽǵɳǵɽǵǵǵǵϺǵǵǵǵݸǵɽǵ麣ǵǵɽǵɽǵǵǵǵǵǵǵǵϺǵŰĦϺǵɽanĦൺǵӰװϷϺǵϾŰĦϾŰĦϾŰĦ㶫huλ㽭huңhuң
ӣҸĻȾ,ɾӹȫ.
ugg boots cheap UGG Boots UGG Boots Sale UGG Bailey Button Triplet ugg australia uk mens ugg boots new ghd hair straighteners coach handbags outlet
ӣվĶ٣ÿ쿴ɾ, ұ˫Ϊ˴Ǯ;ãӲҪɾҾɾվɾipҲ㡣
ɹͷ Ҹ θ Ƽʪõķ ҸƷ ƾõҽԺ 򾲶ʮζ ƹɹͷҩ θҩ ҽԺ ɹͷô ƹɹͷõҽԺ θҽԺ ̿۸ lovegreen californianews
ӣǵάɽǵάݸǵά麣ǵάɽǵάɳǵάɽǵάǵάǵάǵάϺǵάǵάǵάǵάݸǵάɽǵά麣ǵάǵάɽǵάɽǵάǵάǵάǵάǵάǵάǵάǵάϺװ˿㰴ĦϺǵάɽСlaohujiϷǵӰװϾСϾСϾС㽭huϷɽǵά˿㰴Ħ