文本内容只为交流学习之用,如有人用于非法用途,产生的后果笔者不负任何责任。由于本人水平有限,不足之处还请大家多多指正。
0x00 前言
前段时间在审计一款iOS棋牌手游的时候,发现了大量的luac加密文件,文件头部都是统一的Magic number,这引起了我的好奇。于是,一番搜索,发现这是使用了cocos2d-x引擎写的游戏,游戏逻辑使用lua脚本编写,为了不暴露lua源码,把lua编译为luac字节码并做了加密处理。关于解密的文章,网上搜索到的大部分都是Android系统下的,iOS的很少,虽然cocos2d-x是跨平台的,但是在逆向破解的过程中发现两个平台还会有些不一样的地方,于是有了本文。
0x01 一些简单的尝试
在学习了一些解密思路后,开始了一些简单的尝试,首先观察到所有luac头部的Magic number都是一样的,这个Magic number很有可能是使用xxtea加密算法加密的sign值。如下图入红色打码部分就是Magic number。
xxtea加密算法一般需要一个sign值和一个key来加密,首先尝试直接在IDA中搜索sign值字符串,sign值附近的字符串很有可能就是key值。但最终没能在IDA里找到与sign匹配的字符串,看来这款游戏还是做了一些防护的。
接下来尝试定位加载lua脚本函数,然后用lldb断点调试,找出加密使用的key值。按照网上介绍的方法,在IDA里直接搜索加载解密后的lua脚本函数luaL_loadbuffer
,iOS一般情况下都是搜索不到的,因为Android的lua解析引擎是native的代码,需要编译为so来调用,这就需要导出相关函数给java调用,而iOS可以使用静态混编,clang编译器在编译c/c++代码的时候一般都会把函数符号给strip掉,因此iOS不像Android那样可以直接搜索关键函数。但是这里却神奇的找到了,可能是开发者不小心忘了strip了?
欣喜之下赶紧在Xcode里打了符号断点,然而还是高兴的太早了,断点根本就没有触发。难道没有调用这个函数去加载lua脚本?又尝试了luaL_loadbufferx
函数和一些相关的导出函数,然而都没有断下来。What?!这里请脑补黑人问号的表情。。。
通过函数符号既然断不下来,那就接着尝试定位没有符号的函数,然后通过函数地址下断点。通过搜索关键函数里的字符串特征”error loading module '%s' from file"
定位luaL_loadbuffer
函数。这里定位到三个函数里出现了关键字符串。
通过函数的文件地址+ASLR偏移分别对这三个函数下地址断点,然而函数还是没有断下来。
这时我仿佛觉得事情并没有那么简单,这些暴露出来的定位函数的关键点可能只是为了迷惑逆向人员而放的的烟雾弹。
0x02 另辟蹊径
既然你把函数符号strip了,字符串也都做了处理,还放了烟雾弹。那我就另辟蹊径,通过一些必须调用的系统库函数作为入口点。既然你要处理文件,那肯定要调用库函数fopen吧,但是fopen调用的太频繁,怎么定位到我们感兴趣的点呢?答案是是使用Xcode的debugger command,当然你也可以使用fish hook,把fopen的参数打印出来,调用栈也打印出来,发现以.luac
结尾的文件,就是你感兴趣的点。
按照这个方法一步步跟到解析出文件头部sign值的函数,但跟到这里调用栈就莫名的没有了,IDA里xref这个函数的时候发现是一个在常量区的vtable虚函数表,这下静态分析也断了。
查看这个vtable发现了关键点cocos2d::LuaStack
,于是到cocos2d开源的github库去搜索了一番,最终定位到CCLuaStack.cpp
这个源码文件,然后通过对比源码和IDA里vtable的相邻函数,最终定位到了我们感兴趣的函数luaLoadBuffer
的地址。于是,迅速的计算ASLR偏移地址,下断点,然后惊喜的发现,lldb的反汇编跟IDA里的居然对不上!What?! 请再次脑补黑人问号表情。。。
0x03 lldb的坑
经过一番搜索,有人说是高版本lldb的问题,也有人说是32位iOS设备上可能反汇编出来的是arm指令集,与IDA里的thumb指令不一致。
先尝试把arm指令反汇编为thumb指令,使用命令di --start-address 0x00AABBCC -c 10 -A thumbv7
转换,然而发现还是一样不一致。
于是又尝试下载了Xcode7.2,使用低版本的Xcode的lldb去调试,由于低版本的Xcode对高版本的iOS系统不兼容,期间又解决了一些兼容性的问题。最终调试后发现,问题依旧,还是不对上啊😢。在各种对比各种求问搜索后最终认为应该是计算ASLR的基地址出了问题。
我一般是使用image list
这个lldb命令确定基地址的,但是网上搜索到一篇帖子说image list -o -f
确定的基地址会出现问题,而image list
却是好的,而且两者的基地址居然不一样。于是我尝试使用image list -o -f
这个命令发现确实和image list
的基地址不一样,然后尝试使用image list -o -f
的基地址计算出ASLR后的地址,下断点,最后惊奇的发现,居然能对上了!What?!
这里使用image list -o -f
确定的基地址虽然正确了,但是其他模块的地址却是一样的,这也是有问题的吧,有图有真相
image list -o -f
和image list
都有问题,那多了-o -f
参数后两者有什么却别呢?
看样子-o
参数还是要加的,但是加了其他模块的地址却都是一样的是什么鬼?lldb的bug?
0x04 柳暗花明
经过一番折腾,lldb断点终于能断在正确的位置上了,经过调试前面发现的luaLoadBuffer
函数,最终发现了xxtea解密的关键密钥key。现在有了sign和key,那解密就很好说了,网上有很多解密工具可以使用,打开解密工具,填上key和sign,成功解密出lua脚本。
参考:
https://bbs.pediy.com/thread-216969.htm
https://www.freebuf.com/column/173230.html
https://blog.csdn.net/lwanttowin/article/details/80628835
https://zhuanlan.kanxue.com/article-8282.htm
http://bbs.iosre.com/t/lldb-image-list/7593/6
EOF