上篇文章我们更深入的讨论了"VB Ring3下解锁文件的模块"那篇文章,这次我将和大家完美解决上篇文章存在的一系列问题。在这次讨论前先容许我给大家说声“对不起!”。由于最近我一直出差在外地,所以在发表这几篇文章时都比较仓促,一般都是一时兴起写出来的文章,就连代码都没有经过严格测试,还有就是由于时间的问题,所以文章和源码内没有添加详细的注释,希望大家见谅(本来写得程序就臭,再加上没注释相信让很多朋友无法读懂吧!希望不要误导大家)。这次我将尽量给大家详细的注释和一些有必要的提示,和大家共同探讨相关问题,用纯VB代码打造一个Ring3下解锁文件(USB设备)的简单工具。
    我们先回顾上篇文章还没有解决的系列问题,再做总结然后再谈下我们没有考虑的问题和我们即将做出什么样的工具以及此工具的扩展等等。
    没有解决的问题:
    在做全进程锁定文件扫描时会造成进程死锁。解决办法上篇文章我提了下,是用线程来解决。那么我们现在就得解决VB多线程的问题。(下面深入讨论)
    我们需要做出什么样的工具来?
    这次我们先做简单点,能把锁定的文件释放就OK了?
    扩展方面:
    解锁USB设备,卸载USB设备,解锁DLL文件,USB设备使用限制等(这个问题留给下篇文章吧)。    现在我们逐个讨论,先讨论"没有解决的问题".这是个难题,相信大家都会第一时间想到从CreateThread这个函数下手,尽量做出稳定的线程来。好有此想法不错,但是我觉得不是最佳的选择。先不说是否能做出稳定的线程出来,我们的目标是要以最简单最方面最安全的做法来完成。其实在上篇文章中我已经不是很明显的把一种解决方式给大家了,不知道大家留意了没有。先请大家回顾下在VC在的解决方案吧。代码如下,我们分析下:
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 执行就会引起上面所说的现象)
 }    大家看明白了上面代码的用处了没有,如果没看懂的我给大家解释一下(也许我理解的也不是很正确,希望大家见谅).首先我们先说下"HookSing"这个函数的着用。这个函数的着用其实就是判断传进来的文件句柄是否能让NtQueryObject调用。也许我这句话说得很让大家不明白,我在这里就给大家解释解释。还记得上次我们讨论了为什么进程会被死锁的情况问题,通过我的测试和了解发现问题是在GetFileType这个函数上(也许我发现的并不一定正确,有兴趣的可以自己分析下),而不是NtQueryObject这个函数,应该说不直接是这个函数造成的。现在我再说下为什么不是"NtQueryObject"直接导致死锁的原因。不知道大家有没有对死锁的原因作深入研究和测试,大家有没有这样测试过,在调用"NtQueryObject"函数之前先调用GetFileType,如果你测试过的话你会发现,程序会在"GetFileType"函数上卡住(死锁)。也许有的朋友会反问我。你上篇文章不是说调用了"NtQueryObject"才会造成死锁的吗?对!大家说的没错,如果直接调用"NtQueryObject"有可能会造成死锁,但是就我估计"NtQueryObject"在调用之前应该先调用了"GetFileType"这个函数造成的,究竟是不是这样我也不知道,我也是估计,有兴趣或者对反汇编有研究的朋友可以跟踪下。我们这次旨在解决问题,我就先假设我的猜测是对的。那么我们现在的问题就是怎么判断句柄是否能让"NtQueryObject"调用。好的我们再看下上面的VC代码,很明显程序建立了一个线程并且作了超时处理,这很重要也是解决问题的关键所在,当"GetFileType"不能正常获取文件句柄类型时就不能给"NtQueryObject"函数调用,不然就会死锁(大家不要问我原因,因为我也不知道)。一但无法获取,也就是线程执行超时,我们就把线程终止掉并且让程序执行下次循环,注意是让程序执行下次循环而不是继续执行,这是有区别的,如果让程序继续执行的话就会死锁,所以我特别在"continue;"后注释了这是必须的。好现在解决问题的方法我们基本上也了解了,现在的问题就是怎么在VB上实现此功能。很遗憾如果你试图使用CreateThread写类似代码来解决此问题时,你会失败,也许会偶尔成功,但是也不是很稳定的,我说了这次我们要安全稳定的解决此问题。那么没其他好办法了吗?我说过我开始也试图了很方法失败了,解决此问题不是那么简单,但是也不是那么难,如果大家够细心的话,应该留意到了上篇文章其实我已经给出了一种解决方案。那么解决方法是什么呢?呵呵,还记得上次我最后留给大家解锁文件的一种方案吗?不错,正是类似的方法,正是"CreateRemoteThread"的这个强大的函数,我们就要用它来解决我们创建线程的问题。在这里我简单说下CreateRemoteThread这个函数吧。这个函数的功能是在远程创建一个线程(这里的远程也可以是本进程,大家不要被“远程”这两个字误导了).对我们就需要这个函数的功能。其实不管是"CreateThread"还是"CreateRemoteThread"最终都得调用NtCreateThread这个函数,但是奇怪的是在VB中用CreateThread创建线程就是不那么稳定,相信和VB库文件有很大的关系,但是更奇怪的是在VB中使用CreateRemoteThread却相对稳定的多。我们就要稳定,如果大家到现在还没明白解决方法的话,我们再对CloseRemoteHandleEx这个函数做下分析。'解锁指定进程的锁定文件
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) '这里是打开进程获取句柄(这次我们是对于自己的进程所以这句可以直接用GetCurrentProcess代替即可)
'    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
    '获取DLL基地址
    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我对上面代码对关键处做了注释相信大家应该看得明白,如果不明白,先看下下面我用来解决此问题的代码,我再做详细的解释。Private Function MyGetFileType(ByVal hFile As Long) As Long
    Dim hRemProcess As Long, hThread As Long, lngResult As Long, pfnThreadRtn As Long, hKernel As Long
    Dim dwEax As Long, dwTimeOut As Long
    '进程句柄,这里我们只需要传GetCurrentProcess即可
    hRemProcess = GetCurrentProcess
    '获取DLL基地址
    hKernel = GetModuleHandle("kernel32")
    If hKernel = 0 Then
        MyGetFileType = 0
        Exit Function
    End If
    '获取GetFileType函数地址
    pfnThreadRtn = GetProcAddress(hKernel, "GetFileType")
    If pfnThreadRtn = 0 Then
        FreeLibrary hKernel
        MyGetFileType = 0
        Exit Function
    End If
    '建立本地线程,参数传hFile(需要检测的文件句柄),在调用CreateRemoteThread的时候注意参数传递,不要把
    '地址传递和值传递搞错了,在这里我就不多说了。
    hThread = CreateRemoteThread(hRemProcess, ByVal 0&, 0&, ByVal pfnThreadRtn, ByVal hFile, 0, ByVal 0&)
    '检测超时
    dwEax = WaitForSingleObject(hThread, 100)
    If dwEax = &H102 Then
        '如果超时了就把线程结束返回0好程序不执行NtQueryObject
        Call GetExitCodeThread(hThread, dwTimeOut)
        Call TerminateThread(hThread, dwTimeOut)
        NtClose hThread
        MyGetFileType = 0
        FreeLibrary hKernel
        Exit Function
    End If
    If hThread = 0 Then
        FreeLibrary hKernel
        MyGetFileType = False
        Exit Function
    End If
    '获取函数返回值,如果值大于0表示函数正确执行也就是说可以让NtQueryObject调用
    GetExitCodeThread hThread, lngResult
    MyGetFileType = lngResult
    NtClose hThread
    NtClose hRemProcess
    FreeLibrary hKernel
