[转]ring3下干净的强行删除文件

在某公司实习完,再次回到寝室。还是在学校好。

实习期间的给我的任务就是为项目添加一个强行删除的模块。

背景是硬盘上存储空间不够时,需要删掉老的文件,如果这时后,老的文件被打开了,没有关掉,就无法删除。所以叫我写一个这样的功能。

所谓干净,指的是释放掉这个被占用的句柄。强行删除的方法很多,用驱动直接发磁盘IRP。等等


查阅相关资料后。整理思路如下,如果有同学以后要写这样的功能,可以参考,

1.ZwQuerySystemInformation获取系统当前句柄列表.


2.遍历这个列表,跳过PID==4的 句柄(惹不起)。跳过不是文件的句柄

3. 根据PID判断,如果是自身进程打开的,直接取此句柄
dwCurProcessId==pSystemsHandleInformation->Handles[dwIndex].ProcessID

如果不是,DuplicateHandle相同权限的句柄到自身进程

4.根据句柄用NtQueryInformationFile
获取文件路径。
这里必须用NtQueryInformationFile而不是ZwQueryInformationFile
MSDN上说的很清楚。
If the call to this function occurs in user mode, you should use the name "NtQueryInformationFile"
instead of "ZwQueryInformationFile".


这个获取到的路径是不带盘符的,盘符要用GetFileInformationByHandle
,通过比对VolumeSerialNumber单独处理.

注意:
NtQueryInformationFile
是堵塞的,可能会一直卡在那里不返回,所以要放到单独的线程里执行并设置超时。
我一开始想偷懒,直接用ZwQueryObject,这样获取到的就是完整的设备格式路径,不用处理盘符。
在实际编写时会发现,虽然NtQueryInformationFile和ZwQueryObject都是堵塞的,

在线程超时后,TerminateThread线程时,如果是ZwQueryObject就会导致内存泄露,句柄无法释放,
主线程退出后,发现任务管理器进程还在,CodeProject上有人提出过这个问题,不过他最后是用驱动解决的,
而我一开始就限制了,为了稳定必须在ring3下

如果我用NtQueryInformationFile,然后超时时TerminateThread就没事。

5.比对输入的文件路径和获取到文件路径(要自己处理带盘符的完整DOS风格路径)
获取此时的PID和handle,

6.打开指定PID的进程,创建远程线程closehandle,关闭掉指定的handle.

7.因为一个文件可能被多个句柄占用,所以第一次获取到之后不能自己返回,要继续,获取一个pid和handle就
用远程线程结束一次。一直到没有句柄占用此文件。

-----------------------------------------------------------------------------
无图无真相,我用千千静听做的测试。

千千静听在播放D:\www\Music\the mass-era.mp3文件时,这个时候,普通删除是无法删除掉这个文件的,

会提示


运行demo程序。拖放文件到路径框



点击删除后,显示当前占用此文件的进程和句柄相关信息,随即关闭这个句柄,并成功删除掉了文件





在单曲循环模式下,此时千千静听会直接卡死,只能通过结束进程来推出。

其他模式下,会自动跳到下一曲。


---------------------------------------------------------------------------

//提升自身到Debug权限
BOOL MyEnableDebugPriority(VOID)
{
HANDLE hTokenHandle=NULL;
TOKEN_PRIVILEGES TokenPrivileges;
BOOL bFlag=FALSE;

//打开自身进程令牌
bFlag=OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES,&hTokenHandle);
if (!bFlag)
{
bFlag=FALSE;
}
else
{
//查询Debug权限
bFlag=LookupPrivilegeValueW(NULL,SE_DEBUG_NAME,&TokenPrivileges.Privileges[0].Luid);
if (!bFlag)
{
bFlag=FALSE;
}
else
{
TokenPrivileges.PrivilegeCount=1;
TokenPrivileges.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; //我是想获得权限
bFlag=AdjustTokenPrivileges(hTokenHandle,FALSE,&TokenPrivileges,0,(PTOKEN_PRIVILEGES)NULL,0); //提升权限
}
}

if (hTokenHandle!=NULL)
{
CloseHandle(hTokenHandle);
}

