首页
论坛
课程
招聘
[原创]KCTF2021春季赛题目提交 第七题 千里寻根 设计思路
2021-4-25 21:02 2518

[原创]KCTF2021春季赛题目提交 第七题 千里寻根 设计思路

2021-4-25 21:02
2518

战队名称:

Archaia(武汉科锐学员队)

队长QQ:

846235136

参赛题目:

见附件

公开的用户名及序列号:

用户名 : FE0C37052AED0E33
序列号 : 7D4DBA7A9C2EF1A8EF848BC880B83170431F37E599048DBB88C306BC403579D1

题目答案:

用户名 : KCTF
序列号 : B91AE5FCDA57D87406968CBDB8829799790A77302D7E8754B705894489B37A10

题目设计:

此题《千里寻根》为"KCTF2019Q3第十题《传家之宝》"和"KCTF2019Q4第六题《三道八佛》"的升级版本,
在经历前两次比赛后总结不足,修改更新出来的作品.

 

此题风格上和之前两道题目一样, 依旧是没有在算法上设卡, 主打代码流.
主要的设计思路就是

代码长长长, 并且设卡阻止破解者"眼看手跳快速pass大量框架代码直捣黄龙"

与之前两题不同之处

1.《传家之宝》《三道八佛》两道题目是windows32位的应用程序, 经过代码重构(整体思路和程序大体流程基本上没变)这次提交的题目《千里寻根》是windows64位的应用程序
2.三道题目作战思路都是使用"蜗牛壳":
使用SMC技术一边执行关键算法代码,一边解密"下一代蜗牛".

首代蜗牛负责输入用户名和序列号.
中间的蜗牛负责背着后代的壳(后面层的加密代码), 行走一小步(执行一点关键算法代码), 再产生出下一代蜗牛(解密下一层的代码).
末代蜗牛负责验证和输出结果.

 

《传家之宝》共2880层, 《三道八佛》共1400层, 这次《千里寻根》共2021层.

 

(1)《传家之宝》《三道八佛》两道题目因为"中间的蜗牛"特征过于明显, 很容易就写出了跟踪脚本, 分离并整合出关键算法代码.
所以这次提交的题目对"中间的蜗牛"进行了变异处理(代码随机混淆).
"中间的每一代蜗牛"都干着相同的事情, 可是都是长得完全不一样.
(2)《传家之宝》《三道八佛》两道题目为了影响攻击者写跟踪脚本, 加入了多种反调试手段(异常, 时间等).
这次提交的题目中, "蜗牛壳"删除了原有的所有反调试手段.

 

3.在"蜗牛壳"的基础上, 另外还给应用程序加了个"PE加密壳", 这是《传家之宝》《三道八佛》两道题目中没有的.
"PE加密壳"的作用是CRC校验, 反调试, 加密原程序的导入表项

 

4.关键的验证算法上没有过多设计, 因为此题重点在壳上.
使用的是《三道八佛》里的算法加上稍作修改的base64算法

技术要点:

PE加密壳:
CRC校验: 只校验外壳代码, 在攻击者patch外壳代码的时候会导致解压缩代码节数据不对
反调试: 使用了两种反调试"IsDebuggerPresent"和"模拟NtQueryInformationProcess"
加密导入表: 如果不脱此加密壳就着手研究, 在"首代蜗牛"和"末代蜗牛"调用API的地方, 不能直接看到被调用API的名字和地址

 

蜗牛壳:
SMC加密: 使用简单的加密算法保护后代蜗牛的代码, 防止破解者看到未来太远的代码
地址随机化: 每一代蜗牛展开蜗牛壳, 抛出下一代蜗牛时, 随机指定下一代蜗牛的执行地址
切片技术: 将核心算法的代码切成切片, 然后将每个切片贴到每层壳上(有可能有的层是没有核心算法代码的切片的), 每层壳被执行的时候, 相应的切片也会被执行.
代码独立: 蜗牛壳在运作的时候, 不调用任何外部的API, 不使用外部的堆栈
对抗脚本: 破解者在看了前面几层壳的架势之后, 不会真的一层一层单步跟踪, 而会写脚本脱壳取肉. 这是对比之前两题主要改进的地方, 利用混淆工具对中间层进行随机混淆, 加大破解者寻找蜗牛壳行为特征写脚本的难度.

