Blog.GC

记一次失败的逆向之旅

| Comments

楔子

前段时间,实验室一哥发现了EA的一款手游挺不错,遂在实验室小范围传播了开来。你说这游戏吧,它又肝又氪,让人停不下来。这不,上上周出了个活动,这个活动和之前的不一样,它可以重复刷,而且体力消耗非常慢,你要是慢慢玩,一整天都不见得能把体力清完。一哥一看,哟,可以生财啊,便在电脑上装了模拟器,再用上按键精灵,美滋滋地当上了矿主。但是我这个iOS用户就苦了,电脑上没有模拟器,平时又紧跟潮流,升级系统,也没法越狱。但是看看他们安卓派的,上到一哥,下到小师弟,都开张赚得第一桶金。再看看对门二狗,不仅在电脑上开,还在平板上开,大刀阔斧搞建设。大家都是科技工作者,凭啥iOS的就得那旁边看着?!我也来搞呗……

第一章 当头一棒

说搞就搞,问题在于怎么搞。

根据我多年前搞MA的经验,多半也是本地计算,然后HTTP请求。那果断打开Fiddler,然后给粪叉配置好Fiddler的证书,没办法,苹果强制都要上TLS。一通抓包,有所发现,但是怎么都是登录内容,没有具体游戏数据。这就奇了怪了,它这不可能不传输啊。没办法,请出Wireshark大佬,把粪叉接到机子上,运行rvictl。又是一通抓包,发现在游戏中确实不断地在通信。这一下,就上头了,难道是纯TCP流?毕竟大厂,还是有可能的。但这可难不倒我,掏出神船笔记本,上面装的可是KALI系统,启动sslspit(官网)。在粪叉上设置好网关,打开游戏,报错连不上网。

嗯?

再看看Wireshark抓出来的包吧,基本都是报inappropriate fallback,心头一凉,多半是有服务器证书校验了。这样的话,搞MITM基本是没戏了。(这是当时的想法,最终还是搞了MITM,这里暂时不表。)

既然搞不了MITM,那就试试能不能对流量解密罢,谷歌一通搜索,倒是发现了一篇报告,叫*TLS Session Key Extraction from Memory on iOS Devices*,确实不错,但是需要越狱,如果不越狱就要重新打包,有点麻烦,先作为一个可选项放着吧,想想有什么更简单的办法。

就在左思右想的时候,Joker跑来说了一句:“你不是有Mac么,Xcode里不是有模拟器么😂”

第二章 铩羽而归

Joker这一句话,让我精神为之一振。用Fiddler从App Store抓到了ipa,往模拟器里一放,直接就给你报错。百度瞎查了一会,可能是没有砸壳,上某助手上下了砸壳的ipa,还是不行。再仔细搜索一了下,只能说苹果真的好心,App Store发布的程序,都会根据设备优化。也就是说,我拿粪叉下的App,只可能包含arm指令,根本不支持模拟器的X86指令,模拟器这条路算是彻底断了。

吐血

不过,现在手头有了砸了壳的ipa文件,先来看看里面有些什么吧……呃,一些素材,一些贴图,一坨配置文件,一个二进制文件。看到了二进制文件,我就又上头了,正好前不久刚逆向了一个安卓安全键盘的APP,现在还在兴奋点上。抄起Hopper,先看看String,找点灵感。结果灵感没找到,就找到些零碎的信息,什么DirtySockProtoHttp之类的,上网查了之后,顺便发现了EA开源的修改版Webkit。就这么看看二进制文件,时间倒是过去了好几天,这样下去可不行。

第三章 陷入僵局

也不知哪个神经元被激活了,我突然想起了家里还有一个沉睡许久的5c,应该可以越狱。轻车熟路越狱之后,第一个想到的就是之前的那篇报告。配置好Frida,先按照报告里的代码跑,结果发现只能解出极少数的Master Secret,想想不对啊,虽然文章里说,可能是因为SSL Session的关系,但是只解出这么点是不可能的。看来还得自己动手,刚好它hook的是苹果开过源的coreTLS,找到源码开始啃,同时也看看网上对于TLS握手的分析文章。哦,不知道是不是他们故意把代码写成错的,还是什么情况,明明报告里自己也说了tls_handshake_internal_prf不仅要计算Master Secret,同时也要做Key Expansion,但是代码里却只解析了Key Expansion的情况。但是,实际上hook tls_handshake_internal_prf的时候,可以在onLeave的时候调用另外两个函数tls_handshake_internal_master_secrettls_handshake_internal_client_random,这在tls_handshake.h头文件里都写着,不知道为啥那篇报告里没有这么做。

Master Secret

