此篇博文为
http://www.vbgood.com/viewthread.php?tid=69444&extra=page%3D1
的源代码
实现思路:
我是个懒人,我的目标就是干最少的活,完成最多的事情。当我看到网上那么多帖子中讨论的方法都很麻烦时,我觉得应该有更简单的办法。
调用api其实就是call过去,我的第一反应是:建一个空的function。得到api的入口,然后复制代码,覆盖掉我的function。执行我的function就等于执行了api。
但仔细一想不行,很多api会jmp +xxx,这样的话,我不能保证把jmp到的代码都复制下来如果自己检测jmp,会变得很麻烦。
那么如果复制代码不行,那我不复制行不行?接下来很容易就想到了,为什么不改写我的function,让他直接跳转到api呢?
好像可以耶~
call不行,因为会有压栈动作,我这个汇编盲这点还是知道的。那么就jmp吧……最近看api hook看得太多了,经典的5个字节。 jmp的好处多多,没有任何多余动作,参数完整保留到jmp目的地。
问题又来了,怎么才可以知道我的function在哪里呢?容易,经常用到回调函数的朋友一定知道Addressof操作符吧,它的作用就是返回函数的入口。但是vb里面是不能直接使用a=Addressof b的,必须在函数中调用。
那么我们就走个弯路: a=Clng("&H" & Hex(Addressof b)) 把Addressof b当作参数传给Hex函数就可以了,得到16进制,然后再用Clng转换成10进制。这样就得到了b函数的地址了。
接下来就容易了,只要在a地址处写入5个字节就行了,具体哪五个字节其实我也不知道,我随便找了个程序,od载入一下,找了个jmp看一下16进制代码,明白了,原来是E9啊。后面4个字节容易,算一下就行了。它=目标地址-E9的地址-5。
好了,问题基本解决。那么参数呢?走一步算一步吧,实验对象经典的MessageBoxA 4个参数。那么我就新建一个模块,输入2行代码:
Public Function myFunc(ByVal a As Long = 0, ByVal b As Long = 0, ByVal c As Long = 0, ByVal d As Long = 0) As Long
End Function
再来个主窗口:
text1=Clng("&H" & Hex(Addressof myFunc))
再来个按钮:
call myFunc(0,0,0,0)
编译,od载入,ctrl+g到text1里显示的地址,哈哈
xor eax,eax
ret
nop
还真简单,od里at MessageBoxA,然后记下MessageBoxA的地址,返回myFunc地址,把原来的代码修改成jmp MessageBoxA-myFuc -5。
回到程序里点按钮,哈哈,msgbox出现了。 接下来就容易了,先测试下传参数怎么样。
call myFunc(me.hwnd, strptr("123"),strptr("456"),0)
因为myFunc的原型4个参数都是byval的long,而MessageBoxA的2、3个参数是字符串指针,所以我就用strptr得到字符串的地址,然后传过去,就不会有问题了。
执行一下,果然没错。 再来看看多个参数怎么办。我想到了Optional,这样就可以不用管参数个数了。
因为如果有2个必选参数,4个Optional参数,那么你传2个参数进去,后面的4个参数因为不存在就不会压栈,如果api有3、4、5、6个参数,我只要按参数个数传就可以了,少于myFunc的参数会自动省略掉。
这是我觉得最巧妙的地方,[color=Red]所以不会有参数数量问题[/color]
试验一下吧:改成
Public Function myFunc(Optional ByVal a As Long = 0, Optional ByVal b As Long = 0, Optional ByVal c As Long = 0, _
Optional ByVal d As Long = 0, Optional ByVal e As Long = 0, Optional ByVal f As Long = 0) As Long
End Function
其他不变。。。执行一下看看,omg,成功了,哈~ 写上10个参数,应该可以应付任何api了吧?
哈哈,那么到这里原理大家都明白了吧?至于如何写入那5个字节的jmp就随意了,CopyMemory和WriteProcessMemory都可以
我的程序用的是WriteProcessMemory,用起来顺手。剩下的大家就看源代码吧~
实现的核心代码其实就8行