首页
社区
课程
招聘
[求助]求有经验的文件重定向驱动开发者帮助
发表于: 2015-5-26 08:22 6962

[求助]求有经验的文件重定向驱动开发者帮助

2015-5-26 08:22
6962
按照WDK例子 simrep 做了个微过滤驱动的文件重定向例子,处理了 IRP_MJ_CREATE 规则如下:
1. 获取源文件名
2. 计算源文件名定向到的文件名 (如 C:\a.txt -> d:\a.txt)
3. 判断定向文件(D:\a.txt)是否存在,如果存在,则 Reparse
4. 如果定向文件不存在,判断是否有写权限,如无写权限, passthrough
5. 如果有写权限,判断源文件(C:\a.txt)是否存在,如果不存在,则直接 Reparse 到 定向文件(D:\a.txt)
6. 如果源文件存在,则将源文件先复制到目标文件,再 Reparse

只处理 IRP_MJ_CREATE 后,一些简单的程序能正常工作,并能正常实现定向,但一些大型点的程序启动会有问题,我现在能想到的是目录查询会有问题,如将 C:\a.txt 定向到 D:\a.txt 后,如果源文件并不存在,程序通过枚举目录而发现文件肯定找不到 a.txt ,可能会影响程序正常运行,那么问题来了:
1. 使用微过滤如何做目录的合并(即在查询源目录的时候,把定向目录里定向过的文件也合并过去,并且不能有两份,如 C:\ 下本来有 b.txt ,无 a.txt,定向 a.txt 到 D:\a.txt 后,进程查询 C:\ 目录能查询到两个文件:a.txt b.txt,再如 C:\下本来就有 a.txt ,又定向了一份到 D:\a.txt ,进程查询 C:\ 目录时只能查到一个文件,a.txt)
2. 其他的还有哪些重要的IRP是必须处理才能兼容大型程序的。

望高手不吝赐教

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 185
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
但一些大型点的程序启动会有问题


首先,你应该去确认是出了什么问题,报了什么错。  可以跟踪一下应用程序。

知道了问题,再对应的去修改。 你现在感觉就是在猜。
2015-5-26 09:21
0
雪    币: 8
活跃值: (58)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
mark一个,同求
2015-5-26 09:28
0
雪    币: 55
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
我已经确定需要合并目录了,过滤IRP_MJ_DIRECTORY_CONTROL.IRP_MN_QUERY_DIRECTORY 目前做法是这样的:
过滤原有查询,当原有查询返回 STATUS_NO_MORE_FILES 时,打开定向目录,并将返回结果改为 STATUS_SUCCESS。据调试如果返回 STATUS_SUCCESS 上层应该是会继续查询的,当继续查询被我们捕获到后,我们再查询定向的目录,一个细节是原目录和定向目录中都有一个文件时,将原目录中文件隐藏。
如原目录 C:\test 下有 a.txt b.txt 定向目录 D:\ 下有 b.txt c.txt,当查询到 a.txt b.txt 时将 b.txt 擦除,继续查询 D:\ 得到 b.txt c.txt 则总的结果是 a.txt b.txt c.txt
整个合并过程在XP上工作观察是稳定的,但在 win7 上将返回值改为 STATUS_SUCCESS 后上层并没有继续查,原因不明。
核心代码如下:

static
FLT_PREOP_CALLBACK_STATUS
_SbPreDirectoryControl(
    IN PFLT_CALLBACK_DATA Data,
    IN PCFLT_RELATED_OBJECTS FltObjects,
    IN PVOID* CompletionContext
    )
{
    FLT_PREOP_CALLBACK_STATUS FltStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
    UNICODE_STRING Volume = {0};

    do
    {
        PSB_FILEOBJ_DESC FileobjDesc = NULL;

        if (IRP_MN_QUERY_DIRECTORY != Data->Iopb->MinorFunction)
        {
            break;
        }

        if (!SbIsSandboxProcess((ULONG)PsGetCurrentProcessId()))
        {
            break;
        }

        // 如果记录的有定向目录,则说明已经在合并中了,让后回调去完成查询
        FileobjDesc = _SbGetFileobjDesc(Data->Iopb->TargetFileObject);
        if (FileobjDesc && FileobjDesc->DirectoryHandle)
        {
            KdPrint(("found merge query, send to post callback\n"));
            FltStatus = FLT_PREOP_SUCCESS_WITH_CALLBACK;
            break;
        }

        if (!NT_SUCCESS(IoVolumeDeviceToDosName(Data->Iopb->TargetFileObject->DeviceObject, &Volume)) ||
            Volume.Length < 4 ||
            Volume.Buffer[1] != L':'
            )
        {
            break;
        }

        // 沙箱中文件查询则 passthrough
        if (SbIsSandboxVolume(Volume.Buffer[0]))
        {
            break;
        }
        
        // 否则就让它走 Post Callback (好合并目录和隐藏原目录中文件)
        FltStatus = FLT_PREOP_SUCCESS_WITH_CALLBACK;
    } while (FALSE);

    if (Volume.Buffer)
    {
        ExFreePool((VOID*)Volume.Buffer);
    }

    return FltStatus;
}