return bFlag;
}
DWORD WINAPI MyQueryFileNameByHandleThreadFunc(LPVOID pParam)
{
FILE_INFO *pFileInfo=(FILE_INFO*)pParam;

WCHAR wcVolume[3]={0};

NTSTATUS MyNtStatus;
IO_STATUS_BLOCK IoStatus;
UCHAR szBuff[0x1000];
RtlZeroMemory(szBuff,sizeof(szBuff));
FILE_NAME_INFORMATION *pFileNameInformation=(FILE_NAME_INFORMATION*)szBuff;

MyNtStatus=NtQueryInformationFile(pFileInfo->hFileHandle,&IoStatus,pFileNameInformation,
sizeof(FILE_INFO)-sizeof(HANDLE)-sizeof(BOOL),FileNameInformationClass);

if(NT_SUCCESS(MyNtStatus))
{
if(pFileNameInformation->FileNameLength!=0)
{
pFileInfo->bFlag=TRUE;
pFileInfo->FileNameInfo.FileNameLength=pFileNameInformation->FileNameLength;
if (MyGetVolumeNameByHandle(pFileInfo->hFileHandle,wcVolume))// 得到盘符
{
RtlZeroMemory(pFileInfo->FileNameInfo.FileName,sizeof(pFileInfo->FileNameInfo.FileName));

pFileInfo->FileNameInfo.FileName[0]=wcVolume[0];
pFileInfo->FileNameInfo.FileName[1]=wcVolume[1];

wcsncpy(&pFileInfo->FileNameInfo.FileName[2],
pFileNameInformation->FileName,
pFileNameInformation->FileNameLength);

pFileInfo->FileNameInfo.FileName[2+pFileNameInformation->FileNameLength-1]=0;
}

}
}


return 0;
}


//获取当前操作系统中文件句柄 的object值
//这里必须用NtQuerySystemInformation
UCHAR MyGetOsFileHandleObject(VOID)
{
UCHAR ucResult=0;
DWORD dwSize=100;
DWORD dwNeedSize=0;
NTSTATUS MyNtStatus;
DWORD dwCurProcessId=GetCurrentProcessId();
DWORD dwIndex=0;

HANDLE hTempFile=CreateFileW(_T("C:\\boot.ini"),0,0,NULL,OPEN_EXISTING,0,0);

SYSTEM_HANDLE_INFORMATION* pSystemsHandleInformation = (SYSTEM_HANDLE_INFORMATION*)VirtualAlloc( NULL,dwSize, MEM_COMMIT, PAGE_READWRITE );

if (NULL==pSystemsHandleInformation)
{
return 0;
}

MyNtStatus=NtQuerySystemInformation(SystemHandleInformation,pSystemsHandleInformation,dwSize,&dwNeedSize);

if (STATUS_INFO_LENGTH_MISMATCH==MyNtStatus)
{
if (0 == dwNeedSize)
{
ucResult=0;
goto MyErrorExit;
}
else
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
pSystemsHandleInformation = (SYSTEM_HANDLE_INFORMATION*)VirtualAlloc( NULL,dwNeedSize, MEM_COMMIT, PAGE_READWRITE );

if(NULL==pSystemsHandleInformation)
{
ucResult=0;
goto MyErrorExit;
}
}
}

MyNtStatus=NtQuerySystemInformation(SystemHandleInformation,pSystemsHandleInformation,dwNeedSize,NULL);

if (!NT_SUCCESS(MyNtStatus))
{
goto MyErrorExit;
}
for (dwIndex=0;dwIndex<pSystemsHandleInformation->Count;dwIndex++)
{
if( (dwCurProcessId==pSystemsHandleInformation->Handles[dwIndex].ProcessID) &&
(hTempFile==(HANDLE)pSystemsHandleInformation->Handles[dwIndex].HandleNumber) )
{
ucResult=(UCHAR)pSystemsHandleInformation->Handles[dwIndex].HandleType; //得到句柄类型
OutputDebugStringW(_T("\n得到句柄类型\n"));
break;
}

}


MyErrorExit:

if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE);
}

if (hTempFile!=INVALID_HANDLE_VALUE)
{
CloseHandle(hTempFile);
}

