VB实现COM接口针对返回S_FALSE时的COM HOOK

这几天在写HtmlUI的VB6版本,Browser端原来折腾过,并且代码都在,还算好说,Server端用Asynchronous Pluggable Protocols,遍地求代码求不到,最后只得自己研究E文的MSDN,主要是要实现IInternetProtocol接口。

用VB写过COM的同学应该都知道,实现接口时VB是没法直接返回HRESULT的,通常的做法是什么都不做就代表S_OK,用Err.Raise E_XXXX返回错误。

在实现IInternetProtocol时,和往常一样,开始是一大堆的S_OK和一大堆的E_NOTIMPL,执行时发现IInternetProtocol::Read函数一直会被调用,查下MSDN得知如果数据全部发送完毕则返回S_FALSE。于是在函数结尾写上Err.Raise S_FALSE。然后奇怪的问题就来了,从断点命中来看,Start、Read、Terminate都是按顺序执行的,但页面却无法显示。折腾半天未果,遂找了份前人写过的代码比对(http://www.vbgood.com/thread-91065-1-1.html,估计这份代码是全世界唯一的APPVB版公开代码)。

这份代码用的是手工的纯C语言式接口实现,执行正常。断点命中表示Read函数被调用了多次,而我的代码只被调用了一次。联想到昨天实现IClassFactory时Err.Raise pUnknown.QueryInterface(…)的写法莫名其妙地罢工而改成hr = pUnknown.QueryInterface(…)  If hr <> 0 Then Err.Raise hr就好了,推测Err.Raise不能用来返回正确的错误码。打开OD,通过内存断点断到Read函数里,在urlmon.dll的返回地址处断下,果然,Err.Raise S_FALSE的返回值并非1,而是0x800A0001。

Google了国内外一圈,没有找到有关S_FALSE的快速解决办法。考虑到既能解决这个问题又能保全VB在COM应用上的方便性,决定用Com Hook解决。

Com Hook,和API Hook类似(导入导出表修改方式,非inline hook),只不过这次Hook的是COM的虚函数表,将原有虚函数表中的函数地址替换成我们的地址,改变程序流程,做点手脚。具体做法请复习32位汇编与com原理,下面贴代码~

Private Sub DoHook_IInternetProtocol_Read()
    Dim pInternetProtocol As olelib.IInternetProtocol
    Dim pVTable As Long, pFuncInternetProtocol_Read As Long, dwCode As Long
    Set pInternetProtocol = Me
    CopyMemory pVTable, ByVal ObjPtr(pInternetProtocol), 4
    CopyMemory pFuncInternetProtocol_Read, ByVal pVTable + 4 * 9, 4
    CopyMemory dwCode, ByVal pFuncInternetProtocol_Read, 4
    If dwCode <> &H102474FF Then
        Dim pAlloc As Long, jmpOffset As Long, bCode() As Byte
        pAlloc = VirtualAlloc(ByVal 0, &H1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
        bCode = Hex2Byte("FF742410FF742410FF742410FF742410E8000000003D01000A807505B801000000C210")
        CopyMemory ByVal pAlloc, bCode(0), UBound(bCode) + 1
        jmpOffset = pFuncInternetProtocol_Read - (pAlloc + 21)
        CopyMemory ByVal pAlloc + 17, jmpOffset, 4
 
        VirtualProtect ByVal pVTable, &H1000, PAGE_EXECUTE_READWRITE, dwCode
        CopyMemory ByVal pVTable + 4 * 9, pAlloc, 4
    End If
End Sub

以上代码在Class_Initialize中调用。

因为仅仅是一个函数遇到这样的问题,个例,所以hook也就只针对一个函数,目前尚未考虑写一个通用的处理函数。先这样放着吧~

One Reply to “VB实现COM接口针对返回S_FALSE时的COM HOOK”

  1. 博主有联系方式吗,我有个VB中如何仿电子书使用异步可插入协议的问题想向你请教,不知可否?

Leave a Reply

Your email address will not be published. Required fields are marked *