S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

FileMon源码学习笔记(一)

Posted on 2010-02-18 15:10 S.l.e!ep.¢% 阅读(1802) 评论(0)  编辑 收藏 引用 所属分类: Windows WDM
FileMon源码学习笔记(一)
2008-11-24 09:37

//----------------------------------------------------------------------
//
// HookDrive
//
// Hook the drive specified by determining which device object to
// attach to. The algorithm used here is similar to the one used
// internally by NT to determine which device object a file system request
// is directed at.
//
//----------------------------------------------------------------------
BOOLEAN
HookDrive(
    IN ULONG Drive,
    IN PDRIVER_OBJECT DriverObject
    )
{
    IO_STATUS_BLOCK     ioStatus;
    HANDLE              ntFileHandle;  
    OBJECT_ATTRIBUTES   objectAttributes;
    PDEVICE_OBJECT      fileSysDevice;
    PDEVICE_OBJECT      hookDevice;
    UNICODE_STRING      fileNameUnicodeString;
    PFILE_FS_ATTRIBUTE_INFORMATION fileFsAttributes;
    ULONG               fileFsAttributesSize;
    WCHAR               filename[] = L"
\\DosDevices\\A:\\ ";
    NTSTATUS            ntStatus;
    ULONG               i;
    PFILE_OBJECT        fileObject;
    PHOOK_EXTENSION     hookExtension;
   
    //
    // Is it a legal drive letter?
    //
    if( Drive >= 26 ) {

        return FALSE;
    }

    //
    // Has this drive already been hooked?
    //
    if( DriveHookDevices[Drive] == NULL ) {

        //
        // Frob the name to make it refer to the drive specified in the input
        // parameter.
        //
        filename[12] = (CHAR) ('A'+Drive);

        //
        // We have to figure out what device to hook - first open the volume's
        // root directory
        //
        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( DriveHookDevices[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 );
                DriveHookDevices[ 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 );
        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
        //
        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;
        hookExtension->Hooked       = TRUE;
        hookExtension->Type         = STANDARD;

        //
        // Finally, attach to the device. The second we're successfully attached, we may
        // start receiving IRPs targetted at the device we've hooked.
        //
        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 ));
        }

        //
        // Determine if this is a NTFS drive
        //
        fileFsAttributesSize = sizeof( FILE_FS_ATTRIBUTE_INFORMATION) + MAXPATHLEN;
        hookExtension->FsAttributes = (PFILE_FS_ATTRIBUTE_INFORMATION) ExAllocatePool( NonPagedPool,
                                                                                       fileFsAttributesSize );
        if( hookExtension->FsAttributes &&
            !NT_SUCCESS( IoQueryVolumeInformation( fileObject, FileFsAttributeInformation,
                                                   fileFsAttributesSize, hookExtension->FsAttributes,
                                                   &fileFsAttributesSize ))) {

            //
            // On failure, we just don't have attributes for this file system
            //
            ExFreePool( hookExtension->FsAttributes );
            hookExtension->FsAttributes = NULL;
        }

        //
        // Close the file and update the hooked drive list by entering a
        // pointer to the hook device object in it.
        //
        ObDereferenceObject( fileObject );

        ZwClose( ntFileHandle );

        DriveHookDevices[Drive] = hookDevice;
       
    } else {

        hookExtension = DriveHookDevices[Drive]->DeviceExtension;
        hookExtension->Hooked = TRUE;
    }
    return TRUE;
}

以上摘自FileMon源码,作者在获得要hook的设备的DeviceObject的时候用了以下方式:

ZwCreateFile——》ObReferenceObjectByHandle——》IoGetRelatedDeviceObject

另外,这个设备对象也可以直接用一个函数获得IoGetDeviceObjectPointer,该函数原型如下:

NTSTATUS
IoGetDeviceObjectPointer(
    IN PUNICODE_STRING ObjectName ,
    IN ACCESS_MASK DesiredAccess ,
    OUT PFILE_OBJECT * FileObject ,
    OUT PDEVICE_OBJECT * DeviceObject
    );

直接由名字获得设备对象和文件对象,而该函数内部的实现方式combojiang大侠也给出过c的逆向代码如下: 逆向为c的代码:
NTSTATUS
IoGetDeviceObjectPointer(
     IN PUNICODE_STRING ObjectName,
     IN ACCESS_MASK DesiredAccess,
     OUT PFILE_OBJECT *FileObject,
     OUT PDEVICE_OBJECT *DeviceObject
     )
{
     IO_STATUS_BLOCK ioStatus;
     OBJECT_ATTRIBUTES objectAttributes;
    
     //额外定义出来的栈变量。由于C与汇编的游戏规则不同。
     PFILE_OBJECT fileObject;
     HANDLE fileHandle;
     NTSTATUS status;
    
     InitializeObjectAttributes( &objectAttributes,
                                 ObjectName,
                                 OBJ_KERNEL_HANDLE,
                                 (HANDLE) NULL,
                                 (PSECURITY_DESCRIPTOR) NULL );
                                
    status = ZwOpenFile( &fileHandle,
                          DesiredAccess,
                          &objectAttributes,
                          &ioStatus,
                          0,
                          0x40 );

     if (status >= 0)
     {

          status = ObReferenceObjectByHandle( fileHandle,
                                             0,
                                             IoFileObjectType,
                                             0,
                                             (PVOID *) &fileObject,
                                             0 );
         if (status >= 0)
         {

             *FileObject = fileObject;
             *DeviceObject = IoGetRelatedDeviceObject( fileObject );
         }

         ZwClose( fileHandle );
     }

     return status;
}
与FileMon的源码使用的方法类似,所以FileMon源码里面应该可以用这个函数直接替代,但是原作者没有直接调用这个函数,不知道原因是什么,难道是写FileMon的时候还没提供这个函数,所以要自己来实现吗?


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理