pwnhub端午节公开赛 writeup

端午节时候pwnhub终于出了一期android逆向题目,抽空去练练手。整体来看是嵌套ELF的玩法,挺不错的。

转载请联系本人,否则作侵权处理。

相关文件链接:https://github.com/LeadroyaL/attachment_repo/tree/master/pwnhub-duanwu

(shudu.apk, dec1, dec1.idb,  fix.idb,   fix.so )

一开始是个数独,先玩一下吧,也没看逻辑,说不定会动态修改什么数据,于是找到一个在线的解题网站 http://www.llang.net/sudoku/calsudoku.html 。

把数独解掉了,有一个输入flag的EditText和check的button。

这时候返回去看一下数独的逻辑,好像就是一个简单的数独,没有存放太多的全局变量,再全部填写完毕而且正确的情况下自己会dismiss,之后绘制一个新的界面、就是我们的check界面了。比较有意思的就是里面大部分的String都被加密处理掉了,在Decode类的某个方法,看起来是自己写的解密,也没仔细看逻辑,就是输入char[],输出String的一个解密器。

Java层的逻辑大概就这么多了,先过一个游戏(当然也可以修改smali来直接调用d.setSelectTile()来直接结束游戏显示入口),之后就是正式入口了,没有设置什么陷阱。


JNI的入口是public native String Decode.check(String input, String md5_sign) 看起来是需要签名的md5做什么事情,不要擅自篡改。

这时候随便输入一点东西,点确定,发现我的Nexus5报错了,说签名被修改?拿室友的小米4.4.4也说签名不对?还好我的Nexus 6P没事,说flag错误,如图。。。

查一下为什么会发生这样的事情,这里大概尝试了N个小时为什么4.4.4不能运行,主要逻辑是这样

这里尝试了很多方法,最后实在不行patch反调试后,开始debug,结果发现ret1和ret2都是非0的、而且执行到了正确解压的分支,靠!不可能啊啊啊啊,这题有毒啊,我执行解密解压是正确的!我也很绝望啊!所以,我也不知道为什么4.4.4是无法运行的。

好吧,那我们先放下这个问题不管,看一下native的逻辑。

先看init_array,进来就是一个反调试,新开一个线程,不停fork、sleep、kill。

再看看JNI_OnLoad,跳到了0x18D8 JNI_OnLoad_init。

先解密了3个string,再注册方法,八九不离十就是那个Decode.check(),跟过去看一下。

0x1810是JNI_Decode_check的入口,先把字符串拿一下,然后代入0x1628 main_check,第一个参数是input_string,第二个参数是md5,第三个参数是返回的result。

逻辑比较清晰,注释也在代码里写好,挑主要的说,两个难点,一个是解密一堆数据,另一个是解密后的调用。

先看0x1580 decrypt_with_md5 ,输入是待解密数据、长度、密钥,逻辑也比较简单,直接按字节xor即可拿到解密后的数据,后面调用了zlib的uncompress,解密一下可以得到2组数据。

file命令看一下

第一个是ELF文件,第二应该是一段汇编,可能是启动命令吧。手动patch掉,patch的方法是覆盖掉dec1本来的数据,再按P来显示反汇编。

之后就是比较精彩的部分了,代码里调用了(p_fun2)(&v13);我们解密后看一下p_func2到底是在做些什么。

修好后的fix.so的0x30e8就是要解密后的代码了,看起来是用llvm写的,很丑,其实我也没大看懂,前几句是

大概呢就是拿到调用之前的一些数据,总共有3个有用的:

1. p_func1,指向那个ELF文件
2. const_10000,一个数字0x10000
3. p_dlsym,指向之前调用dlsym的地址

其中有个so_main,和mprotect,猜一下意思,是去调用解密出来的ELF里的这个函数,中间那一大堆llvm的东西可能是对字符串的第一次加密,我们暂且先不管。。。

果然在跳出一大堆翔一样的代码后有这么一句

就是调用so_main,传递的参数暂时还比较迷,没太懂。那么就开始分析so_main吧!

新建了个结构体,也不知道前两个字段是干嘛的

分析一下,发现是一个RC4的加密,根据输入的内容,以及32位的key,加密后与预期进行对比。

先写个python看一下到底是不是RC4,因为check_success和check_fail都调用了这个解密方法,很容易验证,不过flag解密估计是一堆乱码,毕竟可能2次加密后的结果。

写个py脚本,先验证一下check_success时的结果,再解密一下被加密过的flag。

卧槽?居然有明文?好吧,这样就莫名其妙拿到了flag。。。

 

我还以为那堆llvm里有第一层加密,结果没有什么卵用,嗯就这样愉快的结束了。。。

最后还有两个疑点:

1. 为什么4.4.4不成功,至今不明白,猜不透(搞不懂)
2. 那堆llvm代码是干嘛的(懒的看)

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code