我也来发下FileMon解说

                           我也来发下FileMon解说

 

废话不说,直接主题:

 

DriverEntry开始:

    RtlInitUnicodeString (&deviceNameUnicodeString,

                          deviceNameBuffer );

 

    //

    // Create the device used for GUI communications

    //

    ntStatus = IoCreateDevice ( DriverObject,

                                0,

                                &deviceNameUnicodeString,

                                FILE_DEVICE_FILEMON,

                                0,

                                TRUE,

                                &GUIDevice );

首先创建了一个控制设备,创建成功后便创建一个设备链接名,用于应用程序通过这个链接打开设备,进而进行一些通信,传递命令等。接下来便是填写分发历程了,这里有一个新的就是这个是文件过滤驱动,必须要创建FastIoDispatch这个分发函数,

引用MSDN上的:

To register the file system filter driver's fast I/O dispatch routines, you must allocate and initialize a fast I/O dispatch table, store the entry points of the fast I/O dispatch routines into the table, and store the address of the table in the FastIoDispatch member of the driver object.

For example, the FileSpy sample driver sets the entry points for its fast I/O dispatch routines as follows:

RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
fastIoDispatch->FastIoCheckIfPossible = SpyFastIoCheckIfPossible;
fastIoDispatch->FastIoRead = SpyFastIoRead;
fastIoDispatch->FastIoWrite = SpyFastIoWrite;
fastIoDispatch->FastIoQueryBasicInfo = SpyFastIoQueryBasicInfo;
fastIoDispatch->FastIoQueryStandardInfo = SpyFastIoQueryStandardInfo;
fastIoDispatch->FastIoLock = SpyFastIoLock;
fastIoDispatch->FastIoUnlockSingle = SpyFastIoUnlockSingle;
fastIoDispatch->FastIoUnlockAll = SpyFastIoUnlockAll;
fastIoDispatch->FastIoUnlockAllByKey = SpyFastIoUnlockAllByKey;
fastIoDispatch->FastIoDeviceControl = SpyFastIoDeviceControl;
fastIoDispatch->FastIoDetachDevice = SpyFastIoDetachDevice;
fastIoDispatch->FastIoQueryNetworkOpenInfo = SpyFastIoQueryNetworkOpenInfo;
fastIoDispatch->MdlRead = SpyFastIoMdlRead;
fastIoDispatch->MdlReadComplete = SpyFastIoMdlReadComplete;
fastIoDispatch->PrepareMdlWrite = SpyFastIoPrepareMdlWrite;
fastIoDispatch->MdlWriteComplete = SpyFastIoMdlWriteComplete;
fastIoDispatch->FastIoReadCompressed = SpyFastIoReadCompressed;
fastIoDispatch->FastIoWriteCompressed = SpyFastIoWriteCompressed;
fastIoDispatch->MdlReadCompleteCompressed = SpyFastIoMdlReadCompleteCompressed;
fastIoDispatch->MdlWriteCompleteCompressed = SpyFastIoMdlWriteCompleteCompressed;
fastIoDispatch->FastIoQueryOpen = SpyFastIoQueryOpen;

DriverObject->FastIoDispatch = fastIoDispatch;

不必都要写上,你要是想要全部监视的话就慢慢写吧,filemon上面弄了一个简单的方法直接弄一个结构:

FAST_IO_DISPATCH    FastIOHook = {

    sizeof(FAST_IO_DISPATCH),

    FilemonFastIoCheckifPossible,

    FilemonFastIoRead,

    FilemonFastIoWrite,

    FilemonFastIoQueryBasicInfo,

    FilemonFastIoQueryStandardInfo,

    FilemonFastIoLock,

    FilemonFastIoUnlockSingle,

    FilemonFastIoUnlockAll,

    FilemonFastIoUnlockAllByKey,

    FilemonFastIoDeviceControl,//只要这个的

    FilemonFastIoAcquireFile,

    FilemonFastIoReleaseFile,

    FilemonFastIoDetachDevice,//还有这个

 

    //

    // new for NT 4.0

    //

    FilemonFastIoQueryNetworkOpenInfo,

    FilemonFastIoAcquireForModWrite,

    FilemonFastIoMdlRead,

    FilemonFastIoMdlReadComplete,

    FilemonFastIoPrepareMdlWrite,

    FilemonFastIoMdlWriteComplete,

    FilemonFastIoReadCompressed,

    FilemonFastIoWriteCompressed,

    FilemonFastIoMdlReadCompleteCompressed,

    FilemonFastIoMdlWriteCompleteCompressed,

    FilemonFastIoQueryOpen,

    FilemonFastIoReleaseForModWrite,

    FilemonFastIoAcquireForCcFlush,

    FilemonFastIoReleaseForCcFlush

};

来完成,这里还用到了一个自定义的宏用于找到指定的分发函数:

// A check to see if a fastio table extends to a specific entry

//

#define FASTIOPRESENT( _hookExt, _call )                                                      /

    ((((ULONG)&_hookExt->FileSystem->DriverObject->FastIoDispatch->_call -                    /

       (ULONG) &_hookExt->FileSystem->DriverObject->FastIoDispatch->SizeOfFastIoDispatch <    /

       (ULONG) _hookExt->FileSystem->DriverObject->FastIoDispatch->SizeOfFastIoDispatch )) && /

      hookExt->FileSystem->DriverObject->FastIoDispatch->_call )

好了,填写FastIoDispatchDriverObject->FastIoDispatch = &FastIOHook;

然后便是一些初始化的动作,如初始化自选锁:

KeInitializeSpinLock( &FilterMutex );

还用初始化了LookasideList,用于连续分派内存,这里还弄了一个

Store   = MemAllocatePool( NonPagedPool, sizeof(*Store) );,这个结构是用于存储我们得到的路径名,进程名等信息的

 

上述步骤完成后,首先程序进入到的是我们的FilemonDispatch;这个函数:

NTSTATUS FilemonDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )

{

    //

    // Determine if its a request from the GUI to us, or one that is

    // directed at a file system driver that we've hooked

    //

       //决定是否是回应我们的的GUI,还是直接在一个我们hook的文件系统上

    if ( GUIDevice != DeviceObject )

       {

 

        return( FilemonHookRoutine( DeviceObject, Irp ));

 

    }

       else

       {

 

        return( FilemonDeviceRoutine( DeviceObject, Irp ));

 

    }

}

 

第一次肯定是执行FilemonDeviceRoutine( DeviceObject, Irp )的,我们继续看

在这个FilemonDeviceRoutine( DeviceObject, Irp )函数中,只是简单的打印了下IRP_MJ_CREATEIRP_MJ_CLOSE,并将得到的IRP_MJ_DEVICE_CONTROL:设备控制命令直接传入到FilemonFastIoDeviceControl中去了。在FilemonFastIoDeviceControl这里面进行了详细的响应:

在这个函数里同样,首先判断是不是我们的控制设备传来的命令,并做了相应的响应:
看了下应用程序的代码,首先传进来的便是FILEMON_setdrives的命令了,才开始总是不明白没有FILEMON_setdrives:这个怎么就开始监视了呢。在这个FILEMON_setdrives:命令响应中,就开始设置hook了,通过调用HookDriveSet这个函数进行了hook;

 

剩下的那个几个命令很容易理解,路过

FilemonFastIoDeviceControl里,如果不是我们的控制设备传来的IRP,便简单的记录了下

 

下面来看HookDriveSet这里面:

 