代码是改好了,Master Secret也解出来了,但是发现了一个问题,没有解出游戏内容的流量的Master Secret。难道是我还有遗漏的地方?把整个coreTLS代码来来回回翻了几遍,把几个怀疑对象用Frida分析一下,并没有什么特别的结果。这时候,我心中突然有一个想法,就是对于游戏内容,它并不是用系统接口进行传输的,可能是在底层的socket上构建的私有实现。毕竟大厂,可能有现成的库,又联想到前面的DirtySockProtoHttp,应该是八九不离十了。

为了验证自己的想法,我直接对send函数进行hook,抓到了游戏数据的TLS握手包,如下图:

握手

同时,查看了调用堆栈,并没有任何上层系统调用,说明应该是私有实现了。

握手

既然是私有实现,网上也没有相关资料,那就只能反汇编找找突破口了。跟着调用堆栈,诶,不对啊,Frida给的调用堆栈,并不是调用send的函数。惊了,试了好几次都不行。但这时候,也不想找原因了,先想想怎么办吧,隔壁矿主都四矿了。好吧,上lldb+debugserver吧,挂线程,找偏移,下断点,一气呵成。第一次倒也顺利,命中断点返回了正确的调用堆栈,但是之后就直接崩了,报Terminated due to signing error。重试了几次,大多数上来就崩,偶尔命中了断点再崩,总之就是崩崩崩,谷歌了半天也没什么有用的信息,如果哪位大佬有思路,请务必告诉我,在此先谢过了。

虽然lldb用不成了,还有ida呢,打开ida,挂线程,找偏移,rebase,下断点,一气呵成,还是崩。那……应该是debugserver的问题了吧。虽然debugserver不能用,但我毕竟已经拿到了正确的调用堆栈,还是可以分析的。于是纵身一跃,跳入了arm汇编的汪洋大海。

几天后,觉得事情不对,我根本分析不出结果。这时候要是能下断点,单步分析该多好啊,但是debugserver又用不了,Firda的调用堆栈又不靠谱……

第四章 柳暗花明

人,确实是一个神奇的生物。正在汇编泥潭中挣扎的我,在寝室里吃小浣熊的时候,不知为何突然想起了,之前ipa包中,有一个Symantec.cer的证书文件。又联想到,之前Wireshark抓包的时候,客户端请求的密钥交换算法是RSA,那么这个证书应该就是用来校验服务器发来的公钥的,RSA从算法上就能在一般情况下防御中间人攻击。如果把这个证书换成我自己生成的ca证书,不就可以用sslsplit搞MITM了么。那一夜,兴奋得做梦都在笑。

第二天,连院士来开讲座都能迟到的我,竟然早早地醒来了。到了实验室,二话不说就开搞,把证书拷到手机里,替换原有的证书,打开sslsplit……我擦!成了!老子也要开矿啦!谁说用iOS的不能当煤老板!兴奋之余,还是先看看数据的内容吧。Emmmm,HTML头部写着数据类型是protostuff,一查,这个不是Java的序列化库么,但是手机端应该是用C++写的吧,那估计就是用的Google Protobuf了,服务器端用的Java,毕竟EA开源的项目,除了Java就是C++了。然而摆在眼前的问题是,如何在没有proto元文件的情况下解出里面的内容了。

这玩意网上不应该没有吧,一通搜索,找到几个,但都不好用。那就自己写呗,谷歌的东西,文档(地址)还是写得很清晰的,动动手,就把解码脚本写出来了。(已经上传到GitHub,欢迎围观

终章 向大厂低头

包是解了,但是毕竟没有描述的文件,只能猜意思,边玩边抓边解,倒也猜出了大半。先试试发几个包看看,结果……

还是大厂玩得6啊

不得不说,大厂就是大厂,在这里等着我呐。这就意味着,解不出它的Checksum算法,就没法发送自定义的数据包。虽然知道算出来的是32位的校验和,估计是CRC32或者Adler32,又知道数据流在获得Session之后才会有Checksum,估计SessionId是盐,但又有什么用呢,不知道它是怎么组合的啊。我的矿,就这么矿难了。

本着破罐子破摔的想法,我进行数据包重放,结果,嘿,百密一疏啊。大厂并没对数据包里的时间戳进行校验,也就是说,可以重放数据包。好吧,虽然做不成全自动矿机,半自动的傻瓜矿机还是可以的。

至此,两周的逆向之旅,最终以这种方式迎来的结局。不得不说,离我的想象还是有距离,主要还是自己实力不足导致的,没能够从二进制文件本身出发,逆向出关键算法。

题外话

虽然这番折腾延误了我本身的研究,但是确实已经很久没有自发地、这么激情地折腾一件事了,即便结果不是那么理想,我依旧从中感受到了快乐。

扯个屁的蛋,周末还要交提纲呢,还不去分析实验数据。

一首《凉凉》送给我自己。

jioleng

Comments

comments powered by Disqus