本文为2016年0ctf中的mobile题目boomshakalaka的writeup。

1

boomshakalaka

首先点我下载APK,安装运行APK后,发现是一个类似之前微信上的打飞机游戏。
直接用jeb反编译APK,没有任何保护处理,反编译代码如下图:
2
可以看到APK初始化时,新建了两个xml文件,分别为flag.xml和CocosdxPrefsfile.xml,并且分别写入了一些字符串,其中flag文件中的YmF6aW5nYWFhYQ==明显为base64编码,随便找了个在线base64解码,解码后为bazingaaaa,再凑上Flag的标志,组合为0ctf{bazingaaaa},提交后提示错误。
运行游戏,没有得分,直接暂停。CocosdxPrefsfile.xml的内容为:
MGN0ZntDMGNvUzJkX0FuRHJv
经过多次测试,每次游戏完成初始化后,CocosdxPrefsfile.xml的内容均为上诉字符串。同样是base64编码,解码后为0ctf{C0coS2d_AnDro,很明显地方找对了,但是Flag不全。
接着继续游戏,随便得了几分,然后撞死。CocosdxPrefsfile.xml的内容为:
MGN0ZntDMGNvUzJkX0FuRHJv...dz99
发现除了开始初始化的固定字符串意外,结尾也同样是固定的dz99,猜测是游戏结束时写入的固定串。
根据得到最高分的提示,开始找关于得分的函数。Java层没几个类,因此重心转到so,把libcocos2dcpp.so拖到ida里,通过score关键字找到关键函数ControlLayer::updateScore(int),直接F5后,发现逻辑就是根据每次击中飞机得到的分数,向CocosdxPrefsfile.xml写入对应的字符串,如图:
3
4
值得注意的是,其中最大分数被设置为1000000000分,其对应的字符串为4w,因此结合前面分析,字符串为:
MGN0ZntDMGNvUzJkX0FuRHJv4wdz99
解码后为0ctf{C0coS2d_AnDro?,出现了乱码,明显还是不对。
分析到这里,这道题几乎已经是完成了。剩下的就是开始拼凑Flag了。通过多次尝试,最后我们按照ControlLayer::updateScore(int)中所有分数的从小到大的顺序,将其对应的字符串组合到一起为:
MWRfRzBtRV9Zb1VfS24w
再将头部和尾部组合到一起:
MGN0ZntDMGNvUzJkX0FuRHJvMWRfRzBtRV9Zb1VfS24wdz99
解码后为0ctf{C0coS2d_AnDro1d_G0mE_YoU_Kn0w?},搞定。

总结

  1. flag.xml的内容是为了提示我们CocosdxPrefsfile.xml的内容也是base64编码。
  2. 千万不要真的手动打最高分,毫无意义。

最后吐槽一下,这道题毫无技术含量,逻辑也有很大问题。从技术来看,只要具备基本的Android逆向技能,就能定位到ControlLayer::updateScore(int),事实上,我用了5分钟就找到了这个函数,但是到最后找到Flag用了几个小时。按照题目得到最高分的提示,我直接在上层函数修改了分数为1000000000分,得到字符串为MGN0ZntDMGNvUzJkX0FuRHJv4wdz99。我继续尝试修改分数为2147483647(32位有符号整数的最大值),得到字符串为MGN0ZntDMGNvUzJkX0FuRHJvdz99。然后又设想了整数溢出之类的问题。最后的答案竟然是把所有分数的字符串全部拼在一起,我不知道这样拼凑和play the game, get the highest score有什么联系,并且正确的Flag几乎不可能出现在CocosdxPrefsfile.xml中。
讲道理而论,这道题真的浪费了我几个小时的青春(当然不排除我不玩ctf,too young too simple,sometimes naive)。