博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关闭其它进程占用的文件句柄
阅读量:5346 次
发布时间:2019-06-15

本文共 13117 字,大约阅读时间需要 43 分钟。

当我们启动一个子进程,

打开读写管道,同时设置子进程继承这些管道的句柄,

我们就可以操作子进程的标准输入和标准输出了。

这样有个弊端,子进程会继承父进程打开的所有文件句柄。

如果子进程不退出,一直持续任务,那么,被打开的文件就无法重命名和删除了。

有两个解决的办法:

1. CreateFile的时候属性参数直接指定不允许继承句柄。但是这个方法有个弊端:

    c/c++的文件操作并没有提供属性设置,默认的属性是被继承的。

    如果写的是跨平台程序必须使用标准库时,就没有办法了。

 

2. 使用系统API枚举所有打开的句柄内核对象,然后关闭这些内核对象。

    代码如下:

    头文件定义如下:

1 #pragma warning(disable: 4996) // _tcsnicmp deprecated 2 #include 
3 4 // This makro assures that INVALID_HANDLE_VALUE (0xFFFFFFFF) returns FALSE 5 #define IsConsoleHandle(h) (((((ULONG_PTR)h) & 0x10000003) == 0x3) ? TRUE : FALSE) 6 #define SystemHandleInformation (SystemProcessInformation + 11) 7 #define ObjectNameInformation (ObjectTypeInformation - 1) 8 9 struct OBJECT_NAME_INFORMATION10 {11 UNICODE_STRING Name; // defined in winternl.h12 TCHAR NameBuffer;13 };14 15 typedef NTSTATUS(NTAPI* PNtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS Info, PVOID Buffer, ULONG BufferSize, PULONG ReturnLength);16 17 typedef LONG NTSTATUS;18 19 typedef struct _SYSTEM_HANDLE20 {21 DWORD dwProcessId;22 BYTE bObjectType;23 BYTE bFlags;24 WORD wValue;25 PVOID pAddress;26 DWORD GrantedAccess;27 }SYSTEM_HANDLE;28 29 typedef struct _SYSTEM_HANDLE_INFORMATION30 {31 DWORD dwCount;32 SYSTEM_HANDLE Handles[1];33 } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION, **PPSYSTEM_HANDLE_INFORMATION;34 35 36 typedef NTSTATUS(WINAPI *PNtQuerySystemInformation)37 (IN SYSTEM_INFORMATION_CLASS SystemInformationClass,38 OUT PVOID SystemInformation,39 IN ULONG SystemInformationLength,40 OUT PULONG ReturnLength OPTIONAL);

 

实现代码:

// returns// "\Device\HarddiskVolume3"                                (Harddisk Drive)// "\Device\HarddiskVolume3\Temp"                           (Harddisk Directory)// "\Device\HarddiskVolume3\Temp\transparent.jpeg"          (Harddisk File)// "\Device\Harddisk1\DP(1)0-0+6\foto.jpg"                  (USB stick)// "\Device\TrueCryptVolumeP\Data\Passwords.txt"            (Truecrypt Volume)// "\Device\Floppy0\Autoexec.bat"                           (Floppy disk)// "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB"                   (DVD drive)// "\Device\Serial1"                                        (real COM port)// "\Device\USBSER000"                                      (virtual COM port)// "\Device\Mup\ComputerName\C$\Boot.ini"                   (network drive share,  Windows 7)// "\Device\LanmanRedirector\ComputerName\C$\Boot.ini"      (network drive share,  Windwos XP)// "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" (network folder share, Windwos XP)// "\Device\Afd"                                            (internet socket)// "\Device\Console000F"                                    (unique name for any Console handle)// "\Device\NamedPipe\Pipename"                             (named pipe)// "\BaseNamedObjects\Objectname"                           (named mutex, named event, named semaphore)// "\REGISTRY\MACHINE\SOFTWARE\Classes\.txt"                (HKEY_CLASSES_ROOT\.txt)DWORD GetNtPathFromHandle(HANDLE h_File, CString* ps_NTPath){    if (h_File == 0 || h_File == INVALID_HANDLE_VALUE)        return ERROR_INVALID_HANDLE;    // NtQueryObject() returns STATUS_INVALID_HANDLE for Console handles    if (IsConsoleHandle(h_File))    {        ps_NTPath->Format(_T("\\Device\\Console%04X"), (DWORD)(DWORD_PTR)h_File);        return ERROR_SUCCESS;    }    BYTE  u8_Buffer[2000];    DWORD u32_ReqLength = 0;    UNICODE_STRING* pk_Info = &((OBJECT_NAME_INFORMATION*)u8_Buffer)->Name;    pk_Info->Buffer = 0;    pk_Info->Length = 0;    HMODULE h_NtDll = GetModuleHandle(_T("Ntdll.dll")); // Ntdll is loaded into EVERY process!    PNtQueryObject NtQueryObject = (PNtQueryObject)GetProcAddress(h_NtDll, "NtQueryObject");    if (NtQueryObject == NULL)    {        return ERROR_FUNCTION_FAILED;    }    // IMPORTANT: The return value from NtQueryObject is bullshit! (driver bug?)    // - The function may return STATUS_NOT_SUPPORTED although it has successfully written to the buffer.    // - The function returns STATUS_SUCCESS although h_File == 0xFFFFFFFF    NtQueryObject(h_File, OBJECT_INFORMATION_CLASS(ObjectNameInformation), u8_Buffer, sizeof(u8_Buffer), &u32_ReqLength);    // On error pk_Info->Buffer is NULL    if (!pk_Info->Buffer || !pk_Info->Length)        return ERROR_FILE_NOT_FOUND;    pk_Info->Buffer[pk_Info->Length / 2] = 0; // Length in Bytes!    *ps_NTPath = pk_Info->Buffer;    return ERROR_SUCCESS;}// converts// "\Device\HarddiskVolume3"                                -> "E:"// "\Device\HarddiskVolume3\Temp"                           -> "E:\Temp"// "\Device\HarddiskVolume3\Temp\transparent.jpeg"          -> "E:\Temp\transparent.jpeg"// "\Device\Harddisk1\DP(1)0-0+6\foto.jpg"                  -> "I:\foto.jpg"// "\Device\TrueCryptVolumeP\Data\Passwords.txt"            -> "P:\Data\Passwords.txt"// "\Device\Floppy0\Autoexec.bat"                           -> "A:\Autoexec.bat"// "\Device\CdRom1\VIDEO_TS\VTS_01_0.VOB"                   -> "H:\VIDEO_TS\VTS_01_0.VOB"// "\Device\Serial1"                                        -> "COM1"// "\Device\USBSER000"                                      -> "COM4"// "\Device\Mup\ComputerName\C$\Boot.ini"                   -> "\\ComputerName\C$\Boot.ini"// "\Device\LanmanRedirector\ComputerName\C$\Boot.ini"      -> "\\ComputerName\C$\Boot.ini"// "\Device\LanmanRedirector\ComputerName\Shares\Dance.m3u" -> "\\ComputerName\Shares\Dance.m3u"// returns an error for any other device typeDWORD GetDosPathFromNtPath(const TCHAR* u16_NTPath, CString* ps_DosPath){    DWORD u32_Error;    if (_tcsnicmp(u16_NTPath, _T("\\Device\\Serial"), 14) == 0 || // e.g. "Serial1"        _tcsnicmp(u16_NTPath, _T("\\Device\\UsbSer"), 14) == 0)   // e.g. "USBSER000"    {        HKEY h_Key;        if (u32_Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Hardware\\DeviceMap\\SerialComm"), 0, KEY_QUERY_VALUE, &h_Key))            return u32_Error;        TCHAR u16_ComPort[50];        DWORD u32_Type;        DWORD u32_Size = sizeof(u16_ComPort);        if (u32_Error = RegQueryValueEx(h_Key, u16_NTPath, 0, &u32_Type, (BYTE*)u16_ComPort, &u32_Size))        {            RegCloseKey(h_Key);            return ERROR_UNKNOWN_PORT;        }        *ps_DosPath = u16_ComPort;        RegCloseKey(h_Key);        return ERROR_SUCCESS;    }    if (_tcsnicmp(u16_NTPath, _T("\\Device\\LanmanRedirector\\"), 25) == 0) // Win XP    {        *ps_DosPath = _T("\\\\");        *ps_DosPath += (u16_NTPath + 25);        return ERROR_SUCCESS;    }    if (_tcsnicmp(u16_NTPath, _T("\\Device\\Mup\\"), 12) == 0) // Win 7    {        *ps_DosPath = _T("\\\\");        *ps_DosPath += (u16_NTPath + 12);        return ERROR_SUCCESS;    }    TCHAR u16_Drives[300];    if (!GetLogicalDriveStrings(300, u16_Drives))        return GetLastError();    TCHAR* u16_Drv = u16_Drives;    while (u16_Drv[0])    {        TCHAR* u16_Next = u16_Drv + _tcslen(u16_Drv) + 1;        u16_Drv[2] = 0; // the backslash is not allowed for QueryDosDevice()        TCHAR u16_NtVolume[1000];        u16_NtVolume[0] = 0;        // may return multiple strings!        // returns very weird strings for network shares        if (!QueryDosDevice(u16_Drv, u16_NtVolume, sizeof(u16_NtVolume) / sizeof(TCHAR)))            return GetLastError();        int s32_Len = (int)_tcslen(u16_NtVolume);        if (s32_Len > 0 && _tcsnicmp(u16_NTPath, u16_NtVolume, s32_Len) == 0)        {            *ps_DosPath = u16_Drv;            *ps_DosPath += (u16_NTPath + s32_Len);            return ERROR_SUCCESS;        }        u16_Drv = u16_Next;    }    return ERROR_BAD_PATHNAME;}//EnableTokenPrivilege( SE_DEBUG_NAME );BOOL EnableTokenPrivilege(LPCTSTR pszPrivilege){    // do it only once    static bool bEnabled = false;    if (bEnabled)    {        return TRUE;    }    bEnabled = true;    HANDLE hToken = 0;    TOKEN_PRIVILEGES tkp = { 0 };    // Get a token for this process.    if (!OpenProcessToken(GetCurrentProcess(),        TOKEN_ADJUST_PRIVILEGES |        TOKEN_QUERY, &hToken))    {        return FALSE;    }    // Get the LUID for the privilege.     if (LookupPrivilegeValue(NULL, pszPrivilege,        &tkp.Privileges[0].Luid))    {        tkp.PrivilegeCount = 1;  // one privilege to set            tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;        // Set the privilege for this process.         AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,            (PTOKEN_PRIVILEGES)NULL, 0);        if (GetLastError() != ERROR_SUCCESS)            return FALSE;        return TRUE;    }    return FALSE;}/* * Basically, with the above code, we can close the handles created by another process.  * After closing the handle, we can rename or delete that file or directory.  * But there are cases where after closing the handle, we can rename the folder but deleting is not possible. * using this option on a DLL used by another process is just ignored.*/BOOL CloseHandleWithProcess(SYSTEM_HANDLE& sh){    HANDLE hFile = (HANDLE)sh.wValue;    HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, sh.dwProcessId);    if (hProcess)    {        HANDLE hDup = 0;        BOOL b = DuplicateHandle(hProcess, hFile, GetCurrentProcess(),            &hDup, DUPLICATE_SAME_ACCESS, FALSE, DUPLICATE_CLOSE_SOURCE);        if (hDup)        {            CloseHandle(hDup);        }        CloseHandle(hProcess);    }        return FALSE;}BOOL RenameWithClose(const CString& srcpath, const CString& dstpath){    if (MoveFileEx(srcpath, dstpath, MOVEFILE_REPLACE_EXISTING))    {        return TRUE;    }    else    {        // The process cannot access the file because it is being used by another process        // Try to close file handle used by another process        if (GetLastError() == ERROR_SHARING_VIOLATION)        {            HMODULE hModule = GetModuleHandle(_T("ntdll.dll"));            PNtQuerySystemInformation NtQuerySystemInformation = (PNtQuerySystemInformation)GetProcAddress(hModule, "NtQuerySystemInformation");            if (NtQuerySystemInformation == NULL)            {                SetLastError(ERROR_SHARING_VIOLATION);                return FALSE;            }            else            {                // Get the list of all handles in the system                PSYSTEM_HANDLE_INFORMATION pSysHandleInformation = new SYSTEM_HANDLE_INFORMATION;                DWORD size = sizeof(SYSTEM_HANDLE_INFORMATION);                DWORD needed = 0;                NTSTATUS status = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS(SystemHandleInformation), pSysHandleInformation, size, &needed);                if (!NT_SUCCESS(status))                {                    if (0 == needed)                    {                        delete pSysHandleInformation;                        SetLastError(ERROR_SHARING_VIOLATION);                        return FALSE;// some other error                    }                    // The previously supplied buffer wasn't enough.                    delete pSysHandleInformation;                    size = needed + 1024;                    pSysHandleInformation = (PSYSTEM_HANDLE_INFORMATION)new BYTE[size];                    status = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS(SystemHandleInformation), pSysHandleInformation, size, &needed);                    if (!NT_SUCCESS(status))                    {                        // some other error so quit.                        delete pSysHandleInformation;                        SetLastError(ERROR_SHARING_VIOLATION);                        return FALSE;                    }                }                // iterate over every handle                for (DWORD i = 0; i < pSysHandleInformation->dwCount; i++)                {                    HANDLE hDup = (HANDLE)pSysHandleInformation->Handles[i].wValue;                    if (pSysHandleInformation->Handles[i].dwProcessId == GetCurrentProcessId())                    {                        CString strNtPath;                        CString strDosPath;                        GetNtPathFromHandle(hDup, &strNtPath);                        GetDosPathFromNtPath(strNtPath, &strDosPath);                        if (strDosPath == srcpath)                        {                            _tprintf(_T("%s: (process id: %d) (filetype: %d) with handle 0x%x\n"), (LPCTSTR)strDosPath,                                pSysHandleInformation->Handles[i].dwProcessId, pSysHandleInformation->Handles[i].bObjectType,                                pSysHandleInformation->Handles[i].wValue);                                                        //now we can close file open by another process                            //do rename or delete file again                            //EnableTokenPrivilege(SE_DEBUG_NAME);                            //CloseHandleWithProcess(pSysHandleInformation->Handles[i]);                        }                    }                }                delete pSysHandleInformation;            }        }        else        {            return FALSE;        }    }    return TRUE;}

 

转载于:https://www.cnblogs.com/jojodru/p/5346029.html

你可能感兴趣的文章
linux下编译安装nginx
查看>>
ArcScene 高程不同的表面无法叠加
查看>>
[ONTAK2010] Peaks
查看>>
DLL 导出函数
查看>>
windows超过最大连接数解决命令
查看>>
12个大调都是什么
查看>>
angular、jquery、vue 的区别与联系
查看>>
参数范围的选择
查看>>
使用 MarkDown & DocFX 升级 Rafy 帮助文档
查看>>
THUPC2019/CTS2019/APIO2019游记
查看>>
Nodejs Express模块server.address().address为::
查看>>
4.3.5 Sticks (POJ1011)
查看>>
POJ 2960 S-Nim 博弈论 sg函数
查看>>
Dijkstra模版
查看>>
一个简单的插件式后台任务管理程序
查看>>
GDB调试多进程程序
查看>>
组合数
查看>>
CMD批处理延时启动的几个方法
查看>>
转:LoadRunner中web_custom_request 和 web_submit_data的差别
查看>>
HTC G7直刷MIUI开启A2SD+亲测教程
查看>>