return ucResult;
}
//遍历系统当前所有文件句柄,每得到一个,就查这个句柄对应的文件名
DWORD WINAPI MyLookupHandleThreadFunc(LPVOID pParam)
{
LOOKUP_INFO * pLockorInfo=(LOOKUP_INFO*)pParam;

DWORD dwSize=100;
DWORD dwNeedSize=0;
NTSTATUS MyNtStatus;
DWORD dwCurProcessId=GetCurrentProcessId();
DWORD dwIndex=0;
BOOL bRemoteFlag=FALSE;
HANDLE hRemoteProcess=NULL;
HANDLE hCurProcess=GetCurrentProcess();

BOOL bDupliFlag=FALSE;


HANDLE hTureHandle=NULL;

SYSTEM_HANDLE_INFORMATION* pSystemsHandleInformation = (SYSTEM_HANDLE_INFORMATION*)VirtualAlloc( NULL,dwSize, MEM_COMMIT, PAGE_READWRITE ); 

if (NULL==pSystemsHandleInformation)
{
pLockorInfo->bFlag=FALSE;
if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE); 
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}
return -1;
}

MyNtStatus=NtQuerySystemInformation(SystemHandleInformation,pSystemsHandleInformation,dwSize,&dwNeedSize);

if (STATUS_INFO_LENGTH_MISMATCH==MyNtStatus)
{
if (0 == dwNeedSize)
{
pLockorInfo->bFlag=FALSE;
if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE); 
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}
return -1;
}

VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE); 
pSystemsHandleInformation = (SYSTEM_HANDLE_INFORMATION*)VirtualAlloc( NULL,dwNeedSize, MEM_COMMIT, PAGE_READWRITE );  

if(NULL==pSystemsHandleInformation)
{
pLockorInfo->bFlag=FALSE;
if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE); 
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}
return -1;
}

}

MyNtStatus=NtQuerySystemInformation(SystemHandleInformation,pSystemsHandleInformation,dwNeedSize,NULL);

if (!NT_SUCCESS(MyNtStatus))
{
pLockorInfo->bFlag=FALSE;
if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE); 
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}
return -1;
}




for (dwIndex=0;dwIndex<pSystemsHandleInformation->Count;dwIndex++)
{
if(4==pSystemsHandleInformation->Handles[dwIndex].ProcessID)    //system惹不起
        {
continue;
}

//不是文件句柄的直接54
        if (pLockorInfo->ucOSFileHandleType!=pSystemsHandleInformation->Handles[dwIndex].HandleType)
{
continue;
}

if (dwCurProcessId==pSystemsHandleInformation->Handles[dwIndex].ProcessID)
{
bRemoteFlag=FALSE;
hTureHandle=(HANDLE)pSystemsHandleInformation->Handles[dwIndex].HandleNumber;
}
else
{
bRemoteFlag=TRUE;
hRemoteProcess=OpenProcess(PROCESS_DUP_HANDLE,FALSE,pSystemsHandleInformation->Handles[dwIndex].ProcessID);
if (hRemoteProcess!=NULL)
{

bDupliFlag=DuplicateHandle(hRemoteProcess,(HANDLE)pSystemsHandleInformation->Handles[dwIndex].HandleNumber,
hCurProcess,&hTureHandle,0,FALSE,DUPLICATE_SAME_ACCESS); //复制相同权限的handle
                
if (!bDupliFlag)
{
hTureHandle=NULL;
}
}

if (hRemoteProcess!=NULL)
{
CloseHandle(hRemoteProcess);
}
}

if (hTureHandle!=NULL)
{

//根据文件句柄获取文件路径
            if (MyGetFileNameByHandle(hTureHandle,pLockorInfo->szFileName))
{

pLockorInfo->bFlag=TRUE;
pLockorInfo->dwLockProcessId=pSystemsHandleInformation->Handles[dwIndex].ProcessID;
pLockorInfo->wLockHandle=pSystemsHandleInformation->Handles[dwIndex].HandleNumber;

MyCloseRemoteHandle(pSystemsHandleInformation->Handles[dwIndex].ProcessID,
(HANDLE)pSystemsHandleInformation->Handles[dwIndex].HandleNumber);

}

//每一次使用后,清理
            if (bRemoteFlag)
{
CloseHandle(hTureHandle);
}
}


}

if (pSystemsHandleInformation!=NULL)
{
VirtualFree(pSystemsHandleInformation, 0, MEM_RELEASE); 
}
if (hCurProcess!=NULL)
{
CloseHandle(hCurProcess);
}

