S.l.e!ep.¢%

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

FileMon源码学习笔记(二)

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

FileMon源码中另一个比较疑惑的地方,FileMon创建了两类设备,一个是用于和ring3通信的GUI设备,另一个是hook的过滤设备,但在代码中,当收到发向GUI设备的IRP_MJ_DEVICE_CONTROL时,代码竟是去调用属于hook设备的功能函数,而在这个功能函数里面通过条件判断是否是GUI设备来分别处理,而对于发给GUI设备的其他IRP都在直接在GUI的处理函数中直接处理的,不知道作者这样写是否有什么深层的含义,不过对于我这种初学者来说,这样的写法倒是容易引起混乱,还是不同设备的功能函数,分开来写好一点。下面附上相关代码:

//=========================================================

//GUI设备的功能函数,注意IRP_MJ_DEVICE_CONTROL的实现

//=========================================================

NTSTATUS
FilemonDeviceRoutine(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    PIO_STACK_LOCATION irpStack;
    PVOID               inputBuffer;
    PVOID               outputBuffer;
    ULONG               inputBufferLength;
    ULONG               outputBufferLength;
    ULONG               ioControlCode;

    //
    // Go ahead and set the request up as successful
    //
    Irp->IoStatus.Status      = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;

    //
    // Get a pointer to the current location in the Irp. This is where
    // the function codes and parameters are located.
    //
    irpStack = IoGetCurrentIrpStackLocation (Irp);

    //
    // Get the pointer to the input/output buffer and its length
    //
    inputBuffer        = Irp->AssociatedIrp.SystemBuffer;
    inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outputBuffer       = Irp->AssociatedIrp.SystemBuffer;
    outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    ioControlCode      = irpStack->Parameters.DeviceIoControl.IoControlCode;

    switch (irpStack->MajorFunction) {
    case IRP_MJ_CREATE:

        DbgPrint(("Filemon: IRP_MJ_CREATE\n"));

        //
        // Start the sequence number at 0
        //
        Sequence = 0;
        break;

    case IRP_MJ_CLOSE:

        DbgPrint(("Filemon: IRP_MJ_CLOSE\n"));

        //
        // A GUI is closing communication
        //
        FilterOn = FALSE;

        //
        // If the GUI has no more references to us, reset the output
        // buffers and hash table.
        //
        FilemonResetLog();
        FilemonHashCleanup();

        //
        // Stop capturing drives
        //
        HookDriveSet( 0, DeviceObject->DriverObject );
        UnhookSpecialFs( NPFS );
        UnhookSpecialFs( MSFS );
        break;

    case IRP_MJ_DEVICE_CONTROL:

        //
        // This path will never execute because we have registered a
        // fast I/O path for device control. That means that the fast I/O entry
        // point will ALWAYS be called for Device Control operations
        //
        DbgPrint (("Filemon: IRP_MJ_DEVICE_CONTROL\n"));

        //
        // Get output buffer if its passed as an MDL
        //
        if( Irp->MdlAddress ) {

            outputBuffer = MmGetSystemAddressForMdl( Irp->MdlAddress );
        }

        //
        // Its a request from the GUI. Simply call our fast handler.
        //
        FilemonFastIoDeviceControl( irpStack->FileObject, TRUE,
                                    inputBuffer, inputBufferLength,
                                    outputBuffer, outputBufferLength,
                                    ioControlCode, &Irp->IoStatus, DeviceObject );
        break;
    }

    //
    // Complete the IRP
    //
    IoCompleteRequest( Irp, IO_NO_INCREMENT );
    return STATUS_SUCCESS;  
}

//=========================================================

//hook设备的功能函数,在里面夹杂了处理GUI设备的IRP_MJ_DEVICE_CONTROL的代码