for ( drive = 0; drive < 26; ++drive )

       {

 

        bit = 1 << drive;

 

        //

        // Are we suppoed to hook this drive?

        //

              //若不存在该驱动器就不能hook

              //传来0就是UHOOK

                      if ( bit & DriveSet ) 

              {  //   11    &    11

 

            //

            // Try to hook drive

            //

            if ( ! HookDrive( (char)('A'+drive), DriverObject ) )

                     {

            

                //

                // Remove from drive set if can't be hooked

                //

                            //不能hook的画就移除驱动器设置

                DriveSet &= ~bit;

 

            }

                     else

                     {

 

                //

                // hook drives in same drive group     

                //

                for( i = 0; i < 26; i++ )

                            {

 

                    if( LDriveMap[i] == LDriveMap[ drive ] &&!LDriveDevices[i] )

                                   {

                        DriveSet |= ( 1<<i );

                        LDriveDevices[i] = LDriveDevices[drive];

 

                    }

                }

            }

 

        }这里的LDriveDevices[26];是为为每一个驱动器设置hook的表,记录该文件对象什么的。并将hook了的卷记录下来。

 

HookDrive里面,首先查看该卷是否已经被hook了,没有的话就开始hook

直接看注释吧

RtlInitUnicodeString( &fileNameUnicodeString, filename );

        InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString,

                                    OBJ_CASE_INSENSITIVE, NULL, NULL );

        ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS,

                                 &objectAttributes, &ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,

                                 FILE_OPEN,

                                 FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE,

                                 NULL, 0 );

              //打开根目录

        if( !NT_SUCCESS( ntStatus ) )

              {

 

            DbgPrint(("Filemon: Could not open drive %c: %x/n", 'A'+Drive, ntStatus ));

 

            return FALSE;

        }

 

        DbgPrint(("Filemon:  opened the root directory!!! handle: %x/n", ntFileHandle));  

 

        //

        // Got the file handle, so now look-up the file-object it refers to

        //

              //得到了文件句柄后,在得到文件对象

        ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA,

                                              NULL, KernelMode, &fileObject, NULL );

        if( !NT_SUCCESS( ntStatus )) {

 

            DbgPrint(("Filemon: Could not get fileobject from handle: %c/n", 'A'+Drive ));

            ZwClose( ntFileHandle );

 

            return FALSE;

        }

              //得到了文件对象了

 

        // 

        // Next, find out what device is associated with the file object by getting its related

        // device object

        //接下来,找出哪一个设备关联了文件对象,通过得到它的关联设备对象

        fileSysDevice = IoGetRelatedDeviceObject( fileObject );

 

        if ( ! fileSysDevice )

              {

 

            DbgPrint(("Filemon: Could not get related device object: %c/n", 'A'+Drive ));

 

            ObDereferenceObject( fileObject );

            ZwClose( ntFileHandle );

 

            return FALSE;

        }

 

        // 

        // Check the device list to see if we've already attached to this particular device.

        // This can happen when more than one drive letter is being handled by the same network

        // redirecter

        //  检查设备列表是否我们已经挂接到这个具体的设备

        for( i = 0; i < 26; i++ )

              {

 

            if( LDriveDevices[i] == fileSysDevice )

                     {

 

                //

                // If we're already watching it, associate this drive letter

                // with the others that are handled by the same network driver. This

                // enables us to intelligently update the hooking menus when the user

                // specifies that one of the group should not be watched -we mark all

                // of the related drives as unwatched as well

                //

                ObDereferenceObject( fileObject );

 

                ZwClose( ntFileHandle );

 

                LDriveMap[ Drive ]     = LDriveMap[i];

                LDriveDevices[ Drive ] = fileSysDevice;

 

                return TRUE;

            }

        }

 

        //

        // The file system's device hasn't been hooked already, so make a hooking device

        //  object that will be attached to it.

        //

        ntStatus = IoCreateDevice( DriverObject,

                                   sizeof(HOOK_EXTENSION),

                                   NULL,

                                   fileSysDevice->DeviceType,

                                   0,

                                   FALSE,

                                   &hookDevice );

 

              /************************************************************************/

              /*  DeviceType参数必须始终设置为过滤设备对象所附加到的目标(文件系统或过滤)

              设备对象。按照此方法传递设备类型是非常重要的,这是因为它将由I/O Manager使用

              ,并传回给应用程序 ,在上面调用IoCreateDevice时,由于过滤设备对象并没有命名,

              因此将DeviceName参数设置为NULL                                                                    */

              /************************************************************************/

        if ( !NT_SUCCESS(ntStatus) )

              {

 

            DbgPrint(("Filemon: failed to create associated device: %c/n", 'A'+Drive ));  

 

            ObDereferenceObject( fileObject );

            ZwClose( ntFileHandle );

 

            return FALSE;

        }

 

        //

        // Clear the device's init flag as per NT DDK KB article on creating device

        // objects from a dispatch routine

        //需要确保清除过滤设备对象的DO_DEVICE_INITIALIZING标识

              //注意:如果本标识没有被清除,其它过滤驱动将无法再次附加到该过滤链

              //此时调用IoAttachDeviceToDeviceStackSafe将失败

        hookDevice->Flags &= ~DO_DEVICE_INITIALIZING;

 

        //

        // Setup the device extensions. The drive letter and file system object are stored

        // in the extension.

        //

        hookExtension = hookDevice->DeviceExtension;

        hookExtension->LogicalDrive = 'A'+Drive;

        hookExtension->FileSystem   = fileSysDevice;

 

        //

        // Finally, attach to the device. The second we're successfully attached, we may

        // start receiving IRPs targetted at the device we've hooked.

        //

              //fileSysDevice使我们盘的文件设备对象

        ntStatus = IoAttachDeviceByPointer( hookDevice, fileSysDevice );

        if ( !NT_SUCCESS(ntStatus) ) 

              {

 

            //

            // Couldn' attach for some reason

            //

            DbgPrint(("Filemon: Connect with Filesystem failed: %c (%x) =>%x/n",

                      'A'+Drive, fileSysDevice, ntStatus ));

 

            //

            // Derefence the object and get out

            //

            ObDereferenceObject( fileObject );

            ZwClose( ntFileHandle );

 

            return FALSE;

 

        }

              else //挂接成功

              {

 

            //

            // Make a new drive group for the device,l if it does not have one

            // already

            //

            DbgPrint(("Filemon: Successfully connected to Filesystem device %c/n", 'A'+Drive ));

            if( !LDriveMap[ Drive ] )

                     {

 

                LDriveMap[ Drive ] = ++LDriveGroup;

            }

        }

   

        //

        // Close the file and update the hooked drive list by entering a

        // pointer to the hook device object in it.

        //

        ObDereferenceObject( fileObject );

 

        ZwClose( ntFileHandle );

 

        LDriveDevices[Drive] = hookDevice;

    }

 

