今天突发奇想终于把VB下的“函数指针”实现了。
我先解释下VB下的“函数指针”是什么意思吧!相信大家都遇到这样一些尴尬的问题。
问题一:一个未到处的函数,知道声明在VB中怎么调用它能,相信有研究的人都会想些方法五外乎下面几种。(1)使用CreateRemoteThread建立一个线程来执行它,这里我们先别谈它的执行效率,都存在一个问题,参数只能是一个或者是没有参数的函数,如果这个未导出的函数参数有多个能,显然就不能使用这个函数来解决了。(2)CallWindowProc这个函数也能执行函数,但是显然还是存在参数问题。
问题二:自己写了段ShellCode怎么执行能?当然上面说的几种方法都行,但是还是脱离不了参数的困扰。
问题三:在VB下进行API Hook时的尴尬,现在很多代码都是当需要调用原函数前的时候先恢复原来hook的代码然后再调用,然后再hook,这里存在严重的效率和潜在问题。
等等还有些问题就不列举了。难道就没一种方法能象C等语言那样声明一个函数指针,然后让函数指针指向这个地址,然后CALL的方法了吗?我在这个问题上也想过,但是苦于没有找到好的方法解决一直,没有实质性的突破,今天终于突发奇想,实践证明了VB也是可以使用函数指针的。我的方法是利用API Hook技术来实现的,由于代码没有经过严格封装,所以暂时不贴全,贴点关键点的,大家一起来讨论。我先说下我的思路,我一开始就留意到了msvbvm60的导出函数DllFunctionCall,没错就是它,它是我们在使用API函数时的一个封装体,在内部实现了GetProcAddress+GetModuleHandle来实现获取函数的地址,在这之前先进行了压栈操作,当函数地址获取完后就直接jmp过去了,具体自己可以使用OD或者IDA去察看。我现在把这个函数进行了hook,并且在内部维护;两张表,一张存放函数地址的一张存放函数名称的,并且这两张表是一一对应的,当检测到我需要调用的函数时,就把对应的函数地址返回给DllFunctionCall这样我们就实现了移花接木的功能。
请看下面声明Public Declare Function DeleteFileW Lib "msvbvm60.dll" (ByVal lpszFileName As Long) As Long
其实这个声明在msvbvm60是不存在的,但是没关系我们就是要这样做,当然函数名称你可以任意取但是别和msvbvm60到处的函数名字一样就行。这时DeleteFileW和就可以是我自己指定的地址了,当然这个地址的函数原型是要和上面声明的一样的才行。这样当在程序里调用DeleteFileW的时候其实已经跳转到了我想要跳转到的地址,这样就实现了VB下的“函数指针”的功能了。好大家看下面的关键代码。Public Function InitHook() As Boolean
    mszmsvbvm60 = StrConv("msvbvm60.dll", vbFromUnicode) '这里需要村Ansi字符串类型
    '这里我最多维护1024个元素
    glpdwFunAddresses = VirtualAlloc(ByVal 0&, 4 * 1024, MEM_COMMIT, PAGE_READWRITE) '地址表
    glpdwFunNames = VirtualAlloc(ByVal 0&, CLng(128 * CLng(1024)), MEM_COMMIT, PAGE_READWRITE) '名称表
    
    InitHook = glpdwFunAddresses <> glpdwFunNames <> 0