//=========================================================
BOOLEAN
FilemonFastIoDeviceControl(
    IN PFILE_OBJECT FileObject,
    IN BOOLEAN Wait,
    IN PVOID InputBuffer,
    IN ULONG InputBufferLength,
    OUT PVOID OutputBuffer,
    IN ULONG OutputBufferLength,
    IN ULONG IoControlCode,
    OUT PIO_STATUS_BLOCK IoStatus,
    IN PDEVICE_OBJECT DeviceObject
    )
{
    BOOLEAN             retval = FALSE;
    BOOLEAN             logMutexReleased;
    PHOOK_EXTENSION     hookExt;
    PLOG_BUF            oldLog, savedCurrentLog;
    CHAR                fullPathName[MAXPATHLEN], name[PROCNAMELEN], errorBuf[ERRORLEN];
    KIRQL               oldirql;
    LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;
    LARGE_INTEGER       dateTime;

    hookExt = DeviceObject->DeviceExtension;
    if( hookExt->Type == GUIINTERFACE ) {

        //
        // Its a message from our GUI!
        //
        IoStatus->Status      = STATUS_SUCCESS; // Assume success
        IoStatus->Information = 0;      // Assume nothing returned

        switch ( IoControlCode ) {

        case IOCTL_FILEMON_VERSION:

            //
            // Version #
            //
            if( OutputBufferLength >= sizeof(ULONG)) {

                *(ULONG *)OutputBuffer = FILEMONVERSION;
                IoStatus->Information = sizeof(ULONG);

            } else {

                IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
            }           
            break;

        case IOCTL_FILEMON_SETDRIVES:

            //
            // Hook and/or unhook drives
            //
            DbgPrint (("Filemon: set drives\n"));

            if( InputBufferLength >= sizeof(ULONG) &&
                 OutputBufferLength >= sizeof(ULONG)) {

                *(ULONG *)OutputBuffer = HookDriveSet( *(ULONG *)InputBuffer, DeviceObject->DriverObject );
                IoStatus->Information = sizeof(ULONG);

            } else {

                IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
            }
            break;

        case IOCTL_FILEMON_HOOKSPECIAL:

            if( InputBufferLength >= sizeof(FILE_SYSTEM_TYPE )) {

                if( !HookSpecialFs( DeviceObject->DriverObject, *(PFILE_SYSTEM_TYPE) InputBuffer )) {
               
                    IoStatus->Status = STATUS_UNSUCCESSFUL;
                }
            } else {

                IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
            }
            break;

        case IOCTL_FILEMON_UNHOOKSPECIAL:

            if( InputBufferLength >= sizeof(FILE_SYSTEM_TYPE )) {

                UnhookSpecialFs( *(PFILE_SYSTEM_TYPE) InputBuffer );

            } else {

                IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
            }
            break;

        case IOCTL_FILEMON_STOPFILTER:
           
            //
            // Turn off logging
            //
            DbgPrint(("Filemon: stop logging\n"));
            FilterOn = FALSE;
            break;

        case IOCTL_FILEMON_STARTFILTER:
         
            //
            // Turn on logging
            //
            DbgPrint(("Filemon: start logging\n"));
            FilterOn = TRUE;
            break;

        case IOCTL_FILEMON_SETFILTER:

            //
            // Gui is updating the filter functions
            //
            DbgPrint(("Filemon: set filter\n"));

            if( InputBufferLength >= sizeof(FILTER) ) {

                FilterDef = *(PFILTER) InputBuffer;
                FilemonUpdateFilters();

            } else {

                IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
            }
            break;

        case IOCTL_FILEMON_UNLOADQUERY:
#if DBG
            //
            // Is it possible to unload?
            //
            KeAcquireSpinLock( &CountMutex, &oldirql );
            IoStatus->Information = OutstandingIRPCount;

            //
            // Any outstanding Irps?
            //
            if( !OutstandingIRPCount ) {

                //
                // Nope, so don't process anymore
                //
                UnloadInProgress = TRUE;

                KeReleaseSpinLock( &CountMutex, oldirql );

                //
                // Stop capturing drives
                //
                HookDriveSet( 0, DeviceObject->DriverObject );
                UnhookSpecialFs( NPFS );
                UnhookSpecialFs( MSFS );

                //
                // Detach from all devices
                //
                UnloadDetach();

            } else {

                KeReleaseSpinLock( &CountMutex, oldirql );
            }
#else // DBG
            IoStatus->Information = 1;
#endif // DBG
            break;

        case IOCTL_FILEMON_ZEROSTATS:

            //
            // Reset all output buffers
            //
            DbgPrint (("Filemon: zero stats\n"));

            ExAcquireFastMutex( &LogMutex );

            while( CurrentLog->Next ) {

                //
                // Free all but the first output buffer
                //
                oldLog = CurrentLog->Next;
                CurrentLog->Next = oldLog->Next;

                ExFreePool( oldLog );
                NumLog--;
            }

            //
            // Set the output pointer to the start of the output buffer
            //
            CurrentLog->Len = 0;
            Sequence = 0;

            ExReleaseFastMutex( &LogMutex );
            break;

        case IOCTL_FILEMON_GETSTATS:

            //
            // Copy the oldest output buffer to the caller
            //
            DbgPrint (("Filemon: get stats\n"));

    //
            // If the output buffer is too large to fit into the caller's buffer
            //
            if( LOGBUFSIZE > OutputBufferLength ) {

                IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
                return FALSE;
            }

            //
            // Probe the output buffer
            //
            try {                

                ProbeForWrite( OutputBuffer,
                               OutputBufferLength,
                               sizeof( UCHAR ));

            } except( EXCEPTION_EXECUTE_HANDLER ) {

                IoStatus->Status = STATUS_INVALID_PARAMETER;
                return FALSE;
            }           

            //
            // We're okay, lock the buffer pool
            //
            ExAcquireFastMutex( &LogMutex );
            if( CurrentLog->Len || CurrentLog->Next ) {

                //
                // Start output to a new output buffer
                //
                FilemonAllocateLog();

                //
                // Fetch the oldest to give to user
                //
                oldLog = FilemonGetOldestLog();

                if( oldLog != CurrentLog ) {

                    logMutexReleased = TRUE;
                    ExReleaseFastMutex( &LogMutex );

                } else {

                    logMutexReleased = FALSE;
                }

                //
                // Copy it to the caller's buffer
                //
                memcpy( OutputBuffer, oldLog->Data, oldLog->Len );

                //
                // Return length of copied info
                //
                IoStatus->Information = oldLog->Len;

                //
                // Deallocate buffer - unless its the last one
                //
                if( logMutexReleased ) {
                   
                    ExFreePool( oldLog );

                } else {

                    CurrentLog->Len = 0;
                    ExReleaseFastMutex( &LogMutex );                   
                }

            } else {

                //
                // There is no unread data
                //
                ExReleaseFastMutex( &LogMutex );
     IoStatus->Information = 0;
            }
            break;

        default:

            //
            // Unknown control
            //
            DbgPrint (("Filemon: unknown IRP_MJ_DEVICE_CONTROL\n"));
            IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
            break;
        }

        retval = TRUE;

    } else {

        //
        // Its a call for a file system, so pass it through
        //
        if( FASTIOPRESENT( hookExt, FastIoDeviceControl ) ) {
       
            FilemonGetFullPath( FALSE, FileObject, hookExt, fullPathName );
            TIMESTAMPSTART();

            retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoDeviceControl(
                FileObject, Wait, InputBuffer, InputBufferLength, OutputBuffer,
                OutputBufferLength, IoControlCode, IoStatus, hookExt->FileSystem );

            if(hookExt->Hooked) {

                TIMESTAMPSTOP();
                LogRecord( TRUE, NULL, &dateTime, &timeResult,
                           "%s\tFASTIO_DEVICE_CONTROL\t%s\tIOCTL: 0x%X\t%s",
                           FilemonGetProcess( name ), fullPathName,
                           IoControlCode,
                           retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );
            }
        }
    }

    return retval;
}


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