如何防止别人调用自己的函数?
很久没碰wx了,最近想写个东西,就重新拿了起来,最新版本2.6.8.65(此时已经2.6.8.68)。
找到以前分析过的发送文本消息接口,发现函数大变样,很明显的vm痕迹。
1 | .vmp0:1131CE33 000 push 2493AC03h |
当时也没在意,仔细看接口参数并没有变化,就直接拿来用了。
结果发现接口不能用了,并没有成功发送文本信息。
擦,难道vm里面藏了什么玄机,做了防止函数调用的保护??
…
正整备大干一场的时候,重新测试给别人发送消息是ok的。
这是一次美丽的误会,测试时是给自己的微信发送消息,结果证明该接口是不能给自己发的,所以没成功。
…
然后就继续说说先前自以为的wx在函数中可能做的防止调用的保护吧。
防
按照自己思考的防止别人调用函数的思路,其实就是检查调用源,那么肯定是从调用栈入手:
- 在函数内部回溯调用堆栈,检查返回地址
- 返回地址为微信模块则正常调用,否则拒绝执行
- 可能检查一层(wechatwin.dll),或者多层
- 可能检测返回地址在模块范围,或者是准确的返回地址
- vm相关逻辑,增加分析难度
大概实现代码就是:
1 | void TestAntiCall(DWORD a1) |
攻
所以能够想到的对抗方式就是在调用TestAntiCall的时候,修改调用栈返回地址,让TestAntiCall误以为确实是正常调用。
这里分析只考虑检查一层返回地址。
比如如下正常调用代码,00003就是返回地址,在合法模块内,即可正常调用。
1 | //正常调用代码 |
而我的调用TestAntiCall函数(在我的模块内)如下,add esp, 4;
为TestAntiCall拿到的返回地址,这个地址肯定在我的模块内,调用失败。
1 | pfnTestAntiCall = 原始TestAntiCall地址; |
然后尝试欺骗TestAntiCall
,我们修改一下调用栈的返回地址(本来应该是MyRetAddr)。
通过push+jmp
来替换通常的call
,这样返回地址由我们自己压入,这里压入正常调用的返回地址g_SendTextMsgRetAddr
。
1 | //这个会成功 |
当然,就这么简单的调用,肯定会出问题的,因为jmp pfnWxSendTextMsg
之后,就会返回到Right_TestAntiCall
的00003
,如此显然导致栈破坏,会出现崩溃。
所以为了让程序正常执行,还需要多两个处理步骤。
Right_TestAntiCall
的00003处修改指令为jmp MyRetAddr。让执行流返回到MyTestAntiCall1- 恢复00003处原始指令。
1 | //1. `Right_TestAntiCall`的00003处修改指令为jmp MyRetAddr。让执行流返回到MyTestAntiCall1 |
为了拿到MyRetAddr的地址,通过call+pop的方法完成,如下:
1 | __asm { |
上面拿到retaddr和MyRetAddr明显不是同一个,所以在fakeAntiTestCall
中减去一个偏移24拿到MyRetAddr
。
偏移值通过下面的字节码可以计算出来10024E1E
- 10024E06
= 24。
1 | .text:10024DDF EB 37 jmp short RET1 |
如此可以正常完成一次调用,但是还有问题,因为会反复修改Right_TestAntiCall
的指令,可能在多线程中执行时出现问题。
所以更好的方法时在Right_TestAntiCall
的模块中找一个不用(零值)的内存,用来保护临时指令,不细讲了,大家自行探索吧。
(完)
转载请注明出处:https://anhkgg.com/anti-call/