return 0;
}

//根据文件句柄获取文件路径的线程
BOOL MyGetFileNameByHandle(__in HANDLE hFileHandle,__out WCHAR *szFileName)
{
BOOL bFindFlag=FALSE;
FILE_INFO FileInfo;
RtlZeroMemory(&FileInfo,sizeof(FileInfo));
FileInfo.bFlag=FALSE;
FileInfo.hFileHandle=hFileHandle;

HANDLE hQueryThread=CreateThread(NULL,0,MyQueryFileNameByHandleThreadFunc,&FileInfo,0,NULL);

if (WAIT_TIMEOUT == WaitForSingleObject(hQueryThread,100))
{
TerminateThread(hQueryThread,2);
}

if (FileInfo.bFlag)
{
if (0 == wcsicmp(szFileName,FileInfo.FileNameInfo.FileName))
{
bFindFlag=TRUE;
}
}

if (hQueryThread!=NULL)
{
CloseHandle(hQueryThread);
}

return bFindFlag;
}

DWORD WINAPI MyQueryFileNameByHandleThreadFunc(LPVOID pParam)
{
FILE_INFO *pFileInfo=(FILE_INFO*)pParam;

WCHAR wcVolume[3]={0};

NTSTATUS MyNtStatus;
IO_STATUS_BLOCK IoStatus;
UCHAR szBuff[0x1000];
RtlZeroMemory(szBuff,sizeof(szBuff));
FILE_NAME_INFORMATION *pFileNameInformation=(FILE_NAME_INFORMATION*)szBuff;

MyNtStatus=NtQueryInformationFile(pFileInfo->hFileHandle,&IoStatus,pFileNameInformation,
sizeof(FILE_INFO)-sizeof(HANDLE)-sizeof(BOOL),FileNameInformationClass);

if(NT_SUCCESS(MyNtStatus))
{
if(pFileNameInformation->FileNameLength!=0)
{
pFileInfo->bFlag=TRUE;
pFileInfo->FileNameInfo.FileNameLength=pFileNameInformation->FileNameLength;
if (MyGetVolumeNameByHandle(pFileInfo->hFileHandle,wcVolume))// 得到盘符
            {
RtlZeroMemory(pFileInfo->FileNameInfo.FileName,sizeof(pFileInfo->FileNameInfo.FileName));

pFileInfo->FileNameInfo.FileName[0]=wcVolume[0];
pFileInfo->FileNameInfo.FileName[1]=wcVolume[1];

wcsncpy(&pFileInfo->FileNameInfo.FileName[2],
pFileNameInformation->FileName,
pFileNameInformation->FileNameLength);

pFileInfo->FileNameInfo.FileName[2+pFileNameInformation->FileNameLength-1]=0;
}

}
}


return 0;
}

void GetOSVolumeSerialInfo(void)
{
RtlZeroMemory(&VolumeInfo,sizeof(VolumeInfo));

WCHAR szVolumeName[5]= {0};
WCHAR Drive='A';
DWORD dwDiskMask = GetLogicalDrives();
int nIndex=0;
for (nIndex=0; nIndex<26; nIndex++)
{
if( ( (1<<nIndex) & dwDiskMask )!=0)   
{
Drive = nIndex + 'A';
wsprintfW(szVolumeName,_T("%c:\\"),Drive);
wsprintfW(VolumeInfo[nIndex].szVolumeName,_T("%c:"),Drive);
GetVolumeInformation(szVolumeName,NULL,0,&VolumeInfo[nIndex].dwVolumeSerial,0,0,0,0);
}
}
}void GetOSVolumeSerialInfo(void)
{
RtlZeroMemory(&VolumeInfo,sizeof(VolumeInfo));

WCHAR szVolumeName[5]= {0};
WCHAR Drive='A';
DWORD dwDiskMask = GetLogicalDrives();
int nIndex=0;
for (nIndex=0; nIndex<26; nIndex++)
{
if( ( (1<<nIndex) & dwDiskMask )!=0)   
{
Drive = nIndex + 'A';
wsprintfW(szVolumeName,_T("%c:\\"),Drive);
wsprintfW(VolumeInfo[nIndex].szVolumeName,_T("%c:"),Drive);
GetVolumeInformation(szVolumeName,NULL,0,&VolumeInfo[nIndex].dwVolumeSerial,0,0,0,0);
}
}
}