预期的破解思路:

思路1(难以实现):

1.脱去最外层的"加密壳", 得到只有"蜗牛壳"的应用程序
"蜗牛壳"和最外层的"加密壳"不会相互依赖, 所以可以确保最外层的"加密壳"脱掉后能正常运行, 当然可能大佬不需要脱"加密壳"就能进行下面的破解步骤.
脱壳比较简单, 找到OEP(0x140001088), dump, 修复导入表项(导入表项只有system/scanf/printf/GetModuleHandleA/ExitProcess/VirtualProtect六项), 即可完成脱壳.
2.使用x64dbg(或者ida等其他工具)的trace功能, 得到"蜗牛壳"所有的执行过的代码
(1)从"首代蜗牛"输入完成一直跟踪到"末代蜗牛"完成比较输出结果, 得到中间所有的代码.
(2)观察并写代码对上面得到的代码进行优化:

去掉跳转代码
多行汇编代码合并成一行(比如把mov rax, 1和add rax, 2 合并成mov rax, 3)

 

(3)经过上面的步骤就能发现, "中间的每一代蜗牛"代码基本上一样, 根据特征分离出关键算法代码
3.根据关键算法代码写逆算法, 此题在算法上没有过多设计, 参考大佬们写的《三道八佛》wp算法部分和base64算法稍作修改即可写出KeyGen.
https://bbs.pediy.com/thread-256746.htm
https://bbs.pediy.com/thread-256835.htm

相信有不少选手想尝试思路1的"trace所有的执行过的代码", 都会遇到一个很尴尬的问题: 很难trace完, 或者莫名其妙trace结束了.
笔者在自己测试时候, 使用x64dbg的trace into功能, 大概跟踪半小时后, x64dbg会停止trace, 直接把程序运行起来, 而且还附带着"系统库名称符号不见了"/"Ctrl+G无法跳转地址"等一系列奇怪的现象. 这应该是x64dbg的BUG吧, 输出数据太多导致无法alloc内存.

思路2:

断掉trace的念头(trace可能是条不归路), 自己跟踪个一两层代码找特征, 然后编写调试脚本能整层整层跑蜗牛壳.

 

要想破解蜗牛壳保护的程序, 最关键的步骤就是从万千代码海中提取出"肉代码", 这也是此题的难点所在.

 

比较容易发现利用的特征是每层修改栈时候对gs:[30]写入值, 这个在之前比赛的wp中也有选手提到过.
然后利用esp定律, 对栈下访问断点(因为每次执行"肉代码"都要先恢复寄存器环境,栈地址将对偏移都是固定的), 直接运行到"肉代码"处, 然后一直单步跟完这层的肉代码.
脚本log出来的数据需要自己提取出有用的"肉代码". 人肉搞定, 或者脚本一通字符串操作也能搞定.

 

所有的"肉代码"拼在一起, 就是一个完整的算法函数了, 接着思路1的步骤(3)继续完成即可.

 

详细解题步骤请跳转此贴:解题方法

题目中小彩蛋

如果直接对printf函数下断点, 在最后输出提示信息的时候, rdx/r8/r9寄存器会有字符串.

 

感谢看雪论坛, 提供一个那么好的平台交流技术!
感谢武汉科锐, 在那里学到了很多技术知识!
感谢一切和我一起交流技术的伙伴们!

附件说明

CrackMe.rar:提交的题目文件
code.asm:题目使用算法的汇编代码("肉代码")
KenGen.cpp:题目KenGen源码文件
CrackMe_nopack.exe:没有加PE保护壳的题目文件


[2022冬季班]《安卓高级研修班(网课)》月薪两万班招生中~

最后于 2021-5-23 12:28 被kanxue编辑 ,原因:
上传的附件:
收藏
点赞1
打赏
分享
最新回复 (1)
雪    币: 584
活跃值: 活跃值 (11141)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2021-5-3 09:59
2
0
感谢参与!
可以参考《传家之宝》《三道八佛》的思路,但这题请提供你改进过的详细设计思路文档
游客
登录 | 注册 方可回帖
返回