End FunctionPublic Function HookDllFunctionCall() As Boolean
    Dim ShellCode(0 To &H1000) As Byte
    Dim OldProtect As Long
    Dim bytValue As Byte
    Dim dwValue As Long
    Dim wValue As Integer
    Dim dwFunAddress As Long
    Dim bytHookCode(0 To 4) As Byte
    
    ShellCode(0) = &H55
    wValue = &HEC8B
    CopyMemory ByVal VarPtr(ShellCode(1)), ByVal VarPtr(wValue), 2
    wValue = &HEC83
    CopyMemory ByVal VarPtr(ShellCode(&H3)), ByVal VarPtr(wValue), 2
    ShellCode(5) = &H8
    wValue = &H458B
    CopyMemory ByVal VarPtr(ShellCode(&H6)), ByVal VarPtr(wValue), 2
    ShellCode(8) = &H8
    ShellCode(9) = &H53
    ShellCode(&HA) = &H56
    wValue = &H358B
    CopyMemory ByVal VarPtr(ShellCode(&HB)), ByVal VarPtr(wValue), 2
    dwValue = VarPtr(glpdwFunNames)
    CopyMemory ByVal VarPtr(ShellCode(&HD)), ByVal VarPtr(dwValue), 4
    wValue = &H88B
    CopyMemory ByVal VarPtr(ShellCode(&H11)), ByVal VarPtr(wValue), 2
    wValue = &H408B
    CopyMemory ByVal VarPtr(ShellCode(&H13)), ByVal VarPtr(wValue), 2
    ShellCode(&H15) = &H4
    ShellCode(&H16) = &H57
    wValue = &H3D8B
    CopyMemory ByVal VarPtr(ShellCode(&H17)), ByVal VarPtr(wValue), 2
    dwValue = VarPtr(glpdwFunAddresses)
    CopyMemory ByVal VarPtr(ShellCode(&H19)), ByVal VarPtr(dwValue), 4
    ShellCode(&H1D) = &H68
    dwValue = StrPtr(mszmsvbvm60)
    CopyMemory ByVal VarPtr(ShellCode(&H1E)), ByVal VarPtr(dwValue), 4
    ShellCode(&H22) = &H51
    ShellCode(&H23) = &HC7
    '....由于篇幅省略一长串
    dwFunAddress = GetProcAddress(GetModuleHandle("msvbvm60.dll"), "DllFunctionCall")

