⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 filemon学习笔记 --- windows文件过滤系统驱动开发 - 驱动开发 - 私のウェブサイト.htm

📁 驱动开发的一些资料
💻 HTM
📖 第 1 页 / 共 5 页
字号:
                        cellSpacing=0 cellPadding=0 width="100%" border=0>
                          <TBODY>
                          <TR>
                            <TD width=650>
                              <DIV id=art style="MARGIN: 15px">
                              <DIV> WINDOWS文件过滤系统驱动开发,可用于硬盘还原,防病毒,文件安全防护,文件加密等诸多领域。而掌握核心层的理论及实践,对于成为一名优秀的开发人员不可或缺。</DIV>
                              <DIV>  WINDOWS文件过滤系统驱动开发的两个经典例子,Filemon与SFilter,初学者在经过一定的理论积累后,对此两个例子代码的研究分析,会是步入驱动开发殿堂的重要一步,相信一定的理论积累以及贯穿剖析理解此两个例程后,就有能力开始进行文件过滤系统驱动开发的实际工作了。</DIV>
                              <DIV>  对于SFilter例子的讲解,楚狂人的教程已经比较流行,而Filemon例子也许因框架结构相对明晰,易于剖析理解,无人贴出教程,本人在剖析Filemon的过程中积累的一些笔记资料,陆续贴出希望对初学者有所帮助,并通过和大家的交流而互相提高。</DIV>
                              <DIV>  Filemon学习笔记 第一篇:</DIV>
                              <DIV>  Filemon的大致架构为,在此驱动程序中,创建了两类设备对象。</DIV>
                              <DIV>  一类设备对象用于和Filemon对应的exe程序通信,以接收用户输入信息,比如挂接或监控哪个分区,是否要挂接,是否要监控,监控何种操作等。此设备对象只创建了一个,在驱动程序的入口函数DriverEntry中。此类设备对象一般称为控制设备对象,并有名字,以方便应用层与其通信操作。</DIV>
                              <DIV>  第二类设备对象用于挂接到所须监控的分区,比如c:,d:或e:,f:,以便拦截到引应用层对该分区所执行的读,写等操作。此类设备对象为安全起见,一般不予命名,可根据须监控多少分区而创建一个或多个。</DIV>
                              <DIV>  驱动入口函数大致如下:</DIV>
                              <DIV>NTSTATUS<BR>DriverEntry(<BR>  IN 
                              PDRIVER_OBJECT DriverObject,<BR>  IN 
                              PUNICODE_STRING 
                              RegistryPath<BR>  )<BR>{<BR>  NTSTATUS        ntStatus;<BR>  PDEVICE_OBJECT     guiDevice;<BR>  WCHAR          
                              deviceNameBuffer[] = 
                              L"DeviceFilemon";<BR>  UNICODE_STRING     deviceNameUnicodeString;<BR>  WCHAR          
                              deviceLinkBuffer[] = 
                              L"DosDevicesFilemon";<BR>  UNICODE_STRING     deviceLinkUnicodeString;<BR>  ULONG          
                              i;<BR>  DbgPrint (("Filemon.SYS: entering 
                              DriverEntry<BR>"));<BR>  FilemonDriver = 
                              DriverObject;<BR>  //  <BR>  // Setup the device 
                              name<BR>  //  <BR>  RtlInitUnicodeString 
                              (&amp;deviceNameUnicodeString,<BR>             deviceNameBuffer 
                              );<BR>  //<BR>  // Create the device used for GUI 
                              communications<BR>  //此设备对象用来和用户交互信息<BR>  ntStatus 
                              = IoCreateDevice ( 
                              DriverObject,<BR>                sizeof(HOOK_EXTENSION),<BR>                &amp;deviceNameUnicodeString,<BR>                FILE_DEVICE_FILEMON,<BR>                0,<BR>                TRUE,<BR>                &amp;guiDevice 
                              );<BR>  //<BR>  // If successful, make a symbolic 
                              link that allows for the device<BR>  // object's 
                              access from Win32 
                              programs<BR>  //<BR>  if(NT_SUCCESS(ntStatus)) 
                              {<BR>    //<BR>    // Mark this as our GUI 
                              device<BR>    //<BR>    ((PHOOK_EXTENSION) 
                              guiDevice-&gt;DeviceExtension)-&gt;Type = 
                              GUIINTERFACE;<BR>    //<BR>    // Create a 
                              symbolic link that the GUI can specify to gain 
                              access<BR>    // to this 
                              driver/device<BR>    //<BR>    RtlInitUnicodeString 
                              (&amp;deviceLinkUnicodeString,<BR>               deviceLinkBuffer 
                              );<BR>    ntStatus = IoCreateSymbolicLink 
                              (&amp;deviceLinkUnicodeString,<BR>                     
                              &amp;deviceNameUnicodeString 
                              );<BR>    if(!NT_SUCCESS(ntStatus)) 
                              {<BR>      DbgPrint (("Filemon.SYS: 
                              IoCreateSymbolicLink 
                              failed<BR>"));<BR>      IoDeleteDevice( guiDevice 
                              );<BR>      return 
                              ntStatus;      <BR>    }<BR>    //<BR>    // 
                              Create dispatch points for all routines that must 
                              be handled.<BR>    // All entry points are 
                              registered since we might filter a<BR>    // file 
                              system that processes all of 
                              them.<BR>    //<BR>    for( i = 0; i &lt;= 
                              IRP_MJ_MAXIMUM_FUNCTION; i++ ) 
                              {<BR>      DriverObject-&gt;MajorFunction[i] = 
                              FilemonDispatch;<BR>    }<BR>#if 
                              DBG    <BR>    //<BR>    // Driver unload is only 
                              set if we are debugging Filemon. This is<BR>    // 
                              because unloading a filter is not really safe - 
                              threads could<BR>    // be in our fastio routines 
                              (or about to enter them), for example,<BR>    // 
                              and there is no way to tell. When debugging, we 
                              can risk the<BR>    // occasional unload crash as 
                              a trade-off for not having to<BR>    // reboot as 
                              often.<BR>    //<BR>    // 
                              DriverObject-&gt;DriverUnload = 
                              FilemonUnload;<BR>#endif // 
                              DBG<BR>    //<BR>    // Set up the Fast I/O 
                              dispatch 
                              table<BR>    //<BR>    DriverObject-&gt;FastIoDispatch 
                              = &amp;FastIOHook;<BR>  } else 
                              {<BR>    //<BR>    // If something went wrong, 
                              cleanup the device object and don't 
                              load<BR>    //<BR>    DbgPrint(("Filemon: Failed 
                              to create our device!<BR>"));<BR>    return 
                              ntStatus;<BR>  }<BR>  //<BR>  // Initialize the 
                              name hash table<BR>  //<BR>  for(i = 0; i &lt; 
                              NUMHASH; i++ ) HashTable[i] = 
                              NULL;<BR>  //<BR>  // Find the process name 
                              offset<BR>  //<BR>  ProcessNameOffset = 
                              FilemonGetProcessNameOffset();//为了得到当前进程名字<BR>  //<BR>  // 
                              Initialize the synchronization 
                              objects<BR>  //<BR>#if 
                              DBG<BR>  KeInitializeSpinLock( &amp;CountMutex 
                              );<BR>#endif<BR>  ExInitializeFastMutex( 
                              &amp;LogMutex );<BR>  ExInitializeResourceLite( 
                              &amp;FilterResource 
                              );<BR>  ExInitializeResourceLite( 
                              &amp;HashResource );<BR>  //<BR>  // Initialize a 
                              lookaside for file 
                              names<BR>  //<BR>  ExInitializeNPagedLookasideList( 
                              &amp;FullPathLookaside, NULL, NULL,<BR>           
                              0, MAXPATHLEN, 'mliF', 256 );<BR>  //<BR>  // 
                              Allocate the first output 
                              buffer<BR>  //<BR>  CurrentLog = ExAllocatePool( 
                              NonPagedPool, sizeof(*CurrentLog) );<BR>  if( 
                              !CurrentLog ) {<BR>    //<BR>    // Oops - we 
                              can't do anything without at least one 
                              buffer<BR>    //<BR>    IoDeleteSymbolicLink( 
                              &amp;deviceLinkUnicodeString 
                              );<BR>    IoDeleteDevice( guiDevice 
                              );<BR>    return 
                              STATUS_INSUFFICIENT_RESOURCES;<BR>  }<BR>  //<BR>  // 
                              Set the buffer pointer to the start of the buffer 
                              just allocated<BR>  //<BR>  CurrentLog-&gt;Len = 
                              0;<BR>  CurrentLog-&gt;Next = NULL;<BR>  NumLog = 
                              1;<BR>  return 
                              STATUS_SUCCESS;<BR>}在此驱动入口点函数中,主要做了生成新的设备对象,此设备对象用来和应用层信息交互,比如应用层向驱动传递需要挂接或者监控的分区盘符,或者是否挂接盘符,是否监控操作等。 上面创建设备对象的代码为:ntStatus 
                              = IoCreateDevice ( 
                              DriverObject,<BR>                sizeof(HOOK_EXTENSION),<BR>                &amp;deviceNameUnicodeString,<BR>                FILE_DEVICE_FILEMON,<BR>                0,<BR>                TRUE,<BR>                &amp;guiDevice 
                              );<BR>  //<BR>  // If successful, make a symbolic 
                              link that allows for the device<BR>  // object's 
                              access from Win32 
                              programs<BR>  //<BR>  if(NT_SUCCESS(ntStatus)) 
                              {<BR>    //<BR>    // Mark this as our GUI 
                              device<BR>    //<BR>    ((PHOOK_EXTENSION) 
                              guiDevice-&gt;DeviceExtension)-&gt;Type = 
                              GUIINTERFACE;<BR>    //<BR>    // Create a 
                              symbolic link that the GUI can specify to gain 
                              access<BR>    // to this 
                              driver/device<BR>    //<BR>    RtlInitUnicodeString 
                              (&amp;deviceLinkUnicodeString,<BR>               deviceLinkBuffer 
                              );<BR>    ntStatus = IoCreateSymbolicLink 
                              (&amp;deviceLinkUnicodeString,<BR>                     
                              &amp;deviceNameUnicodeString 
                              );<BR>    if(!NT_SUCCESS(ntStatus)) 
                              {<BR>      DbgPrint (("Filemon.SYS: 
                              IoCreateSymbolicLink 
                              failed<BR>"));<BR>      IoDeleteDevice( guiDevice 
                              );<BR>      return 
                              ntStatus;      <BR>    }上面代码完成的功能为创建了用于与应用层交互的控制设备对象,名字在参数&amp;deviceNameUnicodeString,中。设备对象创建成功后又调用IoCreateSymbolicLink创建了一个符号连接,以便于应用层交互。在入口点函数DriverEntry代码中,还有一处代码: 
                              ProcessNameOffset = 
                              FilemonGetProcessNameOffset();//为了得到当前进程名字。此函数体如下:ULONG<BR>FilemonGetProcessNameOffset(<BR>  VOID<BR>  )<BR>{<BR>  PEPROCESS    
                              curproc;<BR>  int       i;<BR>  curproc = 
                              PsGetCurrentProcess();//调用PsGetCurrentProcess取得KPEB基址<BR>  //然后搜索KPEB,得到ProcessName相对KPEB的偏移量<BR>  // 
                              Scan for 12KB, hoping the KPEB never grows that 
                              big!<BR>  //<BR>  for( i = 0; i &lt; 3*PAGE_SIZE; 
                              i++ ) {<BR>  <BR>    if( !strncmp( SYSNAME, 
                              (PCHAR) curproc + i, strlen(SYSNAME) )) 
                              {<BR>      return 
                              i;<BR>    }<BR>  }<BR>  //<BR>  // Name not found 
                              - oh, well<BR>  //<BR>  return 0; 这个函数通过查找KPEB 
                              (Kernel Process Environment 
                              Block),取得进程名,GetProcessNameOffset主要是调用PsGetCurrentProcess取得KPEB基址,然后搜索 
                              KPEB,得到ProcessName相对KPEB的偏移量,存放在全局变量ProcessNameOffset中,得到此偏移量的作用是:无论当前进程为哪个,其名字在KPEB中的偏移量不变,所以都可以通过此偏移量得到。而在入口点函数DriverEntry执行时,当前进程必为系统进程,所以在此函数中方便地根据系统进程名SYSNAME(#define 
                              SYSNAME "System")得到此偏移量。</DIV>
                              <DIV>  分发函数剖析:</DIV>
                              <DIV>  在入口点函数中,通过代码:</DIV>
                              <DIV>for( i = 0; i &lt;= IRP_MJ_MAXIMUM_FUNCTION; 
                              i++ ) {<BR>      DriverObject-&gt;MajorFunction[i] 
                              = 
                              FilemonDispatch;<BR>}简单地把各个分发例程设置成了FilemonDispatch; 
                              然后我们追踪其函数体:NTSTATUS<BR>FilemonDispatch(<BR>  IN 
                              PDEVICE_OBJECT DeviceObject,<BR>  IN PIRP 
                              Irp<BR>  )<BR>{<BR>  //<BR>  // Determine if its a 
                              request from the GUI to us, or one that is<BR>  // 
                              directed at a file system driver that we've 
                              hooked<BR>  //<BR>  if( ((PHOOK_EXTENSION) 
                              DeviceObject-&gt;DeviceExtension)-&gt;Type == 
                              GUIINTERFACE ) {<BR>    return 
                              FilemonDeviceRoutine( DeviceObject, Irp );<BR>  } 
                              else {<BR>    return FilemonHookRoutine( 
                              DeviceObject, Irp );<BR>  }<BR>}</DIV>
                              <DIV>  函数体先判断需要处理IRP包的设备对象的类型,看是属于控制设备对象,还是属于用于挂接并监控文件读写操作的过滤设备对象。如果是属于后者 
                              则进入:FilemonHookRoutine( DeviceObject, Irp 
                              )此函数是拦截文件操作的中心,在其中获得了被操作的文件名字,并且根据操作类型,在</DIV>
                              <DIV>  switch( currentIrpStack-&gt;MajorFunction ) 
                              {</DIV>
                              <DIV>  }</DIV>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -