现在的位置: 首页 > 综合 > 正文

VB Ring3下解锁文件的模块(修正及一些新的想法)

2013年11月25日 ⁄ 综合 ⁄ 共 4721字 ⁄ 字号 评论关闭

发这篇文章之前我想说些心里话,希望大家不要闲我罗嗦.我经常和老魏(Modest【塞北雪貂】)在讨论,VB版的人气越来越差了,我心里在着急,也在难过,说实话我不希望这样的现象出现,更不希望VB从此没落.但是我相信VB不会倒下我们CSDN上的VB版也不会倒下,因为我们大家都不会放弃它,对吗?所以我希望大家发扬共享精神把你宝贵的源码优秀的源码贴出来给大家一起分享吧,多花一点点时间来给大家解决问题,多...好了不说了.
 
前些天发了一篇关于"VB Ring3下解锁文件的模块"的文章(注意这篇文章也是参考了网络上一篇VC的代码),昨天回过头来看了下发现了些小小的问题和一些可以优化或更好的方法现在整理一下给大家.

比如:VB当知道某个进程占用(锁定了对某个文件的操作),我们现在怎么办呢?当然有了我写的这篇文章大家可以说那就解锁啊!知道是哪个进程锁定了还不简单?其实并不是这么简单,问题就出在怎么解锁.当然有的朋友肯定会说使用一个DLL注入到目标进程进行解锁.OK这个方法可行,不错,我开始的程序也这样设计.但是想了下这样局限很大.原因有二.一:VB本来就很难解决标准的DLL的问题.二:就算解决了第一个问题那么第二个问题是什么呢?相信大家都知道CreateRemoteThread这个函数功能是非常强大的,可以做N多事情,当然往往是些木马和病毒利用上了,也正是因为它强大不光是木马和病毒制造者对它十分关注就连杀毒软件也非常关注它,所以几乎都对此函数进行了不同级别的Hook,这样就存在了一个问题,当你使用注入方式的时候可能有些杀毒软件会误报你的程序是危险程序什么的,对用户是非常不好的.那么存在这样的问题就没办法解决了吗?不急我慢慢说来,办法是有的可能还存在多种.最简单也是最难也是大家最先想到的方法。方法就是,使用更高更隐秘的技术让杀毒软件查不到或者直接饶过它的检测,当然你是个高手的话可以,但是我相信就算是饶过了也只是暂时的.我并不推荐这种方法,虽然我自己在这方面做了很多试图...也有了相当的成就,但是这终究不是十分理想的一个主意.那么没有更好的方法了吗?有!大家知道"DuplicateHandle"这个函数吗?不错就是进行句柄复制的函数前一篇文章中就用到了它.不知道大家有没有用到当它使用"DUPLICATE_CLOSE_SOURCE"做参数时,对了这就是解决问题的关键.只要这样复制的句柄我们就可以在本进程关闭远程进程的句柄了.所以我们可以这样写下面类似的代码来完成对锁定文件的释放.

'解锁指定进程的锁定文件
Public Function CloseRemoteHandle(ByVal dwProcessId, ByVal hHandle As Long) As Boolean
    Dim hMyProcess  As Long, hRemProcess As Long, blnResult As Long, hMyHandle As Long
    Dim objCid As CLIENT_ID
    Dim objOa As OBJECT_ATTRIBUTES
    Dim ntStatus As Long
    objCid.UniqueProcess = dwProcessId
    objOa.Length = Len(objOa)
    hMyProcess = GetCurrentProcess()
    ntStatus = NtOpenProcess(hRemProcess, PROCESS_DUP_HANDLE, objOa, objCid)
    If hRemProcess Then
        ntStatus = NtDuplicateObject(hRemProcess, hHandle, GetCurrentProcess, hMyHandle, 0, 0, DUPLICATE_CLOSE_SOURCE Or DUPLICATE_SAME_ACCESS)
        If (NT_SUCCESS(ntStatus)) Then
        'If DuplicateHandle(hRemProcess, hMyProcess, hHandle, hMyHandle, 0, 0, DUPLICATE_CLOSE_SOURCE Or DUPLICATE_SAME_ACCESS) Then
            blnResult = NtClose(hMyHandle)
        End If
        Call NtClose(hRemProcess)
    End If
    CloseRemoteHandle = blnResult
End Function

是不是很神奇啊?是不是不相信?不是说不能跨进程间操作吗...什么什么的,具体的你去查MSDN吧,或者你自己试试看就知道了,相信实践出真理.

