zoukankan      html  css  js  c++  java
  • [转]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; 
    }

  • 相关阅读:
    网络编程前戏
    上传文件数据到数据库
    SpringMVC点滴(1)
    python全栈学习--day2
    python全栈学习--day1
    python练习册 每天一个小程序 第0013题
    python练习册 每天一个小程序 第0012题
    python练习册 每天一个小程序 第0011题
    [XMAN筛选赛](web)ctf用户登录
    python练习册 每天一个小程序 第0010题
  • 原文地址:https://www.cnblogs.com/lzjsky/p/1892680.html
Copyright © 2011-2022 走看看