Group of Software Security In Progress

GoSSIP @ LoCCS.Shanghai Jiao Tong University

2015移动安全挑战赛(阿里&看雪主办)全程回顾(5)

pic4

题目下载

2015年移动安全挑战赛的最后一道题目,在规定的比赛时间内,仅有来自我们GoSSIP的wbyang一名选手解决了这道问题,今天我们就来揭开这一道最高难度题目的神秘面纱。

先把名为AliCrackme_5.apk的文件丢到JEB里看一看:

pic1

dex文件并没有进行加壳和混淆,看上去是一个非常简单的程序,Java代码部分使用函数Register("Bomb_Atlantis", input)对输入进行判断。所以需要分析的逻辑应该都在libcrackme.so里的Register函数中。

接下来我们用IDA打开这个libcrackme.so,不出所料的发现IDA完全没法处理,应该是进行了强烈的混淆和加壳处理:

pic2

使用和解决前面题目相同的技巧,我们继续使用dd的方法来去处一部分的混淆和加壳。运行一次程序后,从/proc/self/maps里找到libcrackme.so在内存中的位置,使用dd命令从/proc/self/mem中提取出内存中的libcrackme.so,接着使用在解决第四题时使用过的技巧,将libcrackme.solibc.so一起加载到IDA里。

用IDA打开dump出的代码后,我们发现仍然有大部分的代码无法被IDA识别,需要手动定位到需要分析的代码然后手工定义(IDA快捷键C)代码,同时由于代码会在THUMB指令集和ARM指令集之间切换,有时候需要用快捷键ALT+G来将T寄存器设置为不同的值,设置正确后才能正确翻译出代码。这里我们首先遇到的问题是无法定位Register函数,同样使用第四题中的技巧,用InDroid监控到Register函数的真实地址,就可以在该地址上开始分析。

libcrackme.so这个动态库里使用的一些混淆方法,对于处理了前面一些类似混淆后现在的我们来说已经不是问题(^_^)。通过分析代码,我们定位了几个函数,这些函数的偏移在不同的设备上应该是不同的。整体的逻辑其实并不复杂,首先会有一个固定的字符串“Bomb_Atlantis”和一个固定的salt去进行一次md5运算,salt是动态生成的,不过由于dump内存的时候这些动态的值已经生成好了,所以能够直接发现这个salt(出于一些版权原因我们不便公布本题目的一些内部细节,因此该salt值请大家自己分析)

之后程序会将这个md5值和我们的输入进行一些异或和计算的操作,经过几步比较简单、可逆的变换之后,进入一个比较复杂的函数,经过这个函数处理后直接和一个内存中的值进行比较,返回比较结果。

pic3

这里说一个我们在做第五题时用到的分析方法——动态hook。由于libcrackme.so中并没有对调用自身的上层应用进行验证,这就导致了我们可以自己写一个程序去加载这个so,调用其中的方法。这也导致了我们在加载libcrackme.so后,可以加载另一个用于hook的so,这样我们可以hook libcrackme.so中的任意函数,从而知道任意函数的参数和返回值,这对于我们理解程序有着非常大的帮助。这里我们使用的hook框架是著名Android安全研究人员Collin Mulliner开发的Android平台上的一个二进制注入框架adbi。当然这道题目并不能够通过注入的方法将我们的so注入进去,因为源程序禁掉了ptrace这样的系统调用。我们对adbi稍作修改,使之成为一个可以手动加载的动态hook框架。同时由于我们没法通过符号表来定位函数的地址,所有的hook地址都需要硬编码,并且要和运行这道题目程序的Android设备内存映射严格对应。

需要指出的是adbi中存在一个小bug,hook.c这个文件的118行应该是

h->jumpt[0]=0x60

而不是0x30,对应的thumb汇编应该是

push{r5,r6}

而不是

push{r4,r5},

这个小bug在解题过程中会造成一些影响。使用adbi来hook这道题目的函数还需要注意一点,这题的代码中有一些函数使用的THUMB指令集,hook这些函数时,不要忘记人工的对hook地址+1。

通过hook的方法,我们已经能够动态的分析libcrackme.so,首先我们验证了我们对之前几步变换的分析结果。之后就是分析最后一个复杂的处理函数,通过静态分析+动态调试,我们发现这是一个类似于白盒密码学的加密函数。我们的输入进入函数后,首先经过几步类似DES的预处理,之后会进行若干轮的查表,通过查询一个巨大的表将我们的输入进行某种加密,生成一段密文,再经过几次简单的处理后和最后内存中的一段常量(出于一些版权原因我们不便公布本题目的一些内部细节,因此该常量请大家自己分析)进行比较。

通过动态调试,我们能够计算出加密算法最后应该输出的值,但是由于这个加密算法的密钥融入了整个置换表中,要找出一个逆置换表显然不太可能。我们简单过滤了libcrackme.so的其他函数,也没有发现用于解密的函数,想要正常解密密文是不太现实了。不过根据对加密算法的分析,我们发现这若干轮的置换是相互独立的,并且每一轮的复杂度并不高,这就意味这我们可以在可以接受的时间内对算法进行爆破。我们一开始的想法是code reuse,直接在Android设备上爆破,但是发现速度太慢,最后只能用笨办法,通过hook从内存中dump出来置换表,用C代码重写了这个算法,有惊无险地在比赛结束前半小时搜索出结果。根据逆推算法推出正确输入是:

3EFoAdTxepVcVtGgdVDB6AA=   

好了,我们的2015移动安全挑战赛全系列回顾就到此为止了!希望大家能和我们多多交流讨论,欢迎大家关注我们的微博GoSSIP_SJTU,基本上每天都会有精彩的内容发布哦。