这次比赛虽然很辛苦,爆肝了两天,但是在这个过程中让我学习到很多东西,看到了很多有意思的题目,比起前天的国赛,有趣的多。整一个比赛过程虽然出现了很多插曲,但最终还是以第31名出线
Nepnep,冲鸭!
0x01 侧防
Re签到题,算法在sub_12F0里,就这么一点点,直接逆就可以
|
|
PS:我也不知道为什么解出来会最后少两个字符,瞒猜是单词“sorce”,然后回括号,交了就对了
0x02 xx_warmup_obf
这题就有意思了。考点应该是ollvm混淆+花指令+解方程+基于信号量的反调试。先通过字符串交叉引用找过来,可以看到整一片代码都是面目全非的,而且这不像是普通的花指令,反而像是数据和代码直接混在了一起,通过分发器和跳转指令来运行这片代码。
没办法,起调试,但是调试的过程当作发现有大量的int 3指令会被运行,而且“pass to app”后,就会进死循环。
这就很诡异了,本身程序自身的代码出现int 3指令就是一件很诡异的事情,而且这里有大量的int 3,而且运行完后就会进死循环。然后看到init_array里有两个函数,在sub_400B4C 里,注册了信号量处理函数,也就是说,当没有调试器附加的时候,执行 int 3 指令,会有信号量发送给这个处理函数,处理函数会更改分发,从而不进入死循环。那我们调试的时候,只需要在进入死循环后修改跳转条件跳出来就可以了(比如上一幅图的0x409D5F处),这样就可以愉快的调试了。我后来是采用输入后attach的调试方法,然后程序就会在完成输入后的那个int处中断下来,这样可以节省很多手动改跳转的时间。
然后一路向下走,过了长度检测,最终会来到0x402D05,这个位置就是算法的开始,仔细观察一下,会发现全部都是这样的结构
rbp-8 就是输入,后面add的数就是找下标索引,然后与一个数相乘后把结果加到edx或者eax里,最后拿去做比较,如果相同则通过JZ指令跳到下一条方程,否在就会更改分发器和标志位,去结束掉程序。
看懂程序后就要想办法把数据dump出来,因为不能出伪代码(后来知道有的带哥是手动去花去混淆修复出伪代码的),直接从两千多条指令中扣出28个方程难度实在是太大,我就写了一个IDAPython脚本,先dump出所有指令
|
|
效果大概这样
然后写python脚本把它parser出来,因为很规则,可以直接通过指令匹配解析。然后这里有个注意点,在本题,运算全部都是带符号运算,但是我们dump出来的数据是没有符号这个概念的,所以需要手动判断一下负数,转一下补码(刚开始我就没注意到这个问题,解析出方程直接上Z3结果跑了一个多小时跑出个unsat)
|
|
解析出28个方程,直接上Z3秒
|
|
0x03 imitation_game
main函数中含有花指令,去除后开始动调
main函数前面fork了一个进程,父进程会对子进程ptrace,这样会导致IDA无法attach,所以先把ptace函数nop掉,然后跟踪父进程看看逻辑。逻辑里发现AES的SBOX,IDA findcrypto插件也同样识别出了这里的AES算法。回头看该函数开头有一串异或,故可确定其为AES-CBC,解密得到第一段flag 6c8f1d78770fe672122478c6f9a150e9
然后还原patch调试子进程
程序读取game.bin后,进行了一大段的虚拟机操作,根据hint,知道是chip-8,用CHIP8Decompile进行了反编译,动调可知,题目在收集了十次按键(输入必须为0-9, A-F,保存在内存中的值也是0-9,A-F)后,开始加密和校验。0x043E开始,依次对输入的十个按键进行简单的运算。然后开始调用一系列的函数,这里经过分析发现采用递归算法,递归函数为0x027A。分析后整理出了10个三元一次方程,上Z3解得第二部分flag
|
|