最近在改这样一个代码,但是有些地方不解,求教!代码名称:Call API functions by Name
下载地址:http://www.freevbcode.com/ShowCode.asp?ID=18631、下面这个函数,将CALL &h12345678 添加到汇编代码数组,为什么要在地址上- VarPtr(m_abCode(m_lCP)) - 4?
Private Sub AddCallToCode(ByVal dwAddress As Long)
    AddByteToCode &HE8
    AddLongToCode dwAddress - VarPtr(m_abCode(m_lCP)) - 4
End Sub
2、下面这个函数中m_lParameters(i) = CLng(FuncParams(i - 1))一句,是如何运行的?明显的FuncParams的每一个元素都是变体,那么对变体执行CLNG函数的效果……难道说是引用类型时,VB6的CLNG函数会返回这个引用类型的内存首地址,而非引用类型时才是我们熟悉的CLNG?头疼!
3、下面函数中,   ReDim m_abCode()时,为什么是18 + 32 + 6 * UBound(m_lParameters)?依据是什么啊?
Public Function CallFunction(ParamArray FuncParams()) As Long
   Dim i As Long
   If m_lpFn = 0 Then
      MsgBox "Function not defined!", vbCritical, "Call function error"
      Exit Function
   End If
   ReDim m_abCode(0)
   ReDim m_lParameters(UBound(FuncParams) + 1)
   ReDim m_abCode(18 + 32 + 6 * UBound(m_lParameters))
   For i = 1 To UBound(m_lParameters)
      m_lParameters(i) = CLng(FuncParams(i - 1))
   Next i
   CallFunction = CallWindowProc(PrepareCode, 0, 0, 0, 0)
   m_lpFn = 0
End Function
以上……………………

解决方案 »

  1.   

    对于问题二.....建议楼主不应该执着于类模块里面的代码....你看下主窗体的代码就会知道...只要是传入数组这样的变量,一律用VARPTR取得指针再传入....所以不存在CLNG在不同情况下返回值不一样的问题.......
      

  2.   

    问题一是因为"call 偏移32位地址"占用5字节....所以应该是"当前地址-5"....而m_ICP表示当前shellcode储存的地址,而且前面已经AddByteToCode &HE8,所以"-VarPtr(m_abCode(m_lCP))"就已经减了1,后面再减4,一共减去了5,正好是call语句的长度...以上为本菜鸟的愚见....第三个问题尚未想到....
      

  3.   

    恩,第一个问题确实如此,传入时确实已经指明了……没动脑子,,,哈哈,搞笑了。
    这个回答我还需要详细问一下,嘿嘿,我比较愚昧……BYTES里面放的就是汇编代码了吧,传入的第一个参数就是这个数组,数组里面的CALL 不是直接调用函数地址吗?为什么还会偏移啊……例如说,要调用SetWindowTextA那么
    Dim s() As Byte, x As Long, y As Long
    s = StrConv("Hello !", vbFromUnicode)
    b = 15
    x = CallApiByName("user32", "SetWindowTextA", hwnd, VarPtr(s(0)))
    它的入口是:
    77D2F56B
    而我输出汇编代码数组,得到的却是CC
    CC
    CC
    CC
    CC
    CC
    CC
    CC
    58
    59
    59
    59
    59
    50
    68
    90
    72
    15
    0
    68
    42
    B
    9
    0
    E8
    A6
    7C
    BD
    77
    0前面的CC不用管了,给调试器用的吧。
    58
    59
    59
    59
    59
    50
    就是清栈并设置运行位置,对CallWindowProc作用的。后面的才是真正的调用SetWindowTextA的代码
    68
    90
    72
    15
    0
    68
    42
    B
    9
    0
    68是对齐代码为4字节指令,忽略。。第二个参数在前,也就是说Hello !这个字符串所在内存地址了吧。第一个参数就是窗口句柄。
    接下来的代码就是我不明白的了
    E8
    A6
    7C
    BD
    77
    E8是CALL这应该没问题后面的呢?就是地址吧。77BD7CA6这个地址就是第一个问题那个函数得到的。用这样一段代码输出他们:
        Form1.Text1.Text = Hex(lngAddress)
        Form1.Text2.Text = Hex(VarPtr(mbytCode(mlngCP)))
        Form1.Text3.Text = Hex(lngAddress - VarPtr(mbytCode(mlngCP)) - 4)
    得到的分别是77D2F56B
    1578C5
    77BD7CA2第一行那是函数地址,直接调用不行吗。。那么怎么转换的啊依据是啥啊。。头都大了。
      

  4.   

    对了,还有一个,,,就是那个该死的77BD7CA6处,根本就没东西!用OLLYDBG调试生成的程序,转到内存77BD7CA6会提示没有分配啊
      

  5.   

    补充一下
    E8 
    A6 
    7C 
    BD 
    77 
    E8是CALL这应该没问题后面的呢?就是地址吧。
    为什么是77BD7CA6
    而不是77D2F56B呢?俺想应该是
    E8 
    6B 
    F5 
    D2 
    77 
    才是CALL SetWindowTextA吧。
      

  6.   

    我说"偏移"是因为汇编是用相对与call语句所在地址来计算被调用函数的地址的....
    比如我用w32dasm反编译了c:\windows\hh.exe,在导入wsprintfA那里看见有这样的一段代码:01001241 E8 41 02 00 00 call 01001487
    :01001487 3B 0D 42 00 01 cmp ecx, dword ptr [01002004]而0x01001487 - 0x01001241 - 5 = 0x241
    所以被调用函数地址计算公式就是"call语句所在地址(上面是0x01001241) + 32位偏移地址(上面是0x241) + 5",就是说如果要求"32位偏移地址",那么就要这样来求:被调用函数地址-call语句所在地址-5而代码里面在执行AddByteToCode &HE8之前VarPtr(mbytCode(mlngCP))就正好是"call语句所在地址",但是加了E8这个字节之后地址指针被向后移动了一个字节,所以后面应该是-4不是-5,于是"lngAddress - VarPtr(mbytCode(mlngCP)) - 4"就应该是要call的"32位偏移地址"了......
      

  7.   

    这分绝大多数给楼上了。
    昨天晚上睡不着,想了想,今天又翻出来一些CE,OLG什么的搞了一下,说明楼上的说法确实是对的,之所以用相对地址是因为前面是E8,参考INTER 的80X86汇编手册看了一下,还有F2,9A,FF什么什么的,那些是用绝对地址。
    其实啊,我是用VB.NET写代码,参考人家的VB6代码,这会儿算基本竣工了测试了SetWindowTextA、FlashWindow、GetWindowTextA、LoadLibraryA这几个函数。就是说只有返回值、传入返回值、返回返回值什么什么的类型都正常运行了。第三个问题不问了估摸就是按代码可能最大长度计算的,由于.NET调用时封装的一些问题,所以直接固定了这个长度为1024字节。不考虑了。。
    最后还发现一个怪事,在VISTA环境下,VB6的代码能运行,但是我写的.NET代码不行,会出现非法写入内存的问题。可能需要权限提升吧,模块在笔记本上放着,懒得测试了也很可能是别的问题,以后有时间在深究吧。在XP下两个代码就都行了。
    结贴了