-
-
[原创]看雪CTF 2019总决赛 第六题 三道八佛
-
发表于: 2019-12-15 00:16 6016
-
这次的题目还是用的Q3第十题的壳
使用x32dbg
调试,依然看到熟悉的操作
在保存完输入的用户名和序列号后便开始解密代码,在解密代码之后依然通过tib
重新设置了程序的栈地址(mov dword ptr fs:[4], eax
和mov dword ptr fs:[8], ebx
),最后通过call eax
跳转到解密后的代码
值得注意的是这一次壳自解密的过程中执行的代码都一样,因此怀疑验证算法是在壳多次自解密完成后才执行的
另外一个和上次题目不同的地方在每次跳转到解密后的代码那里,即call eax
这个指令在后面有变化,因此在写脚本定位特征时需要多判断一个特征:E801000000
,具体见下图:
参考了上次比赛@注册LookLook的脚本,因为我上次写的脚本太冗长了
附件:x32dbg.txt
通过尝试发现壳一共自解密了0x578
次,即1400
次(比上次少了很多)。于是断到最后一次,再进行操作。因为最后一次修改fs:[8]
后还有一次自解密,所以还需要gocode:
这个分支中的操作才能到真正的验证算法
脚本执行完后定位到的函数头尾:
然后手动将dump的bin文件末尾一个字节改成c3
,即ret
,就可以用ida创建函数F5反编译了。附件:dump01.bin dump01.idb
抠出来算法,还需要知道这段算法执行的前后干了什么,调试分析一下
在进入算法前:
esi
指向的数据:
算法完成后:
算法完成后esi+0x1B0
的位置保存了解密后的数据,然后将解密后的数据同用户名比较,若相同则打印成功
需要注意这里比较用的是repe cmpsb
,判断长度为ecx = 0x11
,即判断17
字节的数据。然后可以发现若用户名不足16
位,则默认有填充数据,也就是用户名KCTF
最后验证时验证的用户名数据是:4B 43 54 46 00 1A 19 18 17 16 15 14 13 12 11 10
。具体如下所示:
附件:FixCrackMe.cpp,FixCrackMe.exe
根据以上逻辑,再将ida反编译的代码优化优化,可以做出一份可独立运行的cpp
代码:
优化后的算法看起来就很清晰了,分别将序列号相邻的两个字节拼在一起,然后进行一波看不懂的运算。知道应该输出什么结果后,就可以逆推算法了。
可以发现:
所以
只需要穷举 k_6_5 与 k_8_7,速度就快很多
附件:check_cr.cpp
用z3的道路比较曲折,在后面需要注意的地方有说明
附件:key.py
用z3需要注意的地方:
首先是脱壳,参考上次的,没有什么特别的,改改脚本就完了
脱壳完成后我们先优化代码,然后尝试用z3求解,但是由于对z3的使用不够熟练总是无解
一开始也没注意到用户名KCTF\0
后面有默认填充的数据,认为全是0
,@ccfer就手动逆推算出来了一个序列号,结果不对,一看才知道有填充数据。因为有了填充数据,没办法手动逆推了
然后@大帅锅和@ccfer优化代码,最终发现只有 k_6_5 与 k_8_7 是变量,@ccfer就写出了爆破代码
到了第二天我们开始研究用z3求解,最终@ccfer找到了错误的原因,完成了用z3解这道题
是的,我的队友们就是这么强大!这就是传说中的带躺吧
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [分享]教你签到获得更多的雪币 9988
- [原创]看雪CTF 2019总决赛 第六题 三道八佛 6017
- [原创]看雪CTF 2019总决赛 第二题 南充茶坊 6611