End Function好了问题解决了,快去测试吧,我相信你能打造出出色的工具来。如果大家还有什么问题,可以到我博客上留言吧。下次我再和大家一起讨论"解锁USB设备,卸载USB设备,解锁DLL文件,USB设备使用限制",希望大家不要缺场~~

解决方案 »

  1.   

    文中涉及的地址如下:VB Ring3下解锁文件的模块(一) CSDN地址是:http://topic.csdn.net/u/20070925/11/c0fa3831-e732-46f2-81e3-2465d0577151.html?1416895339VB Ring3下解锁文件的模块(一) 博客地址:http://blog.csdn.net/chenhui530/archive/2007/10/03/1810300.aspxVB Ring3下解锁文件的模块(修正及一些新的想法)CSDN地址:http://topic.csdn.net/u/20071018/17/a7f9a162-e224-4e80-8a41-ead1c29bb6c9.htmlVB Ring3下解锁文件的模块(修正及一些新的想法)博客地址:http://blog.csdn.net/chenhui530/archive/2007/10/18/1831372.aspx
      

  2.   

    上次的贴子中说用注入的方法,可是我在实验注入的时候,机器就会死机。
    后来查到是XP的系统,硬件好像有个什么PDE保护功能,结果一注入就死机,有什么办法吗?