解决方案 »

  1.   

        If dwFunAddress Then
            CopyMemory ByVal VarPtr(gbytDllFunCallOldCode(0)), ByVal dwFunAddress, 6
            glpdwDllFunCallProxyAddress = VirtualAlloc(ByVal 0&, &H1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
            
            If glpdwDllFunCallProxyAddress Then
                CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200, ByVal dwFunAddress, 6
                bytValue = &HB8
                CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 6, ByVal VarPtr(bytValue), 1  'mov eax,DllFunctionCall
                dwValue = dwFunAddress
                CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 7, ByVal VarPtr(dwValue), 4
                wValue = &HC083
                CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 11, ByVal VarPtr(wValue), 2  'add eax,5
                bytValue = &H6
                CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 13, ByVal VarPtr(bytValue), 1
                wValue = &HE0FF
                CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 14, ByVal VarPtr(wValue), 2 'jmp eax
                
                dwValue = glpdwDllFunCallProxyAddress + &H200
                CopyMemory ByVal VarPtr(ShellCode(&H83)), ByVal VarPtr(dwValue), 4
                wValue = &HD0FF
                CopyMemory ByVal VarPtr(ShellCode(&H87)), ByVal VarPtr(wValue), 2
                wValue = &H4589
                CopyMemory ByVal VarPtr(ShellCode(&H89)), ByVal VarPtr(wValue), 2
                wValue = &H458B
                ShellCode(&H8B) = &HF8
                CopyMemory ByVal VarPtr(ShellCode(&H8C)), ByVal VarPtr(wValue), 2
                ShellCode(&H8E) = &HF8
                ShellCode(&H8F) = &H5F
                ShellCode(&H90) = &H5E
                ShellCode(&H91) = &H5B
                wValue = &HE58B
                CopyMemory ByVal VarPtr(ShellCode(&H92)), ByVal VarPtr(wValue), 2
                ShellCode(&H94) = &H5D
                wValue = &H4C2
                CopyMemory ByVal VarPtr(ShellCode(&H95)), ByVal VarPtr(wValue), 2
                ShellCode(&H97) = &H0
        
                
                CopyMemory ByVal glpdwDllFunCallProxyAddress, ByVal VarPtr(ShellCode(0)), &H98
                MsgBox Hex(glpdwDllFunCallProxyAddress)
                bytHookCode(0) = &HE9
                dwValue = glpdwDllFunCallProxyAddress - dwFunAddress - 5
                CopyMemory ByVal VarPtr(bytHookCode(1)), ByVal VarPtr(dwValue), 4 '构造hook Code
                VirtualProtect ByVal dwFunAddress, 6, PAGE_EXECUTE_READWRITE, OldProtect '更改函数地址所在页面属性
                CopyMemory ByVal dwFunAddress, ByVal VarPtr(bytHookCode(0)), 5 'hook
                VirtualProtect ByVal dwFunAddress, 6, OldProtect, OldProtect '更改函数地址所在页面属性
                HookDllFunctionCall = True
            End If
        End If
    End FunctionPublic Sub UnhookDllFunctionCall()
        Dim dwFunAddress As Long
        Dim OldProtect As Long
        
        dwFunAddress = GetProcAddress(GetModuleHandle("msvbvm60.dll"), "DllFunctionCall")    If dwFunAddress Then
            If glpdwDllFunCallProxyAddress Then
                VirtualProtect ByVal dwFunAddress, 6, PAGE_EXECUTE_READWRITE, OldProtect '更改函数地址所在页面属性
                CopyMemory ByVal dwFunAddress, ByVal VarPtr(gbytDllFunCallOldCode(0)), 6 'hook
                VirtualProtect ByVal dwFunAddress, 6, OldProtect, OldProtect '更改函数地址所在页面属性
                Sleep 100
                VirtualFree ByVal glpdwDllFunCallProxyAddress, 0, MEM_RELEASE
            End If
        End If
        
        If glpdwFunAddresses Then
            VirtualFree ByVal glpdwFunAddresses, 0, MEM_RELEASE
        End If
        If glpdwFunNames Then
            VirtualFree ByVal glpdwFunNames, 0, MEM_RELEASE
        End If
    End Sub下面是VB下的“函数指针”的一个应用'***************************************************************************************
    '参数说明
    'lpszLibName 需要hook的函数所在动态库名称
    'lpszFunName 需要Hook的函数名
    'lpdwFunCallback 跳转函数(处理)的地址,使用AddressOf获取
    'lpdwFunAddressPtr 这个参数和上面Hook的DllFunctionCall维护匹配的表
    '有关系的。如果同时需要hook多个函数的话,就需要维护这张表了
    '名称和代理函数地址成对称存在,各自起始地址是glpdwFunAddresses和glpdwFunNames
    '其中glpdwFunAddresses以4为单位增长,glpdwFunNames以128个字节为单位增长,也就说明
    '需要Hook的函数名称长度不能长过127个字节glpdwFunAddresses存放的是每个hook函数的一个
    '代理函数地址,这个地址是由HookApi函数内部生成并且管理,请保证glpdwFunNames和glpdwFunAddresses
    '对应,打个比方你现在准备hook两个函数。其中一是:DeleteFileA另一个是DeleteFileW,那么你就应该按
    '下面的方法来的来调用函数过程
    '1,Call HookApi("kernel32.dll", "DeleteFileA", AddressOf DeleteFileACallback, glpdwFunAddresses,glpdwFunNames) 'Hook DeleteFileA
    '2,Call HookApi("kernel32.dll", "DeleteFileW", AddressOf DeleteFileWCallback, glpdwFunAddresses+4,glpdwFunNames+128) 'Hook DeleteFileW
    Public Function HookApi(ByVal lpszLibName As String, _
                            ByVal lpszFunName As String, _
                            ByVal lpdwFunCallback As Long, _
                            ByVal lpdwFunAddressPtr As Long, _
                            ByVal lpdwFunNamePtr As Long _
                            ) As Boolean
      

  2.   

    这样也行?
    不过那段shellcode有点晕。。
      

  3.   

    你太厉害了!bikinis sale
      

  4.   

    VB也玩ShellCode,不错..不过是当asm用了
      

  5.   

    代码已经发布了
    http://topic.csdn.net/u/20100715/10/888317a8-52a4-40ea-8817-03d01e44546d.html?02404442109367561
      

  6.   

    If dwFunAddress Then
      CopyMemory ByVal VarPtr(gbytDllFunCallOldCode(0)), ByVal dwFunAddress, 6
      glpdwDllFunCallProxyAddress = VirtualAlloc(ByVal 0&, &H1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
        
      If glpdwDllFunCallProxyAddress Then
      CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200, ByVal dwFunAddress, 6
      bytValue = &HB8
      CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 6, ByVal VarPtr(bytValue), 1 'mov eax,DllFunctionCall
      dwValue = dwFunAddress
      CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 7, ByVal VarPtr(dwValue), 4
      wValue = &HC083
      CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 11, ByVal VarPtr(wValue), 2 'add eax,5
      bytValue = &H6
      CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 13, ByVal VarPtr(bytValue), 1
      wValue = &HE0FF
      CopyMemory ByVal glpdwDllFunCallProxyAddress + &H200 + 14, ByVal VarPtr(wValue), 2 'jmp eax
        
      dwValue = glpdwDllFunCallProxyAddress + &H200
      CopyMemory ByVal VarPtr(ShellCode(&H83)), ByVal VarPtr(dwValue), 4
      wValue = &HD0FF
      CopyMemory ByVal VarPtr(ShellCode(&H87)), ByVal VarPtr(wValue), 2
      wValue = &H4589
      CopyMemory ByVal VarPtr(ShellCode(&H89)), ByVal VarPtr(wValue), 2
      wValue = &H458B
      ShellCode(&H8B) = &HF8
      CopyMemory ByVal VarPtr(ShellCode(&H8C)), ByVal VarPtr(wValue), 2
      ShellCode(&H8E) = &HF8
      ShellCode(&H8F) = &H5F
      ShellCode(&H90) = &H5E
      ShellCode(&H91) = &H5B
      wValue = &HE58B
      CopyMemory ByVal VarPtr(ShellCode(&H92)), ByVal VarPtr(wValue), 2
      ShellCode(&H94) = &H5D
      wValue = &H4C2
      CopyMemory ByVal VarPtr(ShellCode(&H95)), ByVal VarPtr(wValue), 2
      ShellCode(&H97) = &H0
        
        
      CopyMemory ByVal glpdwDllFunCallProxyAddress, ByVal VarPtr(ShellCode(0)), &H98
      MsgBox Hex(glpdwDllFunCallProxyAddress)
      bytHookCode(0) = &HE9
      dwValue = glpdwDllFunCallProxyAddress - dwFunAddress - 5
      CopyMemory ByVal VarPtr(bytHookCode(1)), ByVal VarPtr(dwValue), 4 '构造hook Code
      VirtualProtect ByVal dwFunAddress, 6, PAGE_EXECUTE_READWRITE, OldProtect '更改函数地址所在页面属性
      CopyMemory ByVal dwFunAddress, ByVal VarPtr(bytHookCode(0)), 5 'hook
      VirtualProtect ByVal dwFunAddress, 6, OldProtect, OldProtect '更改函数地址所在页面属性
      HookDllFunctionCall = True
      End If
      End If
    End FunctionPublic Sub UnhookDllFunctionCall()
      Dim dwFunAddress As Long
      Dim OldProtect As Long
        
      dwFunAddress = GetProcAddress(GetModuleHandle("msvbvm60.dll"), "DllFunctionCall")  If dwFunAddress Then
      If glpdwDllFunCallProxyAddress Then
      VirtualProtect ByVal dwFunAddress, 6, PAGE_EXECUTE_READWRITE, OldProtect '更改函数地址所在页面属性
      CopyMemory ByVal dwFunAddress, ByVal VarPtr(gbytDllFunCallOldCode(0)), 6 'hook
      VirtualProtect ByVal dwFunAddress, 6, OldProtect, OldProtect '更改函数地址所在页面属性
      Sleep 100
      VirtualFree ByVal glpdwDllFunCallProxyAddress, 0, MEM_RELEASE
      End If
      End If
        
      If glpdwFunAddresses Then
      VirtualFree ByVal glpdwFunAddresses, 0, MEM_RELEASE
      End If
      If glpdwFunNames Then
      VirtualFree ByVal glpdwFunNames, 0, MEM_RELEASE
      End If
    End Sub