2014年7月10日星期四

minifilter-DirectoryControl-QueryDirectory

#include <fltKernel.h>
#include <windef.h>

PFLT_FILTER gFilterHandle;

#define TAG 'tset' //test

/*
文件名就叫:minifilter-QueryDirectory.c吧!
框架是DirectoryControl,主要写的是QueryDirectory,NotifyDirectory与此类似。

参考:
http://msdn.microsoft.com/en-us/library/windows/hardware/ff548658(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff544695(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff540314(v=vs.85).aspx

made by correy
made at 2014.07.09
homepage:http://correy.webs.com
*/

FLT_POSTOP_CALLBACK_STATUS DirectoryControlPostOperation (__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in_opt PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags)
{
    PVOID p = NULL;  
    PFLT_FILE_NAME_INFORMATION    pfni;
    NTSTATUS                      status;

    UNREFERENCED_PARAMETER( CompletionContext );  

    //IRP_MJ_DIRECTORY_CONTROL is an IRP-based operation.
    if (!FLT_IS_IRP_OPERATION(Data))
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    /*
    The file system driver should check the minor function code to determine which directory control operation is requested. 

    One of the following:
    IRP_MN_NOTIFY_CHANGE_DIRECTORY 对应NotifyDirectory结构。
    IRP_MN_QUERY_DIRECTORY 对应QueryDirectory结构即(Union component used for IRP_MN_QUERY_DIRECTORY operations.)
    */
    if (Data->Iopb->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
    {
        return FLT_POSTOP_FINISHED_PROCESSING;//The filter driver must pass this IRP down to the next-lower driver on the stack.
    }

    if( FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING ))
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    if(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length <= 0)
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    if(!NT_SUCCESS(Data->IoStatus.Status))
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }
    
    if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL) {
        p = MmGetSystemAddressForMdlSafe(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress, NormalPagePriority);            
    }  else {
        p = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;             
    } 
    if(p == NULL) {
        return FLT_POSTOP_FINISHED_PROCESSING;  
    }

    //这个不是目录。
    //KdPrint(("查询的目录:%wZ\n", Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName));

    /*
    FltGetFileNameInformation cannot get file name information if the TopLevelIrp field of the current thread is not NULL, 
    because the resulting file system recursion could cause deadlocks or stack overflows. (For more information about this issue, see IoGetTopLevelIrp.) 
    FltGetFileNameInformation cannot get file name information in the paging I/O path. 
    FltGetFileNameInformation cannot get file name information in the post-close path. 
    FltGetFileNameInformation cannot get the short name of a file in the pre-create path. 
    */
    if (FlagOn(Data->Iopb->IrpFlags, IRP_PAGING_IO) || FlagOn(Data->Iopb->IrpFlags, IRP_SYNCHRONOUS_PAGING_IO) || IoGetTopLevelIrp()) //IRP_NOCACHE
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &pfni);    
    if (!NT_SUCCESS( status )) 
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    status = FltParseFileNameInformation(pfni);
    if (!NT_SUCCESS( status )) 
    {
        FltReleaseFileNameInformation(pfni); 
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    KdPrint(("查询的目录:%wZ\n", &pfni->Name));

    //FltReleaseFileNameInformation(pfni); 

    switch(Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass)
    {  
    case FileBothDirectoryInformation://XP走这里了,server 2008也走这里了。
        {
            PFILE_BOTH_DIR_INFORMATION pfbdi = (PFILE_BOTH_DIR_INFORMATION)p;
            UNICODE_STRING FileName = {0};

            if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileIndex == SL_INDEX_SPECIFIED)//SL_RESTART_SCAN SL_RETURN_SINGLE_ENTRY
            {
                /*
                注意有的是一下子枚举完毕,有的是一个一个的枚举。
                下同。
                */
            }

            KdPrint(("查询目录的类型:FileBothDirectoryInformation\n"));

            do
            { 
                FileName.Buffer = pfbdi->FileName;
                FileName.Length = (USHORT)pfbdi->FileNameLength;
                FileName.MaximumLength = FileName.Length;

                if (pfbdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                    KdPrint(("目录:%wZ\n", &FileName));
                } else {
                    KdPrint(("文件:%wZ\n", &FileName));
                }

                pfbdi = (PFILE_BOTH_DIR_INFORMATION)((PCHAR)(pfbdi) + pfbdi->NextEntryOffset);
            } while( pfbdi->NextEntryOffset != 0 );            
        }

        KdPrint(("\n"));
        break;
    case FileDirectoryInformation://win 7走这里了。走这里的时机不太清楚,机会很少。      
        {
            PFILE_DIRECTORY_INFORMATION  pfdi = (PFILE_DIRECTORY_INFORMATION )p;
            UNICODE_STRING FileName = {0};

            KdPrint(("查询目录的类型:FileDirectoryInformation\n\n"));

            do
            { 
                FileName.Buffer = pfdi->FileName;
                FileName.Length = (USHORT)pfdi->FileNameLength;
                FileName.MaximumLength = FileName.Length;

                if (pfdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                    KdPrint(("目录:%wZ\n", &FileName));
                } else {
                    KdPrint(("文件:%wZ\n", &FileName));
                }

                pfdi = (PFILE_DIRECTORY_INFORMATION )((PCHAR)(pfdi) + pfdi->NextEntryOffset);
            } while( pfdi->NextEntryOffset != 0 );            
        }

        KdPrint(("\n"));
        break;
    case FileFullDirectoryInformation://server 2008的dir /a 走这里了。
        {
            PFILE_FULL_DIR_INFORMATION  pffdi = (PFILE_FULL_DIR_INFORMATION )p;
            UNICODE_STRING FileName = {0};

            KdPrint(("查询目录的类型:FileFullDirectoryInformation\n"));

            do
            { 
                FileName.Buffer = pffdi->FileName;
                FileName.Length = (USHORT)pffdi->FileNameLength;
                FileName.MaximumLength = FileName.Length;

                if (pffdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                    KdPrint(("目录:%wZ\n", &FileName));
                } else {
                    KdPrint(("文件:%wZ\n", &FileName));
                }

                pffdi = (PFILE_FULL_DIR_INFORMATION )((PCHAR)(pffdi) + pffdi->NextEntryOffset);
            } while( pffdi->NextEntryOffset != 0 );            
        }

        KdPrint(("\n"));
        break;
    case FileIdBothDirectoryInformation://server 2008也走这里了。
        {
            PFILE_ID_BOTH_DIR_INFORMATION  pfibdi = (PFILE_ID_BOTH_DIR_INFORMATION )p;
            UNICODE_STRING FileName = {0};

            KdPrint(("查询目录的类型:FileIdBothDirectoryInformation\n"));

            do
            { 
                FileName.Buffer = pfibdi->FileName;
                FileName.Length = (USHORT)pfibdi->FileNameLength;
                FileName.MaximumLength = FileName.Length;

                if (pfibdi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                    KdPrint(("目录:%wZ\n", &FileName));
                } else {
                    KdPrint(("文件:%wZ\n", &FileName));
                }

                pfibdi = (PFILE_ID_BOTH_DIR_INFORMATION )((PCHAR)(pfibdi) + pfibdi->NextEntryOffset);
            } while( pfibdi->NextEntryOffset != 0 );            
        }
        KdPrint(("\n"));
        break;
    case FileIdFullDirectoryInformation://这个及上面的都有FileAttributes属性。
        KdPrint(("查询目录的类型:FileIdFullDirectoryInformation\n\n"));
        break;
    case FileNamesInformation://XP有时也走这里,如启动一个程序。win 7 也走这里了。
        {
            PFILE_NAMES_INFORMATION  pfni2 = (PFILE_NAMES_INFORMATION )p;
            UNICODE_STRING FileName = {0};
            UNICODE_STRING FilePathName = {0};
            FILE_STANDARD_INFORMATION fsi = {0};
            IO_STATUS_BLOCK  IoStatusBlock ={0};
            HANDLE  FileHandle = 0;//(HANDLE)-1;
            OBJECT_ATTRIBUTES ob = {0};
            UNICODE_STRING dot  = RTL_CONSTANT_STRING(L".");
            UNICODE_STRING double_dot  = RTL_CONSTANT_STRING(L"..");

            KdPrint(("查询目录的类型:FileNamesInformation\n"));

            FilePathName.MaximumLength = MAX_PATH;//(USHORT)BufferSizeNeeded + 2;
            FilePathName.Buffer = ExAllocatePoolWithTag( NonPagedPool, FilePathName.MaximumLength, TAG );
            if (FilePathName.Buffer == NULL) {
                break;
            }
            RtlZeroMemory(FilePathName.Buffer, FilePathName.MaximumLength);

            do
            { 
                FileName.Buffer = pfni2->FileName;
                FileName.Length = (USHORT)pfni2->FileNameLength;
                FileName.MaximumLength = FileName.Length;

                RtlCopyUnicodeString(&FilePathName, &pfni->Name); 

                if (FilePathName.Buffer[FilePathName.Length/2 -1] != L'\\')
                {
                    status = RtlAppendUnicodeToString( &FilePathName, L"\\");
                    if (!NT_SUCCESS( status )) {
                        break;
                    } 
                }
                if (RtlCompareUnicodeString(&FileName, &dot, TRUE) == 0 || RtlCompareUnicodeString(&FileName, &double_dot, TRUE) == 0)
                {
                    FilePathName.Length -= 2;
                }
                else
                {
                    status = RtlAppendUnicodeStringToString( &FilePathName, &FileName);
                    if (!NT_SUCCESS( status )) {
                        break;
                    }
                }
                InitializeObjectAttributes(&ob, &FilePathName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
                status = ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE  | FILE_SYNCHRONOUS_IO_NONALERT);                
                if (!NT_SUCCESS (status)) 
                {
                    status = ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, FILE_SHARE_READ, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
                    if (!NT_SUCCESS (status))
                    {
                        KdPrint(("\nZwOpenFile fail %wZ with 0x%x.\n", &FilePathName, status));//pagefile.sys和HIVE文件会打不开。
                        if ( status == STATUS_OBJECT_NAME_NOT_FOUND)  {
                            KdPrint(("file does not exist\n"));
                        }
                        if (IoStatusBlock.Information == FILE_DOES_NOT_EXIST ) {
                            KdPrint(("file does not exist\n"));
                        }
                        break;
                    }
                }

                //status = FltQueryInformationFile(FltObjects->Instance, FltObjects->FileObject, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation, &LengthReturned);
                status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
                if (!NT_SUCCESS( status )) 
                {
                    if (FileHandle)
                    {
                        status = ZwClose(FileHandle);
                        if (!NT_SUCCESS (status)) 
                        {
                            KdPrint(("ZwClose fail with 0x%x.\n", status));
                        }
                    }
                    break;
                }

                if (fsi.Directory == TRUE )
                {
                    KdPrint(("目录的名字:%wZ\n", &FilePathName));//注意这个有几个没有显示:点和双点及汉字的等。
                }
                else
                {
                    KdPrint(("文件的名字:%wZ\n", &FilePathName));//FilePathName  FileName
                }     

                if (FileHandle)
                {
                    status = ZwClose(FileHandle);
                    if (!NT_SUCCESS (status)) 
                    {
                        KdPrint(("ZwClose fail with 0x%x.\n", status));
                    }
                }

                pfni2 = (PFILE_NAMES_INFORMATION )((PCHAR)(pfni2) + pfni2->NextEntryOffset);
            } while( pfni2->NextEntryOffset != 0 );

            ExFreePoolWithTag(FilePathName.Buffer, TAG);
        }

        KdPrint(("\n"));
        break;
        //这两个对应的结构没有NextEntryOffset成员,并且上面的结构的第一个成员都是NextEntryOffset。
        //case FileObjectIdInformation:
        //    break;
        //case FileReparsePointInformation:
        //    break;
    default://其实还有更多,不信你看头文件,注意对应的结构的处理。
        KdPrint(("查询目录的类型:FileInformationClass:%d\n", Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass));
        break;
    }   

    FltReleaseFileNameInformation(pfni); 
    return FLT_POSTOP_FINISHED_PROCESSING;
}


CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
    { IRP_MJ_DIRECTORY_CONTROL,  0, 0, DirectoryControlPostOperation},
    { IRP_MJ_OPERATION_END }
};


#pragma PAGEDCODE
NTSTATUS PtInstanceQueryTeardown (__in PCFLT_RELATED_OBJECTS FltObjects,__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
{
    return STATUS_SUCCESS;
}


#pragma PAGEDCODE//#pragma alloc_text(PAGE, PtUnload)
NTSTATUS PtUnload (__in FLT_FILTER_UNLOAD_FLAGS Flags)
{
    FltUnregisterFilter( gFilterHandle );
    return STATUS_SUCCESS;
}


CONST FLT_REGISTRATION FilterRegistration = {
    sizeof( FLT_REGISTRATION ),         //  Size
    FLT_REGISTRATION_VERSION,           //  Version
    0,                                  //  Flags
    NULL,                               //  Context
    Callbacks,                          //  Operation callbacks
    PtUnload,                           //  MiniFilterUnload
    NULL,                               //  InstanceSetup
    PtInstanceQueryTeardown,            //  InstanceQueryTeardown
    NULL,                               //  InstanceTeardownStart
    NULL,                               //  InstanceTeardownComplete
    NULL,                               //  GenerateFileName
    NULL,                               //  GenerateDestinationFileName
    NULL                                //  NormalizeNameComponent
};


DRIVER_INITIALIZE DriverEntry;
#pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE
NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS status;

    UNREFERENCED_PARAMETER( RegistryPath );

    KdBreakPoint();

    status = FltRegisterFilter( DriverObject, &FilterRegistration, &gFilterHandle );
    if (!NT_SUCCESS( status )) //FLT_ASSERT( NT_SUCCESS( status ) );
    {        
        return status;
    }

    status = FltStartFiltering( gFilterHandle );
    if (!NT_SUCCESS( status )) {
        FltUnregisterFilter( gFilterHandle );
    }

    return status;
}

没有评论:

发表评论