完成了文件解锁只能说是完成了一半的一半,为什么这么说呢??如果大家有利用我之前写的模块的朋友肯定会发现个奇怪的地方,就是在做全局文件搜索时有时会卡死造成线程死锁,而且一但程序死锁就会造成程序挂起,而且这种挂起是非常恐怖的,不但程序不能正常退出,就算是用任务管理器也无法结束,甚至是冰刃拿它也没办法,只能通过冰刃强制结束线程的方式去把它干掉.为什么会发生这样的情况呢??不知道有遇到这样情况的朋友吗?你们分析过跟踪过了吗?我不会汇编调试跟踪什么的,我只作了简单的程序跟踪,发现问题发生在NtQueryObject 这个函数上,当对某个进程执行此函数时会造成刚才的现象.那我说的是不是真理呢?或许你自己去跟踪下你会发觉我说的是正确的.但是你错了我也错了造成这样死锁的情况不是这样函数直接造成的?开始我也以为关键问题在这里,我也进行了大量程序测试.我甚至在VC里用线程对这个函数进行了测试,结果都是锁在这个函数这里.这就造成了我以为问题根源就在这个函数中,直到前两天我在网上看到了一篇文章也是关于用NtQueryObject 获取文件路径的程序片段,我开始觉得没什么看的,因为自己早已经掌握了,就不经意的看了下,但是当我看到了一个根本没用的函数出现在我的视线中时,我开始还觉得作者为什么写了个无聊的函数呢?这个函数是什么呢?它就是"GetFileType",当我看到这里我就认真的看了下,我想作者不会平白无故的多出一个函数,后来才知道他还用了线程处理,代码片段是这样的.

DWORD WINAPI HookSing(LPVOID lpParam)
{
    HANDLE hFile=(HANDLE)lpParam;
    GetFileType(hFile);
    return 0;
}

DWORD dwTid=0;
HANDLE hThread =CreateThread(NULL,0,HookSing,hFile,0,&dwTid);
DWORD dwEax=WaitForSingleObject(hThread,100);
if(dwEax==STATUS_TIMEOUT)
{
       DWORD dwTimeOut=0;
       GetExitCodeThread(hThread,&dwTimeOut);
       TerminateThread(hThread,dwTimeOut);
       CloseHandle(hThread);
       continue;//这里要注意(这里有个循环而且这个continue是必须的一但没这个当执行到这里被后面的NtQueryObject 执行就会引起上面所说的现象)
 }

这就是解决问题的关键,好了我说了这么多废话也许有的朋友看得都快睡觉了,那么我们就赶快进去入正题吧.

既然知道了问题所在那么我们现在怎么解决呢?有的人会说那就按上面的代码类似的处理就OK了.但是说的容易,做起来就难?难在哪呢?那就难在CreateThread这个函数,相信大家对这个函数并不陌生,相信大家在这个函数上都栽过跟头,没错Vb对多线程处理上就这么麻烦.我在这里也做了相当多办法来处理这个问题,但是都是最终落败,我甚至想到了hook  GetFileType等等方法都失败了,难道就没办法了?呵呵,这个问题留给下回再讨论.我该做事了,出差快两个月了,我十分想回家了,再不加油我就回不去了.

下面我再给一种注入的方式解决解锁文件的问题,但是这个注入方式有点不一样是不需要DLL,而是执行了CloseHandle这个函数,代码如下:

'解锁指定进程的锁定文件
Public Function CloseRemoteHandleEx(ByVal dwProcessId, ByVal hHandle As Long) As Boolean
    Dim hRemProcess As Long, hThread As Long, lngResult As Long, pfnThreadRtn As Long, hKernel As Long
    Dim objCid As CLIENT_ID
    Dim objOa As OBJECT_ATTRIBUTES
    Dim ntStatus As Long
    objCid.UniqueProcess = dwProcessId
    objOa.Length = Len(objOa)
    ntStatus = NtOpenProcess(hRemProcess, PROCESS_QUERY_INFORMATION Or PROCESS_CREATE_THREAD Or PROCESS_VM_OPERATION Or PROCESS_VM_WRITE, objOa, objCid)
'    hMyProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_CREATE_THREAD Or PROCESS_VM_OPERATION Or PROCESS_VM_WRITE, 0, dwProcessId)
    If hRemProcess = 0 Then
        CloseRemoteHandleEx = False
        Exit Function
    End If
    hKernel = GetModuleHandle("kernel32")
    If hKernel = 0 Then
        CloseRemoteHandleEx = False
        Exit Function
    End If
    pfnThreadRtn = GetProcAddress(hKernel, "CloseHandle")
    If pfnThreadRtn = 0 Then
        FreeLibrary hKernel
        CloseRemoteHandleEx = False
        Exit Function
    End If
    hThread = CreateRemoteThread(hRemProcess, ByVal 0&, 0&, ByVal pfnThreadRtn, ByVal hHandle, 0, 0&)
    If hThread = 0 Then
        FreeLibrary hKernel
        CloseRemoteHandleEx = False
        Exit Function
    End If
    GetExitCodeThread hThread, lngResult
    CloseRemoteHandleEx = CBool(lngResult)
    NtClose hThread
    NtClose hRemProcess
    FreeLibrary hKernel
End Function

欢迎大家多多考虑,一起研究,一起把VB发扬光大,使我们vb版重现辉煌!!

抱歉!评论已关闭.