Winapi:获取具有文件特定句柄的进程 [英] Winapi: Get the process which has specific handle of a file

查看:30
本文介绍了Winapi:获取具有文件特定句柄的进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我有一个带有文件过滤驱动程序的软件,在软件安装过程中,驱动程序以这种方式作为服务启动:

Currently I have a software which has a file filter driver, during installation of software the driver is started as service in this way:

CreateService(serviceManager, name, displayName,
                          SERVICE_START | DELETE | SERVICE_QUERY_STATUS | SERVICE_STOP,
                              SERVICE_FILE_SYSTEM_DRIVER, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
                                  path, NULL, NULL, NULL, NULL, NULL);

路径是C:Program Files(x86)TSUdriverTSUfsd.sys.

我遇到的问题是在卸载软件时.当软件尝试删除 TSUFsd.sys 文件时,它让我拒绝访问.

The problem I'm having is during uninstallation of the software. It gives me access denied when software tries to delete TSUfsd.sys file.

我检查了软件是如何删除驱动程序的,结果是使用DeleteService函数删除它,并等待服务将其状态从SERVICE_STOP_PENDING更改为SERVICE_STOPPED,如果一段时间后它没有发生,它会获取服务 PID 并用 ProcessTerminate 杀死它,然后尝试删除文件rmdir/S/QC:Program Files(x86)TSU.

I've checked how the software deletes the driver, and turns out it deletes it with DeleteService function, and waits for service to change its state from SERVICE_STOP_PENDING to SERVICE_STOPPED and if it doesn't happen after some time, it gets the service PID and kills it with ProcessTerminate and then tries to delete the file with rmdir /S /Q C:Program Files(x86)TSU.

我试图找到可能有文件句柄的进程(使用进程资源管理器)但找不到任何.然后我想也许该服务还活着,所以我输入了 sc query TSUfsd 但该服务也消失了.

I've tried to find the process which could have had the handle of the file(with Process Explorer) but could not find any. Then I thought maybe the service is still alive so I typed sc query TSUfsd but the service was gone too.

我也尝试更改权限并向我的用户授予完全权限,但仍然出现相同的错误.

I've also tried to change permissions and grant full permissions to my user but same error still occurred.

所以我的问题是:

  1. 是否有其他方法可以检查哪个进程(或其他任何进程)可以保留文件?

  1. Is there any other ways to check which process(or anything else) can have a hold of a file?

我还注意到,每当我尝试使用 Cygwin(rm TSUfsd.sys) 删除文件时,它都会毫无问题地删除文件.使用 cmd(del/f ) 和使用 cygwin 删除文件有什么区别?

I've also noticed that, whenever I try to delete the file with Cygwin(rm TSUfsd.sys) it deletes the file without a problem. What is the difference between deleting file with cmd(del /f <filename>) and with cygwin?

推荐答案

对于此任务,从 Windows Vista 开始特殊存在 FileProcessIdsUsingFileInformation FILE_INFORMATION_CLASS.

For this task, starting with Windows Vista special exist FileProcessIdsUsingFileInformation FILE_INFORMATION_CLASS.

所以我们需要用 FILE_READ_ATTRIBUTES 打开文件(即使有人用 0 共享模式打开文件,这也是可能的.如果我们无法访问文件(通过它DACL) 但对父目录具有读访问权限).并调用 NtQueryInformationFileFileProcessIdsUsingFileInformation.返回时,我们得到 FILE_PROCESS_IDS_USING_FILE_INFORMATION 结构(在 wdm.h 中定义),其中包含该文件的 ProcessId 列表(打开文件句柄或映射部分.假设这个文件是 exe/dll - 我们在它加载的地方得到了进程 ID).每个 id 的打印进程名称也很好:

So we need open file with FILE_READ_ATTRIBUTES (this is possible even if somebody open file with 0 share mode. of if we have no access to file (by it DACL) but have read access to parent directory). and call NtQueryInformationFile with FileProcessIdsUsingFileInformation. on return we got FILE_PROCESS_IDS_USING_FILE_INFORMATION structure (defined in wdm.h) where list of ProcessId which hold this file(open file handle or mapped section. say if this file is exe/dll - we got process ids where it loaded). good also with this print process name for every id:

volatile UCHAR guz = 0;

NTSTATUS PrintProcessesUsingFile(HANDLE hFile)
{
    NTSTATUS status;
    IO_STATUS_BLOCK iosb;

    ULONG cb = 0, rcb = FIELD_OFFSET(FILE_PROCESS_IDS_USING_FILE_INFORMATION, ProcessIdList[64]);

    union {
        PVOID buf;
        PFILE_PROCESS_IDS_USING_FILE_INFORMATION ppiufi;
    };

    PVOID stack = alloca(guz);

    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (0 <= (status = NtQueryInformationFile(hFile, &iosb, ppiufi, cb, FileProcessIdsUsingFileInformation)))
        {
            if (ppiufi->NumberOfProcessIdsInList)
            {
                PrintProcessesUsingFile(ppiufi);
            }
        }

        rcb = (ULONG)iosb.Information;

    } while (status == STATUS_INFO_LENGTH_MISMATCH);

    return status;
}

NTSTATUS PrintProcessesUsingFile(POBJECT_ATTRIBUTES poa)
{
    IO_STATUS_BLOCK iosb;
    HANDLE hFile;
    NTSTATUS status;
    if (0 <= (status = NtOpenFile(&hFile, FILE_READ_ATTRIBUTES, poa, &iosb, FILE_SHARE_VALID_FLAGS, 0)))
    {
        status = PrintProcessesUsingFile(hFile);
        NtClose(hFile);
    }

    return status;
}

NTSTATUS PrintProcessesUsingFile(PCWSTR FileName)
{
    UNICODE_STRING ObjectName;
    NTSTATUS status = RtlDosPathNameToNtPathName_U_WithStatus(FileName, &ObjectName, 0, 0);
    if (0 <= status)
    {
        OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };
        status = PrintProcessesUsingFile(&oa);
        RtlFreeUnicodeString(&ObjectName);
    }

    return status;
}

NTSTATUS PrintProcessesUsingFile(PFILE_PROCESS_IDS_USING_FILE_INFORMATION ppiufi)
{
    NTSTATUS status;

    ULONG cb = 0x8000;

    do 
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        if (PVOID buf = new BYTE[cb])
        {
            if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
            {
                union {
                    PVOID pv;
                    PBYTE pb;
                    PSYSTEM_PROCESS_INFORMATION pspi;
                };

                pv = buf;
                ULONG NextEntryOffset = 0;

                do 
                {
                    pb += NextEntryOffset;

                    ULONG NumberOfProcessIdsInList = ppiufi->NumberOfProcessIdsInList;

                    PULONG_PTR ProcessIdList = ppiufi->ProcessIdList;
                    do 
                    {
                        if (*ProcessIdList++ == (ULONG_PTR)pspi->UniqueProcessId)
                        {
                            DbgPrint("%p %wZ
", pspi->UniqueProcessId, &pspi->ImageName);
                            break;
                        }
                    } while (--NumberOfProcessIdsInList);

                } while (NextEntryOffset = pspi->NextEntryOffset);
            }

            delete [] buf;
        }

    } while (status == STATUS_INFO_LENGTH_MISMATCH);

    return status;
}

这篇关于Winapi:获取具有文件特定句柄的进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