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

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

问题描述

当前我有一个带有文件筛选器驱动程序的软件,在软件安装过程中,该驱动程序通过以下方式作为服务启动:

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

路径为 C:\Program Files(x86)\TSU \driver\TSUfsd.sys



我遇到的问题是在卸载软件期间。当软件尝试删除 TSUfsd.sys 文件时,它使我无法访问。



我检查了软件的方式删除驱动程序,然后使用 DeleteService 函数将其删除,然后等待服务将其状态从 SERVICE_STOP_PENDING 更改到 SERVICE_STOPPED ,如果一段时间后没有发生,它将获得服务 PID 并用<$杀死它c $ c> ProcessTerminate ,然后尝试使用 rmdir / S / QC:\Program Files(x86)\TSU\ 。



我试图找到可能具有文件句柄的进程(使用Process Explorer),但是找不到任何进程。然后我以为该服务可能仍然有效,所以我键入了 sc查询TSUfsd ,但该服务也消失了。



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



所以我的问题是:


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


  2. 我还注意到,每当我尝试使用Cygwin( rm TSUfsd.sys code>)会毫无问题地删除文件。


用cmd( del / f< filename> )和cygwin删除文件有什么区别?



解决方案

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



所以我们需要使用 FILE_READ_ATTRIBUTES 打开文件(即使有人打开共享模式为0的文件(如果我们无权访问文件(通过 DACL ),但具有对父目录的读取访问权限)。并调用 NtQueryInformationFile FileProcessIdsUsingFileInformation 。返回时,我们得到 FILE_PROCESS_IDS_USING_FILE_INFORMATION 结构(在 wdm.h 中定义)结构,其中 ProcessId 存放此文件(打开文件句柄或映射部分。说说此文件是否为exe / dll-我们在加载文件的位置获得进程ID)。每个ID的打印过程名称也很合适:

  volatile UCHAR guz = 0; 

NTSTATUS PrintProcessesUsingFile(HANDLE hFile)
{
NTSTATUS状态;
IO_STATUS_BLOCK iosb;

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

工会{
PVOID buf;
PFILE_PROCESS_IDS_USING_FILE_INFORMATION ppiufi;
};

PVOID堆栈= alloca(guz);


{
if(cb {
cb = RtlPointerToOffset(buf = alloca(rcb-cb),堆栈);
}

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

rcb =(ULONG)iosb.Information;

}而(状态== STATUS_INFO_LENGTH_MISMATCH);

退货状态;
}

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

退货状态;
}

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);
}

退货状态;
}

NTSTATUS PrintProcessesUsingFile(PFILE_PROCESS_IDS_USING_FILE_INFORMATION ppiufi)
{
NTSTATUS状态;

ULONG cb = 0x8000;


{
状态= STATUS_INSUFFICIENT_RESOURCES;

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

pv = buf;
ULONG NextEntryOffset = 0;


{
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);
休息时间;
}
} while(--NumberOfProcessIdsInList);

},而(NextEntryOffset = pspi-> NextEntryOffset);
}

delete [] buf;
}

}而(状态== STATUS_INFO_LENGTH_MISMATCH);

退货状态;
}


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);

Where path is C:\Program Files(x86)\TSU\driver\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.

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\.

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.

So my questions are:

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

  2. 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?

解决方案

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

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\n", 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天全站免登陆