BOOL MyGetVolumeNameByHandle(__in HANDLE hFile,__out WCHAR *szVolume)
{
DWORD dwIndex=0;
BY_HANDLE_FILE_INFORMATION stHandleFileInfo;
RtlZeroMemory(&stHandleFileInfo,sizeof(stHandleFileInfo));

GetFileInformationByHandle(hFile,&stHandleFileInfo);
for(dwIndex=0; dwIndex<26; dwIndex++)
{
if (stHandleFileInfo.dwVolumeSerialNumber!=0)
{
if (stHandleFileInfo.dwVolumeSerialNumber==VolumeInfo[dwIndex].dwVolumeSerial)
{
wcscpy(szVolume,VolumeInfo[dwIndex].szVolumeName);
return TRUE;
}
}
}
return FALSE;
}

//结束pid=dwProcessId中的hRemoteHandle句柄
BOOL MyCloseRemoteHandle(__in DWORD dwProcessId,__in HANDLE hRemoteHandle)
{
HANDLE hExecutHandle=NULL;
BOOL bFlag=FALSE;
HANDLE hProcess=NULL;
HMODULE hKernel32Module=NULL;

hProcess=OpenProcess(
PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, 
FALSE,dwProcessId); 

if (NULL==hProcess)
{
bFlag=FALSE;
goto MyErrorExit;
}

hKernel32Module = LoadLibrary( _T("kernel32.dll") );   

hExecutHandle = CreateRemoteThread(hProcess,0,0,  
(DWORD (__stdcall *)( void *))GetProcAddress(hKernel32Module,"CloseHandle"),   
hRemoteHandle,0,NULL);

if (NULL==hExecutHandle)
{
bFlag=FALSE;
goto MyErrorExit;
}

if (WaitForSingleObject(hExecutHandle,2000)==WAIT_OBJECT_0)
{
bFlag=TRUE;
goto MyErrorExit;
}
else
{
bFlag=FALSE;
goto MyErrorExit;
}



MyErrorExit:

if (hExecutHandle!=NULL)
{
CloseHandle(hExecutHandle);
}

if (hProcess !=NULL)
{
CloseHandle(hProcess);
}

if (hKernel32Module!=NULL)
{
FreeLibrary(hKernel32Module); 
}
return bFlag;
}

//根据PID获取进程名
BOOL MyGetProcessNameByPID(DWORD dwProcessId,WCHAR *szProcessName)
{
BOOL bReturnFlag=FALSE;
PROCESSENTRY32* pProcessInfo=new PROCESSENTRY32;

pProcessInfo->dwSize=sizeof(PROCESSENTRY32);

HANDLE MyHandProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);

BOOL bFlag=Process32First(MyHandProcessSnap,pProcessInfo);

while (bFlag)
{
if (dwProcessId==pProcessInfo->th32ProcessID)
{
wcscpy(szProcessName,pProcessInfo->szExeFile);
bReturnFlag=TRUE;
break;
}
bFlag=Process32Next(MyHandProcessSnap,pProcessInfo);
}

if(pProcessInfo!=NULL) 
{
delete pProcessInfo;
pProcessInfo=NULL;
}

if (MyHandProcessSnap!=NULL)
{
CloseHandle(MyHandProcessSnap);
}
return bReturnFlag; 
}

//根据PID获取进程路径
BOOL MyGetProcessPathByPID(DWORD dwProcessId,WCHAR *szProcessPath)
{
HANDLE hModule;
MODULEENTRY32* pMoudleInfo=new MODULEENTRY32;
pMoudleInfo->dwSize=sizeof(MODULEENTRY32);
hModule=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,dwProcessId); 
Module32First(hModule,pMoudleInfo);

wcscpy(szProcessPath,pMoudleInfo->szExePath);

if(pMoudleInfo!=NULL) 
{
delete pMoudleInfo;
pMoudleInfo=NULL;
}

if (hModule!=NULL)
{
CloseHandle(hModule);
}
return TRUE; 
}

原文地址:https://www.cnblogs.com/lzjsky/p/1892680.html