whklhh 发表于 2017-11-10 01:49

【swpu-ctf】re400(VMP)

本帖最后由 whklhh 于 2017-11-10 12:22 编辑

这次的题目是VMP保护的……正好从来没接触过,练习一发0v0


首先查壳,无反应
看来VMP只保护了核心部分的代码啊
(之后查询得知VMP由于效率感人的缘故,因此通常只用来保护核心代码~)
拖入IDA反编译:
http://img.blog.csdn.net/20171110005240201?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2hrbGhoaGg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
耿直的超乎寻常的流程……
要求输入为16个字符
将输入转成int数组后通过sub_401120进行check


然而这个call里面就全是乱码了,看来这就是关键的VMP啦
http://img.blog.csdn.net/20171110010934769?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2hrbGhoaGg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
首先去下载VMP分析插件(看雪和吾爱都有)
拷到OD目录下以后重启即可


右键关键call,选择分析虚拟机,然后选择分析虚拟程序


选择插件-VMP分析插件-打开调试窗口
就可以看到虚拟机指令窗口啦
http://img.blog.csdn.net/20171110011132026?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2hrbGhoaGg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
这里面每一行都是原汇编分析出的对应虚拟机指令
虽然指令还是虚拟机插件作者所自创的指令,但至少比起原来不明所以的汇编清晰多啦
POP、Add等指令都是熟悉的指令,如果还有不理解的指令可以去看雪/吾爱/压缩包内的说明文档找~
(我就没想通SubFlag啥意思qaq


现在还比较迷茫,我们再进行两步就能够得到最精简的代码了:
右击-查看-表达式
右击-查看-最终操作
http://img.blog.csdn.net/20171110011614802?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2hrbGhoaGg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
既去除了无关和复杂操作,又给出了清晰易懂的表达式,让我们仰慕一下插件作者OTZ


到这里基本上就可以等价于汇编了,ReadMemDs就是从输入中读出值,右边表达式中的vx是指左边Pop指令对应的vRx寄存器,mx则是临时变量(我也不知道在哪儿~只能从值对应猜啦)
可以看到,代码依次读入每个字符,进行了一番左移操作后累加了起来


其实稍微计算一下就能看出来就是sum = sum*10 + input[ i]
用这么神奇的表示方法大概是因为虚拟机中没有乘法指令,于是就优化成各种左移和加法了吧。
不过汇编中的乘法指令落到CPU底层上的实现应该也是各种左移和加法吧-0-毕竟都是二进制数嘛


16个字符共进行了4次如上循环,切分成4个四位数
http://img.blog.csdn.net/20171110012033969?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2hrbGhoaGg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast


然后对它们进行运算校验
这里貌似也没什么好方法,只能慢慢计算了
注意一共有4次校验,最后一次没有通过vJmp来跳转,而是直接使用了Flag标志位:
http://img.blog.csdn.net/20171110012306089?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2hrbGhoaGg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
这个SubFlag就是校验v37-0xBB80是否为0的,通过最后的标志位来表达在外部的返回值中,因此也要求通过


最后总结出4个方程:
http://img.blog.csdn.net/20171110012446231?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2hrbGhoaGg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast


这个计算起来有点麻烦呀……
想起来之前刚好搞了Z3约束求解器下来,这东西解方程正好用嘛


安装的时候又费了好大劲,pip安装下来的貌似不太对劲,还是得乖乖去github上拖
弄下来以后又报初始化错误,然后把libz3.dll放进去,再核对32位和64位版本后才终于能用=A=
python3:

import z3

z3.init(r"E:\Users\hasee\AppData\Local\Programs\Python\Python35-32\Lib\site-packages\libz3.dll")

solver = z3.Solver()
v11 = z3.Int('a')
v16 = z3.Int('b')
v19 = z3.Int('c')
v23 = z3.Int('d')
# 限制解的范围
solver.add(v11 < 9999, v16 < 9999, v19 < 9999, v23 < 9999)
solver.add(v11 > 0, v16 > 0, v19 > 0, v23 > 0)
# 添加方程
solver.add(v11 * 5 + v19 * 3 + v23 * 2 + v16 * 4 == 0x130D9,
         v11 * 4 + v16 * 2 + v19 * 6 + v23 * 3 == 0x10aef,
         v11 * 3 + v16 + v19 * 7 + v23 * 5 == 0x11a6b,
         v11 * 2 + v16 * 3 + v19 * 5 + v23 == 0xbb80
         )
# 求解
if (solver.check() == z3.sat):
    print(solver.model())
else:
    print("unsat")


注意Z3默认情况下是只输出一个解的,因此如果方程约束条件不对的话将只能得到错误解╮(╯_╰)╭
输出解后按照顺序将其拼合成字符串即可


总的来说这个VMP还是挺简单的,作为学习工具来讲非常好~萌新首次接触VMP就很快搞定啦~再次感谢SWPU和08067的师傅们~




=========又忘了上附件诶嘿========
感谢L4NCE和画眉二位dalao的指点{:301_1003:}



失业 发表于 2017-11-10 09:02

厉害了。分析VMP
顺便问下半夜发贴的才能成为大神吗?{:301_1010:}

珍惜幸福涙 发表于 2017-11-10 11:09

感谢下楼主,能发下文件让菜鸟学习下吗

whklhh 发表于 2017-11-10 12:23

失业 发表于 2017-11-10 09:02
厉害了。分析VMP
顺便问下半夜发贴的才能成为大神吗?

{:301_977:}半夜发帖只能成为秃子

imtom123 发表于 2017-11-12 18:31

还满想vmp的脱壳的 不知论坛有脱vmp的入门教程吗

chkds 发表于 2017-11-12 18:31

下载学习一下。。。以前看到vmp直接右上角。。。

t5456290 发表于 2017-11-12 18:32

不知论坛有脱vmp的入门教程吗

lanlana 发表于 2017-11-12 19:23

楼主讲的很棒,不过对于那三个方程的得出我还是不懂{:1_908:} 可不可以再详细一丢丢感谢{:1_923:}

lanlana 发表于 2017-11-12 20:35

我想请问下IDA反编译后的代码 是整理过的吗?
还是咱们俩版本不同
感觉我的f5出来之后好乱
非常感谢:loveliness:

whklhh 发表于 2017-11-12 21:04

lanlana 发表于 2017-11-12 20:35
我想请问下IDA反编译后的代码 是整理过的吗?
还是咱们俩版本不同
感觉我的f5出来之后好乱


IDA反编译代码基本一样啊。。我觉得没区别吧_(:з」∠)_
解方程的话,是Z3的使用不懂吗?百度Z3的教程吧,我也不太熟悉它其实~
页: [1]
查看完整版本: 【swpu-ctf】re400(VMP)