查看文件被占用的进程 NtQueryObject NtQueryInformationFile NtQuerySystemInformation

本文介绍了一个用于检测文件占用及系统句柄信息的方法,包括如何通过NTQUERYOBJECT和NTQUERYSYSTEMINFORMATION API获取文件路径,并判断特定句柄是否可能导致NtQueryObject操作卡死。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当你重命名或删除某个文件或文件夹时, 有时候系统提示说:操作无法完成...balabala...; 你怎么知道它被什么占用了,上代码



#pragma once

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
          using namespace std; #include 
          
            typedef std::basic_string 
           
             , std::allocator 
            
              > tstring; #include 
             
               #include 
              
                #pragma comment(lib, "psapi.lib") #define NT_SUCCESS(status) (status == (NTSTATUS)0x00000000L) #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) #define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) #define SystemHandleInformation ((SYSTEM_INFORMATION_CLASS)16) // NTQUERYOBJECT typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING Name; WCHAR NameBuffer[1]; } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; typedef enum _OBJECT_INFORMATION_CLASS { ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectAllInformation, ObjectDataInformation } OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; typedef NTSTATUS (WINAPI *NTQUERYOBJECT)( _In_opt_ HANDLE Handle, _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, _Out_opt_ PVOID ObjectInformation, _In_ ULONG ObjectInformationLength, _Out_opt_ PULONG ReturnLength); // NTQUERYSYSTEMINFORMATION typedef struct _SYSTEM_HANDLE { DWORD dwProcessId; BYTE bObjectType; BYTE bFlags; WORD wValue; PVOID pAddress; DWORD GrantedAccess; } SYSTEM_HANDLE, *PSYSTEM_HANDLE; typedef struct _SYSTEM_HANDLE_INFORMATION { DWORD dwCount; SYSTEM_HANDLE Handles[1]; } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL); // // NtQueryInformationFile // #define FileNameInformation ((FILE_INFORMATION_CLASS)9) // typedef struct _FILE_NAME_INFORMATION { // ULONG FileNameLength; // WCHAR FileName[1]; // } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; typedef NTSTATUS (WINAPI *NTQUERYINFORMATIONFILE)( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass); // typedef struct _CLIENT_ID { // HANDLE UniqueProcess; // HANDLE UniqueThread; // } CLIENT_ID, *PCLIENT_ID; // ncScopedHandle class ncScopedHandle { ncScopedHandle(const ncScopedHandle&); ncScopedHandle& operator=(const ncScopedHandle&); public: ncScopedHandle(HANDLE handle) : _handle(handle) { } ~ncScopedHandle() { if (_handle != NULL) { CloseHandle(_handle); } } operator HANDLE() const { return _handle; } PHANDLE operator& () { return &_handle; } void operator=(HANDLE handle) { if (_handle != NULL) { CloseHandle(_handle); } _handle = handle; } private: HANDLE _handle; }; // ncFileHandle struct ncFileHandle { SYSTEM_HANDLE _handle; tstring _filePath; tstring _path; ncFileHandle (SYSTEM_HANDLE handle, const tstring& filePath, const tstring& path) : _handle (handle) , _filePath (filePath) , _path (path) { } }; // GetDeviceDriveMap void GetDeviceDriveMap(std::map 
               
                 & mapDeviceDrive) { TCHAR szDrives[512]; if (!GetLogicalDriveStrings (_countof(szDrives) - 1, szDrives)) { return; } TCHAR* lpDrives = szDrives; TCHAR szDevice[MAX_PATH]; TCHAR szDrive[3] = _T(" :"); do { *szDrive = *lpDrives; if (QueryDosDevice (szDrive, szDevice, MAX_PATH)) { mapDeviceDrive[szDevice] = szDrive; } while (*lpDrives++); } while (*lpDrives); } // DevicePathToDrivePath BOOL DevicePathToDrivePath (tstring& path) { static std::map 
                
                  mapDeviceDrive; if (mapDeviceDrive.empty ()) { GetDeviceDriveMap (mapDeviceDrive); } for (std::map 
                 
                   ::const_iterator it = mapDeviceDrive.begin (); it != mapDeviceDrive.end (); ++it) { size_t nLength = it->first.length (); if (_tcsnicmp (it->first.c_str (), path.c_str (), nLength) == 0) { path.replace (0, nLength, it->second); return TRUE; } } return FALSE; } // GetHandlePath BOOL GetHandlePath (HANDLE handle, tstring& path) { static NTQUERYOBJECT fpNtQueryObject = (NTQUERYOBJECT)GetProcAddress (GetModuleHandle (_T("ntdll")), "NtQueryObject"); if (fpNtQueryObject == NULL) { return FALSE; } DWORD dwLength = 0; OBJECT_NAME_INFORMATION info; NTSTATUS status = fpNtQueryObject (handle, ObjectNameInformation, &info, sizeof (info), &dwLength); if (status != STATUS_BUFFER_OVERFLOW) { return FALSE; } POBJECT_NAME_INFORMATION pInfo = (POBJECT_NAME_INFORMATION)malloc(dwLength); while (true) { status = fpNtQueryObject (handle, ObjectNameInformation, pInfo, dwLength, &dwLength); if (status != STATUS_BUFFER_OVERFLOW) { break; } pInfo = (POBJECT_NAME_INFORMATION)realloc(pInfo, dwLength); } BOOL bRes = FALSE; if (NT_SUCCESS(status)) { path = pInfo->Name.Buffer; bRes = DevicePathToDrivePath(path); } free(pInfo); return bRes; } // GetSystemHandleInfo PSYSTEM_HANDLE_INFORMATION GetSystemHandleInfo () { static NTQUERYSYSTEMINFORMATION fpNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress (GetModuleHandle (_T("ntdll")), "NtQuerySystemInformation"); if (fpNtQuerySystemInformation == NULL) { return NULL; } DWORD dwLength = 0; SYSTEM_HANDLE_INFORMATION shi; NTSTATUS status = fpNtQuerySystemInformation (SystemHandleInformation, &shi, sizeof (shi), &dwLength); if (status != STATUS_INFO_LENGTH_MISMATCH) { return NULL; } PSYSTEM_HANDLE_INFORMATION pshi = (PSYSTEM_HANDLE_INFORMATION)malloc(dwLength); while (true) { status = fpNtQuerySystemInformation (SystemHandleInformation, pshi, dwLength, &dwLength); if (status != STATUS_INFO_LENGTH_MISMATCH) { break; } pshi = (PSYSTEM_HANDLE_INFORMATION)realloc(pshi, dwLength); } if (!NT_SUCCESS (status)) { free (pshi); pshi = NULL; } return pshi; } // // 检测指定句柄是否可能导致NtQueryObject卡死: // 1.注意必须使用NtQueryInformationFile而不是NtQueryObject进行检测,否则可能导致WinXP系统 // 下进程死锁而无法结束。 // void CheckBlockThreadFunc (void* param) { static NTQUERYINFORMATIONFILE fpNtQueryInformationFile = (NTQUERYINFORMATIONFILE)GetProcAddress (GetModuleHandle (_T("ntdll")), "NtQueryInformationFile"); if (fpNtQueryInformationFile != NULL) { BYTE buf[1024]; IO_STATUS_BLOCK ioStatus; fpNtQueryInformationFile ((HANDLE)param, &ioStatus, buf, 1024, FileNameInformation); } } // IsBlockingHandle BOOL IsBlockingHandle (HANDLE handle) { HANDLE hThread = (HANDLE)_beginthread(CheckBlockThreadFunc, 0, (void*)handle); if (WaitForSingleObject (hThread, 100) != WAIT_TIMEOUT) { return FALSE; } TerminateThread (hThread, 0); return TRUE; } // FindFileHandle BOOL FindFileHandle (LPCTSTR lpName, vector 
                  
                    & handles) { handles.clear (); if (lpName == NULL) { return FALSE; } // 打开“NUL”文件以便后续获取文件句柄类型值。 ncScopedHandle hTempFile = CreateFile (_T("NUL"), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); if (hTempFile == NULL) { return FALSE; } // 获取当前系统中所有的句柄信息。 PSYSTEM_HANDLE_INFORMATION pshi = GetSystemHandleInfo (); if (pshi == NULL) { return FALSE; } // 查询当前系统的文件句柄类型值。 BYTE nFileType = 0; DWORD dwCrtPid = GetCurrentProcessId (); for (DWORD i = 0; i < pshi->dwCount; ++i) { if (pshi->Handles[i].dwProcessId == dwCrtPid && hTempFile == (HANDLE)pshi->Handles[i].wValue) { nFileType = pshi->Handles[i].bObjectType; break; } } HANDLE hCrtProc = GetCurrentProcess (); for (DWORD i = 0; i < pshi->dwCount; ++i) { // 过滤掉非文件类型的句柄。 if (pshi->Handles[i].bObjectType != nFileType) { continue; } // 将上述句柄复制到当前进程中。 ncScopedHandle handle = NULL; ncScopedHandle hProc = OpenProcess (PROCESS_DUP_HANDLE, FALSE, pshi->Handles[i].dwProcessId); if (hProc == NULL || !DuplicateHandle (hProc, (HANDLE)pshi->Handles[i].wValue, hCrtProc, &handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { continue; } // 过滤掉会导致NtQueryObject卡死的句柄(如管道等)。 if (IsBlockingHandle (handle)) { continue; } // 获取句柄对应的文件路径并进行匹配检查。 tstring filePath; if (GetHandlePath (handle, filePath) && filePath.find (lpName) != tstring::npos) { ncScopedHandle hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, pshi->Handles[i].dwProcessId); TCHAR szProcName[MAX_PATH]; GetProcessImageFileName (hProcess, szProcName, MAX_PATH); tstring path (szProcName); DevicePathToDrivePath(path); ncFileHandle fh (pshi->Handles[i], filePath, path); handles.push_back (fh); } } free(pshi); return TRUE; } // BOOL CloseHandleEx (HANDLE handle, DWORD dwPid) // { // if (GetCurrentProcessId () == dwPid) // return CloseHandle (handle); // // ncScopedHandle hProcess = OpenProcess (PROCESS_DUP_HANDLE, FALSE, dwPid); // if (hProcess == NULL) // return FALSE; // // return DuplicateHandle (hProcess, handle, GetCurrentProcess (), NULL, 0, FALSE, DUPLICATE_CLOSE_SOURCE); // } // main int _tmain(int argc, _TCHAR* argv[]) { tstring path (_T("E:\\TDDOWNLOAD\\")); vector 
                   
                     vecHandles; if (!FindFileHandle(path.c_str(), vecHandles)) { return -1; } return 0; } 
                    
                   
                  
                 
                
               
              
             
            
           
         
       
      
      
     
     
    
    
   
   

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值