return TRUE;

 

 

filemon里面我觉得比较重要的几个函数就是HookDriveFilemonGetFullPathFilemonGetProcess这几个了

 

其中FilemonGetProcess是通过先得到我们在DriverEntry中的进程System,然后记录每一个IRP响应的当前进程+System偏移就得到了进程的 名字

// Uses undocumented data structure offsets to obtain the name of the

// currently executing process.

 

FilemonGetFullPath这里采用的方法是获取路径中最复杂的方法了:

主要是通过在FILEOBJECT.FileName中提取的,主要是在文件打开之前从打开文件的请求中提取路径的。

还有一种是在文件CREATE IRP处理结束后获取路径的,是sFilter中所使用的方法

 

还有一个是在文件过滤其他IRP时,得到FILEOBJECT所对应的文件路径;

 

FIlemon中用了一个//名字列表

PHASH_ENTRY        HashTable[NUMHASH];将每次记录的路径存储到这里,

下一次在调用FilemonGetFullPath先查看是否已经有了,有的话就不用在去获取了,适合大的场合。

 

 

到处就差不多了,至于文件过滤驱动中的哪些FastIoDispatchfilemon中大致都是一模一样的,没什么要关注的都是直接retval = hookExt->FileSystem->DriverObject->FastIoDispatch->PrepareMdlWrite(

            FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus,

            hookExt->FileSystem );调用文件系统的

 

 

收工,到此为止,去吃饭了

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值