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

📄 filemon.c

📁 文件名:filemon4。34,文件过滤驱动
💻 C
📖 第 1 页 / 共 5 页
字号:

    //
    // Set the completion routine.
    //
    IoSetCompletionRoutine(irp, FilemonQueryFileComplete, 0, TRUE, TRUE, TRUE);

    //
    // Send it to the FSD
    //
    (void) IoCallDriver(DeviceObject, irp);

    //
    // Wait for the I/O
    //
    KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);

    //
    // Done! Note that since our completion routine frees the IRP we cannot 
    // touch the IRP now.
    //
    return NT_SUCCESS( IoStatusBlock.Status );
}


//----------------------------------------------------------------------
//
// FilemonGetFullPath
//
// Takes a fileobject and filename and returns a canonical path,
// nicely formatted, in fullpathname.
//
//----------------------------------------------------------------------
VOID 
FilemonGetFullPath( 
    BOOLEAN createPath, 
    PFILE_OBJECT fileObject, 
    PHOOK_EXTENSION hookExt, 
    PCHAR fullPathName 
    )
{
    ULONG               pathLen, prefixLen, slashes;
    PCHAR               pathOffset, ptr;
    BOOLEAN             gotPath;
    PFILE_OBJECT        relatedFileObject;
    PHASH_ENTRY         hashEntry, newEntry;
    ANSI_STRING         fileName;
    ANSI_STRING         relatedName;
    PFILE_NAME_INFORMATION fileNameInfo;
    FILE_INTERNAL_INFORMATION fileInternalInfo;
    UNICODE_STRING      fullUniName;
    ULONGLONG           mftIndex;

    //
    // Only do this if a GUI is active and filtering is on
    //
    if( fullPathName ) fullPathName[0] = 0;
    if( !FilterOn || !hookExt || !hookExt->Hooked || !fullPathName) {
     
        return;
    }

    //
    // Lookup the object in the hash table to see if a name 
    // has already been generated for it
    //
    KeEnterCriticalRegion();
    ExAcquireResourceSharedLite( &HashResource, TRUE );

    hashEntry = HashTable[ HASHOBJECT( fileObject ) ];
    while( hashEntry && hashEntry->FileObject != fileObject )  {

        hashEntry = hashEntry->Next;
    }

    //
    // Did we find an entry?
    //
    if( hashEntry ) {

        //
        // Yes, so get the name from the entry.
        //
        strcpy( fullPathName, hashEntry->FullPathName );
        ExReleaseResourceLite( &HashResource );
        KeLeaveCriticalRegion();
        return;
    }

    ExReleaseResourceLite( &HashResource );
    KeLeaveCriticalRegion();

    //
    // We didn't find the name in the hash table so let's either ask
    // the file system for it or construct it from the file objects.
    //

    //
    // Calculate prefix length
    //
    switch( hookExt->Type ) {
    case NPFS: 
        prefixLen = NAMED_PIPE_PREFIX_LENGTH;
        break;
    case MSFS: 
        prefixLen = MAIL_SLOT_PREFIX_LENGTH;
        break;
    default: 
        if( !fileObject ||
            fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM ) {

            prefixLen = 0;

        } else {

            prefixLen = 2; // "C:"
        }
        break;
    }

    //
    // If there's no file object, we can't even ask for a name.
    //
    if( !fileObject ) { 

        if( hookExt->Type == NPFS )      strcpy( fullPathName, NAMED_PIPE_PREFIX );
        else if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );
        else                             sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
        return;
    }

    //
    // Initialize variables
    //
    fileName.Buffer = NULL;
    relatedName.Buffer = NULL;
    gotPath = FALSE;

    //
    // Check for special case first: NTFS volume and a file object
    // with no name. It might be a metadata file that we "know" the name of. This
    // special case also stops us from querying NTFS for the name of a metadata
    // file on versions of NTFS prior to Whistler, which is a good thing since
    // that causes hangs and crashes. On Whistler metadata files have file names.
    //
    if( !fileObject->FileName.Buffer && hookExt->FsAttributes &&
        !memcmp( hookExt->FsAttributes->FileSystemName, L"NTFS", sizeof(L"NTFS")-sizeof(WCHAR))) {

        //
        // The only file that is opened without a name is a volume
        //
        if( createPath ) {

            sprintf( fullPathName, "%C:", hookExt->LogicalDrive );

            //
            // Return right here without inserting this into the hash table, since this might
            // be the cleanup path of a metadata file and we can retrieve the metada's index
            // at a later point.
            //
            return;

        } else if( FilemonQueryFile( hookExt->FileSystem, fileObject, FileInternalInformation,
                              &fileInternalInfo, sizeof( fileInternalInfo ))) {
            
            //
            // Use the name in the metadata name index
            //
            mftIndex = fileInternalInfo.IndexNumber.QuadPart & ~0xF0000000;
            if( mftIndex <= MAX_NTFS_METADATA_FILE ) {

                sprintf( fullPathName, "%C:\\%s", hookExt->LogicalDrive, NtfsMetadataFileNames[ mftIndex ] );
                gotPath = TRUE;
            }                
        } 
    }

    //
    // If we are not in the create path, we can ask the file system for the name. If we
    // are in the create path, we can't ask the file system for the name of the file object, since
    // the file system driver hasn't even seen the file object yet.
    //
    if( !gotPath && !createPath ) {

        //
        // Ask the file system for the name of the file, which its required to be
        // able to provide for the Win32 filename query function. We could use the
        // undocumented ObQueryNameString, but then we'd have to worry about
        // re-entrancy issues, since that call generates the IRP that we create
        // manually here. Since we send the IRP to the FSD below us, we don't need
        // to worry about seeing the IRP in our dispatch entry point. This can fail
        // in some cases, so we fall back on constructing the name ourselves if
        // we have to.
        //
        fileNameInfo = (PFILE_NAME_INFORMATION) ExAllocatePool( NonPagedPool, 
                                                                MAXPATHLEN*sizeof(WCHAR) );

        if( fileNameInfo && 
            FilemonQueryFile(hookExt->FileSystem, fileObject, FileNameInformation, 
                             fileNameInfo, (MAXPATHLEN - prefixLen - 1)*sizeof(WCHAR) )) {

            fullUniName.Length = (SHORT) fileNameInfo->FileNameLength;
            fullUniName.Buffer = fileNameInfo->FileName;
            if( NT_SUCCESS( RtlUnicodeStringToAnsiString( &fileName, &fullUniName, TRUE ))) { 

                fullPathName[ fileName.Length + prefixLen ] = 0;

                if( hookExt->Type == NPFS ) {
                    
                    strcpy( fullPathName, NAMED_PIPE_PREFIX );

                } else if( hookExt->Type == MSFS ) {

                    strcpy( fullPathName, MAIL_SLOT_PREFIX );

                } else if( fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM ) {

                    sprintf( fullPathName, "%C:", hookExt->LogicalDrive );

                } else {
                
                    //
                    // No prefix for network devices
                    //
                }

                memcpy( &fullPathName[prefixLen], fileName.Buffer, fileName.Length );
                gotPath = TRUE;
                RtlFreeAnsiString( &fileName );
                fileName.Buffer = NULL;
            }
        } 
        if( fileNameInfo ) ExFreePool( fileNameInfo );
    }

    //
    // If we don't have a name yet then we are in the create path, or we failed
    // when we asked the file system for the name. In that case we'll go ahead
    // and construct the name based on file object names.
    //
    if( !gotPath ) {

        //
        // If there is no file name at this point, just return "DEVICE" to indicate
        // raw access to a device
        //
        if( !fileObject->FileName.Buffer ) {

            if( hookExt->Type == NPFS )      strcpy( fullPathName, NAMED_PIPE_PREFIX );
            else if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );
            else                             sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
            return;
        }
    
        //
        // Create the full path name. First, calculate the length taking into 
        // account space for seperators and the leading prefix
        //
        if( !NT_SUCCESS( RtlUnicodeStringToAnsiString( &fileName, &fileObject->FileName, TRUE ))) {

            if( hookExt->Type == NPFS )      sprintf( fullPathName, "%s: <Out of Memory>", NAMED_PIPE_PREFIX );
            else if( hookExt->Type == MSFS ) sprintf( fullPathName, "%s: <Out of Memory>", MAIL_SLOT_PREFIX );
            else                             sprintf( fullPathName, "%C: <Out of Memory>", hookExt->LogicalDrive );
            return;
        }

        pathLen = fileName.Length + prefixLen;
        relatedFileObject = fileObject->RelatedFileObject;
    
        //
        // Only look at related file object if this is a relative name
        //
        if( fileObject->FileName.Buffer[0] != L'\\' && 
            relatedFileObject && relatedFileObject->FileName.Length ) {
	        
			if( !NT_SUCCESS( RtlUnicodeStringToAnsiString( &relatedName, &relatedFileObject->FileName, TRUE ))) {

                if( hookExt->Type == NPFS )      sprintf( fullPathName, "%s: <Out of Memory>", NAMED_PIPE_PREFIX );
                else if( hookExt->Type == MSFS ) sprintf( fullPathName, "%s: <Out of Memory>", MAIL_SLOT_PREFIX );
                else                             sprintf( fullPathName, "%C: <Out of Memory>", hookExt->LogicalDrive );
                RtlFreeAnsiString( &fileName );
                return;
            }
            pathLen += relatedName.Length+1;
        }

        //
        // Add the drive letter first at the front of the name
        //
        if( hookExt->Type == NPFS )      strcpy( fullPathName, NAMED_PIPE_PREFIX );
        else if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );
        else if( fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM ) {

            sprintf( fullPathName, "%C:", hookExt->LogicalDrive );
        }

        //
        // If the name is too long, quit now
        //
        if( pathLen >= MAXPATHLEN ) {
            
            strcat( fullPathName, " <Name Too Long>" );

        } else {
    
            //
            // Now we can build the path name
            //
            fullPathName[ pathLen ] = 0;
            
            pathOffset = fullPathName + pathLen - fileName.Length;
            memcpy( pathOffset, fileName.Buffer, fileName.Length + 1 );
    
            if( fileObject->FileName.Buffer[0] != L'\\' && 
                relatedFileObject && relatedFileObject->FileName.Length ) {

                //
                // Copy the component, adding a slash separator
                //
                *(pathOffset - 1) = '\\';
                pathOffset -= relatedName.Length + 1;
                    
                memcpy( pathOffset, relatedName.Buffer, relatedName.Length );

                //
                // If we've got to slashes at the front zap one
                //
                if( pathLen > 3 && fullPathName[2] == '\\' && fullPathName[3] == '\\' )  {
                    
                    strcpy( fullPathName + 2, fullPathName + 3 );
                }
            }
        }  
    } 
    if( fileName.Buffer ) RtlFreeAnsiString( &fileName );
    if( relatedName.Buffer ) RtlFreeAnsiString( &relatedName );

    //
    // Network redirector names already specify a share name that we 
    // have to strip:
    // 
    //     \X:\computer\share\realpath
    //
    // And we want to present:
    //
    //     X:\realpath
    //
    // to the user.
    //
    if( fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM &&
        strlen( fullPathName ) >= strlen("\\X:\\") ) {

        //
        // If this is Win2k the name is specified like this:
        //
        //    \;X:0\computer\share\realpath
        //
        // so we have to handle that case as well
        //
        if( fullPathName[1] == ';' ) {
            
            //
            // Win2K-style name. Grab the drive letter
            // and skip over the share
            //
            fullPathName[0] = fullPathName[2];
            fullPathName[1] = ':';
            fullPathName[2] = '\\';

            //
            // The third slash after the drive is the
            // start of the real path (we start scanning
            // at the ':' since we don't want to make assumptions
            // about the length of the number).
            //
            slashes = 0;
            ptr = &fullPathName[3];
            while( *ptr && slashes != 3 ) {
                
                if( *ptr == '\\' ) slashes++;
                ptr++;
            }
            strcpy( &fullPathName[3], ptr );

        } else if( fullPathName[2] == ':' ) {

            //
            // NT 4-style name. Skip the share name 
            //
            fullPathName[0] = fullPathName[1];
            fullPathName[1] = ':';
            fullPathName[2] = '\\';
                
            //
            // The second slash after the drive's slash (x:\)
            // is the start of the real path
            //
            slashes = 0;
            ptr = &fullPathName[3];
            while( *ptr && slashes != 3 ) {
                
                if( *ptr == '\\' ) slashes++;
                ptr++;
            }
            strcpy( &fullPathName[3], ptr );

        } else {

            //
            // Its a UNC path, so add a leading slash
            //
            RtlMoveMemory( &fullPathName[1], fullPathName, strlen( fullPathName ) + 1);
            fullPathName[0] = '\\';
        }
    }

    //
    // Allocate a hash entry
    //
    newEntry = ExAllocatePool( NonPagedPool, 
                               sizeof(HASH_ENTRY ) + strlen( fullPathName ) + 1);

    //
    // If no memory for a new entry, oh well.
    //
    if( newEntry ) {

        //
        // Fill in the new entry 
        //
        newEntry->FileObject = fileObject;
        strcpy( newEntry->FullPathName, fullPathName );

        //
        // Put it in the hash table
        //
        KeEnterCriticalRegion();
        ExAcquireResourceExclusiveLite( &HashResource, TRUE );

        newEntry->Next = HashTable[ HASHOBJECT(fileObject) ];
        HashTable[ HASHOBJECT(fileObject) ] = newEntry;	

        ExReleaseResourceLite( &HashResource );
        KeLeaveCriticalRegion();
    }
}


//----------------------------------------------------------------------
//
// FilemonGetProcessNameOffset
//
// In an effort to remain version-independent, rather than using a
// hard-coded into the KPEB (Kernel Process Environment Block), we
// scan the KPEB looking for the name, which should match that
// of the system process. This is because we are in the system process'
// context in DriverEntry, where this is called.
//
//----------------------------------------------------------------------

⌨️ 快捷键说明

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