C Winapi:获取具有文件特定句柄的进程

C Winapi:获取具有文件特定句柄的进程,c,windows,winapi,cmd,cygwin,C,Windows,Winapi,Cmd,Cygwin,目前我有一个软件,它有一个文件过滤器驱动程序,在软件安装过程中,驱动程序以如下方式作为服务启动: CreateService(serviceManager, name, displayName, SERVICE_START | DELETE | SERVICE_QUERY_STATUS | SERVICE_STOP, SERVICE_FILE_SYSTEM_DRIVER, SERVIC

目前我有一个软件,它有一个文件过滤器驱动程序,在软件安装过程中,驱动程序以如下方式作为服务启动:

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:\ProgramFiles(x86)\TSU\driver\TSUfsd.sys

我遇到的问题是在卸载软件的过程中。当软件试图删除
TSUfsd.sys
文件时,它允许我拒绝访问

我检查了软件是如何删除驱动程序的,结果显示它使用
DeleteService
功能删除驱动程序,并等待服务将其状态从
service\u STOP\u PENDING
更改为
service\u STOPPED
,如果一段时间后没有发生,它获取服务
PID
并使用
ProcessTerminate
终止它,然后尝试使用
rmdir/S/Q C:\Program Files(x86)\TSU\
删除文件

我试图找到可以处理文件的进程(使用process Explorer),但找不到任何进程。然后我想可能该服务还活着,所以我键入了
sc query TSUfsd
,但该服务也消失了

我还尝试更改权限并向我的用户授予完全权限,但仍然发生相同的错误

因此,我的问题是:

  • 有没有其他方法可以检查哪个进程(或任何其他进程)可以保留文件

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


  • 对于此任务,请从Windows Vista特殊存在开始
    fileprocessidusingfileinformation

    因此,我们需要使用
    文件读取属性打开文件(即使有人以0共享模式打开文件,这也是可能的。当然,如果我们无法访问文件(通过它DACL),但可以读取父目录)。并使用
    fileprocessidusingfileinformation
    调用。返回时,我们使用文件信息
    结构(在
    wdm.h
    中定义)获得了
    FILE\u进程ID\u,其中包含保存此文件的
    ProcessId
    列表(打开文件句柄或映射节。假设此文件是exe/dll-我们在加载的位置获得了进程ID)。同样适用于每个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\n", pspi->UniqueProcessId, &pspi->ImageName);
                                break;
                            }
                        } while (--NumberOfProcessIdsInList);
    
                    } while (NextEntryOffset = pspi->NextEntryOffset);
                }
    
                delete [] buf;
            }
    
        } while (status == STATUS_INFO_LENGTH_MISMATCH);
    
        return status;
    }
    
    volatile-UCHAR-guz=0;
    NTSTATUS打印进程使用文件(句柄hFile)
    {
    非关税国家地位;
    IO_状态_块iosb;
    ULONG cb=0,rcb=FIELD_OFFSET(使用文件信息的文件进程ID,ProcessIdList[64]);
    联合{
    pvoidbuf;
    使用文件信息ppiufi的文件处理ID;
    };
    PVOID stack=alloca(guz);
    做
    {
    如果(cbUniqueProcessId,&pspi->ImageName);
    打破
    }
    }而(--NumberOfProcessIdsInList);
    }而(NexteryOffset=pspi->NexteryOffset);
    }
    删除[]buf;
    }
    }而(状态==状态信息长度不匹配);
    返回状态;
    }
    
    有一个很好的实用程序,名为Mark Russinovich。除非你想自己用代码来做,然后您可以枚举所有进程并检查它们的句柄?在windows 10中-系统保留已加载的驱动程序,在驱动程序将被卸载之前不允许删除。非常感谢您的回答:)因为生成代码时会出现
    错误:#windows DDK不支持错误编译器版本#windows DDK不支持错误编译器版本
    我无法真正更新我的编译器,因为它安装在我的大学计算机上,更新它需要许可和大量时间@建议使用handle.exe来解决此问题,您的代码是否与handle.exe执行相同的操作?@user3503143-是。相同-
    fileprocessidusingfileinformation
    -您的编译器版本是什么?您只需将粘贴wdk定义(
    NtQueryInformationFile
    )复制到自己的src
    (GCC)4.9.2
    ,我们正在使用Cygwin。我尝试了
    handle.exe
    ,但没有找到匹配的句柄
    。还有什么别的原因呢?用户配置文件和文件本身没有损坏。@user3503143您完全可以通过复制/粘贴一些定义来编译此代码。我只是简单地粘贴自己的就绪状态。但是,此处仅强制要求
    NtQueryInformationFile
    文件信息类
    文件处理ID使用文件信息
    。对于可以使用
    CreateFileW
    的打开文件,将进程id转换为不能使用的名称。@user3503143-按用户模式应用程序的方式包括wdm.h(windows.h也是如此)是很困难的。需要在名称空间中包含它+一些技巧。不要尝试将wdm.h包含到项目中。只需使用文件信息和NtQueryInformationFile复制/粘贴文件信息类和文件进程ID即可。使用CreateFileW打开文件(
    文件读取属性
    文件标志
    备份语义)–真正的任务是绝对可行的