XDCTF2015逆向部分Write up

西电2015CTF比赛时间为10.1-10.3,比赛已经过去有一段时间了,由于笔者只做了逆向部分和PWN部分,这里将逆向部分的解题思路贴出来,仅供参考。这里提供题目下载,提取密码:7pvv。有兴趣可以自己动手尝试下。

1.RE100

这题真的有点坑,题目提示为” donn’t belive your eyes”,注定要麻烦一点。

UE打开程序,发现是64位ELF文件,直接拖进kali,运行发现是要输12字节正确序列号。 IDA反汇编查看一下,发现函数并不多,直接点进去一个一个看。发现sub_4008E1处出现可疑函数,F5看一下。

QQ截图20151012112716

OK,调试之,gdb打开之后,直接退出,输出‘Aha ,Bye’,应该是碰到反调试了。

QQ截图20151012113649

函数ptrace百度一下发现是反调试函数,这里比较简单,直接暴力nop掉这段代码就可以正常调试了。正如反编译看到的代码一样,先将input与字符串’|Gq\@?BelTtK5L\|Dd42;’异或再异或7。但是这里最终的异或key不是 ‘|Gq\@?BelTtK5L\|Dd42;’,而是将该key经过base64之后的字符串,这是调试过程发现的,如图所示。

QQ截图20151012114536

QQ截图20151012114616

可以看到key变为”ZzAwZF9DcjRrM3JfZzBfb24=”。接着在函数sub_4006D5进行变换,将字符串第1-6位与第13-18位对称变换。这步是可逆的。

QQ截图20151012153023

得到的结果再进行最后一次变换,如果小于31则加32,这步也是可逆的。最将字符串与

 

对比正确则Iput为flag。,接着开始写解密过程,最后解密得到的flag总是不对,命令行下提示也是过了的。真是坑啊,继续查看其他函数,最后发现函数sub_400787与刚刚的疑似解密函数非常相似,只是少了个异或7

QQ截图20151012153724

重新修改刚刚的解密算法,最后计算出的flag在提示下终于过了。所以这个函数才是真正的解密过程。解密过程python之。flag:U’Re_aWes0me

2.RE200

这道题比较简单,就是用OD跟踪,作者为了不让我们使用IDA的反编译功能,将主要代码加密起来了。第一步还是info下软件信息。

QQ截图20151012195314

可以看出是个PE文件,直接win下运行,发现要求输入flag,随便输一个,提示‘You shall not pass’。OD之,依旧是那个调试,猜测有反调试,IDA查找这个字符串,在交叉引用处逐一查看,发现了简单的反调试伎俩。

QQ截图20151012195846

QQ截图20151012195905

简单修改下跳转条件即可,winhex直接将跳转条件机器码反一下。或者直接用strongOD直接过了。这样可以正常调试了,发现存在一段代码解密过程,对0x401166处开始解密。QQ截图20151012200414

查看解密后的代码,发现是验证flag的关键代码。只能强撸汇编代码了,主要分为5个部分。

1.获取input,判断字符串大小是否在0-25之间,否则不能通过

QQ截图20151012201550

2.要求输入开头以XDCTF{,指示输入中_和$在字符串中的位置,并且指示}位于字符串偏移值24处。

QQ截图20151012202236

3.按照要求构造XDCTF{123456_89QWE$TYUI},找后续检查代码

QQ截图20151012203421

4. XDCTF_循环相减输入是否等于固定值,推导出前6个字符为Congra。

5.接着第二部分检查。此部分直接同tUlat,比对,因此第二部分字符串为tUltra,这部分比较简单,

6.接下来是第三部分,竟然是对运行时间的检测,当大于一个固定时间时则退出程序,不过这部分可以直接爆破掉,得到第四部分检查。将剩下的字符与key异或后判断是否为字符dst。

QQ截图20151012203943

最终得到flagXDCTF{Congra_tUlat$eyOu}。

3.RE300

这个是python的一行代码,手工拆分一下,拆到这样就差不多了。

这个代码与原代码是等效的,不过更清晰一点。

一开始的setbit和getbit两个函数看函数名就能猜出个大概,然后在用下就能知道其作用。不过其第一个参数是个数组,操作中的bit位数是在整个数组中的位数。

关键加密方式依然很难看懂,不过也能看个大概,其中最关键的地方在这里:

在配合着通过修改flag.txt看变量ss和sss的变化就能猜出加密方法:

将输入转化为在数组string.printable.strip()中的位置,然后取后6个字节拼在一起。

因为只取了后6个字节,而第7个字节有可能为0也有可能为1,所以反解的时候两个都要考虑到。

然后拼接一下得到flag:xdctf{0ne-l1n3d_Py7h0n_1s_@wes0me233}

4.RE400

这道题刚开始没做出来,一直无法调试,猜测应该是编译器版本过高导致的,作者还未整理。

5.RE500 

此题较RE400简单很多,以后不能以分数高的就很难。还是一个破解注册码的程序,在错误提示处断下。

QQ截图20151012215002

习惯性上溯,找到按钮函数入口处

QQ截图20151012215634

发现只有两个Edit框,ID是10086和10010,这俩移动联通热线的ID类型根本就不存在,问题来了。只好IDA中一个个查看,看到408550处有了启发。

QQ截图20151012220314

这里它自己Hook了自己的GetDlgItemText。发现这两个一个是验证注册码长度,一个验证注册码是否包含非法字符。后面就是验证了,首先DES(!NOT SURE! Result of KANAL)解密传入的注册码,然后将注册码最后两位移到最前面,接着和程序中的一组字节挨个异或,最后和机器码比对,若相同则正确。但是死活没有找到DES 的解密密钥,所以各种尝试均无功而返。

然后就打算看了一下解密的函数,结果手抽点错了,发现两个函数基本相同,引起了我的怀疑,又发现两个函数分别有“加密之前”、“解密之前”字符串,所以断定他们俩是一对互逆的函数。所以直接在原来调用解密函数的地方把函数换成了加密函数,并设置好相关的缓冲区(函数的第二个参数,不要忘了末尾用0x08 填充到24 字节,不要被IDA 错误的变量类型迷惑住了)为已经逆向变换过的MachineCode,即可得到注册码,提交得到flag。

Flag:XDCTF{1azy_Cm_15_2_s1mp0!}

【via@91ri团队-Leon】