static
NTSTATUS
_SbPrepareMergeDirectory(
    IN OUT PFLT_CALLBACK_DATA Data,
    IN WCHAR SbVolume,
    IN PUNICODE_STRING OriginalDirectory
    )
{
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
    PSB_FILEOBJ_DESC FileobjDesc = NULL;

    do
    {
        IO_STATUS_BLOCK IoStatus = {0};
        OBJECT_ATTRIBUTES ObjAttrib = {0};
        FileobjDesc = (PSB_FILEOBJ_DESC)ExAllocatePoolWithTag(NonPagedPool, sizeof(SB_FILEOBJ_DESC), SB_MEM_TAG);
        if (!FileobjDesc)
        {
            break;
        }

        RtlZeroMemory(FileobjDesc, sizeof(SB_FILEOBJ_DESC));
        FileobjDesc->FileObject = Data->Iopb->TargetFileObject;
        RtlInitEmptyUnicodeString(&(FileobjDesc->OriginalPath), FileobjDesc->OriginalBuff, SB_MAX_NAME_LEN * sizeof(WCHAR));
        RtlInitEmptyUnicodeString(&(FileobjDesc->RedirectPath), FileobjDesc->RedirectBuff, SB_MAX_NAME_LEN * sizeof(WCHAR));

        RtlUnicodeStringCopy(&(FileobjDesc->OriginalPath), OriginalDirectory);
        _SbGetRedirectPath(OriginalDirectory, SbVolume, &(FileobjDesc->RedirectPath));

        InitializeObjectAttributes(&ObjAttrib, &(FileobjDesc->RedirectPath), OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
        Status = ZwCreateFile(
            &(FileobjDesc->DirectoryHandle),
            GENERIC_READ,
            &ObjAttrib,
            &IoStatus,
            NULL,
            0,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            FILE_OPEN,
            FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE,
            NULL,
            0
            );
    } while (FALSE);

    if (!NT_SUCCESS(Status))
    {
        if (FileobjDesc)
        {
            ExFreePoolWithTag((PVOID)FileobjDesc, SB_MEM_TAG);
        }
    }
    else
    {
        _SbRecordFileObject(FileobjDesc);
    }

    return Status;
}

static
FLT_POSTOP_CALLBACK_STATUS
_SbPostDirectoryControl(
    IN OUT PFLT_CALLBACK_DATA Data,
    IN PCFLT_RELATED_OBJECTS FltObjects,
    IN PVOID CompletionContext,
    IN FLT_POST_OPERATION_FLAGS Flags
    )
{
    FLT_POSTOP_CALLBACK_STATUS FltStatus = FLT_POSTOP_FINISHED_PROCESSING;
    PFLT_FILE_NAME_INFORMATION NameInfo = NULL;
    PVOID SafeBuffer = NULL;

    do
    {
        PSB_FILEOBJ_DESC FileobjDesc = NULL;
        BOOLEAN IsDirectory = FALSE;
        WCHAR FirstSbVolume = SbFirstSandboxVolume();
        if (!FirstSbVolume)
        {
            break;
        }

        if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass != FileBothDirectoryInformation &&
            Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass != FileIdBothDirectoryInformation
            )
        {
            break;
        }

        if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName &&
            Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName->Length
            )
        {
            USHORT Index = 0;
            BOOLEAN ContainsAsterisk = FALSE;
            for (Index = 0; Index < Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName->Length / 2; ++Index)
            {
                if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName->Buffer[Index] == L'*')
                {
                    ContainsAsterisk = TRUE;
                    break;
                }
            }

            // 没有 * 说明找的非常精确,如就找 C:\ 下的 a.txt ,精确查找时,直接放过
            if (!ContainsAsterisk)
            {
                break;
            }
        }

        // 如果有映射目录句柄,则说明已经在合并目录,则直接查询定向目录即可
        FileobjDesc = _SbGetFileobjDesc(Data->Iopb->TargetFileObject);
        if (FileobjDesc && FileobjDesc->DirectoryHandle)
        {
            KdPrint(("query redirect path\n"));
            Data->IoStatus.Status = ZwQueryDirectoryFile(
                FileobjDesc->DirectoryHandle,
                NULL,
                NULL,
                NULL,
                &Data->IoStatus,
                Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer,
                Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length,
                Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass,
                FALSE,
                Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName,
                FALSE
                );

            break;
        }

        if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL)
        {
            SafeBuffer = MmGetSystemAddressForMdlSafe(
                Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress,
                NormalPagePriority
                );
        }
        else
        {
            SafeBuffer = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
        }

        if (!SafeBuffer)
        {
            break;
        }

        if (!NT_SUCCESS(FltGetFileNameInformation(
            Data,
            FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT,
            &NameInfo
            )))
        {
            break;
        }

        KdPrint(("_SbPostDirectoryControl %wZ\n", &NameInfo->Name));
        if (STATUS_NO_MORE_FILES == Data->IoStatus.Status)
        {
            // 原查询结束了,准备开始定向目录的合并工作
            KdPrint(("Original Query finished\n"));
            if (NT_SUCCESS(_SbPrepareMergeDirectory(Data, FirstSbVolume, &NameInfo->Name)))
            {
                // 将状态置为 STATUS_SUCCESS 则系统会继续往下查
                Data->IoStatus.Status = STATUS_SUCCESS;
                // 如果设置为成功,则本次的缓冲区仍会被上层使用,会导致查询结果叠加,应设置本次返回长度为0
                // Data->IoStatus.Information = 0;
                // 经调试设置 Data->IoStatus.Information = 0; 还不行,将文件查询相关结构清零似乎可以
                Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length = 0;
                if (FileBothDirectoryInformation == Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass)
                {
                    RtlZeroMemory(SafeBuffer, sizeof(FILE_BOTH_DIR_INFORMATION));
                }
                else
                {
                    RtlZeroMemory(SafeBuffer, sizeof(FILE_ID_BOTH_DIR_INFORMATION));
                }
            }

            break;
        }
        else if (!NT_SUCCESS(Data->IoStatus.Status))
        {
            break;
        }

        // 从原来的查询结果中隐藏沙箱中已经有的部分
        if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass == FileBothDirectoryInformation)
        {
            _SbProcessFileBothDirectoryInformation(
                FirstSbVolume,
                &NameInfo->Name,
                (PFILE_BOTH_DIR_INFORMATION)SafeBuffer,
                Data
                );
        }
        else
        {
            _SbProcessFileIdBothDirectoryInformation(
                FirstSbVolume,
                &NameInfo->Name,
                (PFILE_ID_BOTH_DIR_INFORMATION)SafeBuffer,
                Data
                );
        }
    } while (FALSE);

    if (NameInfo)
    {
        FltReleaseFileNameInformation(NameInfo);
    }

    return FltStatus;
}

2015-5-26 19:33
0
雪    币: 55
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
找到办法了
2015-5-27 13:35
0
雪    币: 31
活跃值: (55)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
什么办法,能不能说一下,我也在做类似的问题,一直不能实现很好的合并。如果能给我一份代码就更好了。将万分感谢
2015-6-15 11:12
0
游客
登录 | 注册 方可回帖
返回
//