第1章
iOS逆向工程简介
虽然从理论上来说iOS App是一个运行于沙箱(sandbox)中的程序,但并不表示我们就对它束手无策,事实上,可以通过逆向工程来一窥其究竟。接下来,就引入iOS软件逆向工程的概念。
1.1 iOS软件逆向工程的要求
iOS软件逆向工程指的是在软件层面上进行逆向分析的一个过程。读者如果想要达到对iOS软件较强的逆向分析能力,最好能非常熟悉iOS设备的硬件构成、iOS系统的运行原理,还要具备丰富的iOS开发经验。比如:拿到一个App之后能够清晰地推断出这个App使用的技术,包括引用了哪些framework、哪些经典的第三方代码,以及整个App工程大致的文件个数、大致的代码行数,另外,还要想象一下如果由自己来组织设计开发,需要投入的人员、时间和精力等。
这要求高吗?其实真的不算高!不过,这些条件都是充分非必要的。如果你目前还不具备这些技术条件,那么有两个必要条件则一定要满足:强烈的好奇心和锲而不舍的精神。因为在iOS软件逆向工程中,好奇心会驱动你去钻研经典的App,而在钻研的过程中会遇到一系列的困难和障碍,各种各样的技术坑,别人埋的、自己挖的,此时就需要锲而不舍的精神来支撑你一步步向前走。但是请相信,在投入大量精力去编写代码、调试程序、分析逻辑之后,你会在不断的试验和错误中感受到逆向工程的艺术之美。
1.2 iOS软件逆向工程的作用
打个比喻,iOS逆向工程就像一杆长矛,专门用于刺破目标程序本以为安全的保护盾,而且还是从想象不到的角度来刺破。
对于微信、陌陌、WhatsApp之类的IM软件,交流的信息是它们的核心;对于银行、交易支付、电商类的软件,交易和客户信息是它们的核心。所有的核心数据都是需要重点保护的,于是,数据库加密、网络连接加密、云存储等,开发人员通过各种手段重重保护,为的就是让使用者能够高枕无忧。
可是iOS逆向工程对这些常规App的攻击不是来自同一个维度!这些攻击可用一个词来定义:维度攻击(“维度攻击”的概念来自科幻小说《三体》,在此向《三体》致敬)。
从维度的角度来解释,我们看待常规App的感觉更像是将App的所有数据、UI、逻辑内容都平展地铺开在一张二维的大纸上,外围圈上厚厚的城墙。它的平面图概念如同图1-1所示的谷歌地图一般。
图1-1 飞到二维城市的上空来俯瞰整座城市
但是当我们跳跃到城墙之外,在三维的天空中俯瞰这个App的二维城堡,这个城堡的内部结构几乎完全开放在眼前,包括所有的Objective-C函数定义、所有的接口数据、甚至所有的函数内执行代码。城墙的防护意义已经荡然无存!此时限制我们的只是这个二维平面城堡到底有多大,里面的内容到底有多丰富,以及排列是整齐有序的还是杂乱无章的。
此时,基于逆向工程的技术能力,可以选择想进入的任意点“高维进入”,监视甚至改变二维平面上的运行逻辑,从而达到获取核心信息或软件设计原理等战术目的,而不是从二维世界打破外围城墙强行攻破。
说得似乎很玄乎,但事实上,就笔者对十余款经典App以及iOS系统进行逆向的经历过程来看,逆向工程的使用确实无一例外地达到了目标。
上面的比喻虽有些不恰当,但也形象地说明了iOS逆向工程的强大能力。现在回到正题,概括起来,iOS逆向工程主要有两个作用:
❏攻破目标程序,拿到关键信息,可以归类于与安全相关的逆向工程;
❏借鉴他人的程序功能来开发自己的软件,可以归类于与开发相关的逆向工程。
接下来就让我们将这些内容逐步展开。
1.2.1 与安全相关的iOS逆向工程
从前面的内容介绍已可以大致了解,iOS逆向工程最突出的应用领域就是与安全相关的。比如:工程师通过逆向一个金融类App,来评定这个软件的安全等级;安全专家通过逆向iOS病毒,来找到杀毒的方法;安全公司通过逆向iOS系统电话、短信功能,来构建一个手机防火墙……
1.评定安全等级
iOS中那些具有交易功能的App一般会先加密敏感数据,然后将加密过的数据存储在本地或通过互联网传输。而如果安全意识不够强,就完全有可能将重要的用户信息(如银行账号和密码)直接用明文保存或传输,安全隐患极大。
假如一个有名望的公司考虑推出一款App,为了让自己App的质量能够对得起用户的信任,该公司请一家安全公司帮忙评估这个App的安全性。这家安全公司自然是不会被授权使用这个App源代码的,也就是说,正向分析其安全性不可行,所以他们只有通过逆向工程,来尝试“攻击”这个App,然后依据结果评定其安全等级。
补充说明:前面在介绍“维度攻击”的概念时已经提及,App虽然可以将低维的攻击防守得如铜墙铁壁一般,但是挡不住高维的逆向攻击。不过不可以据此得出App不安全的结论,因为iOS逆向工程的使用均来自一个前提:iOS越狱。普通用户可能不知道,在将iOS设备越狱之后,即将整个平台都置于风险之中,此时也就更谈不上App的绝对安全了。在这种环境下,我们使用这些逆向工程技术来分析评估目标App中可被攻击点有多少,可攻击点越少的自然就是越安全的。
2.逆向恶意软件
iOS是智能移动终端操作系统,它同计算机操作系统已没有本质区别。从第一代开始,它就已具备了上网功能,而互联网正是恶意软件传播的最好媒介。2009年暴露的Ikee病毒是iOS上公开的第一款蠕虫病毒,它会感染那些已经越狱并且安装了SSH,但是又没有更改其默认root密码"alpine"的iOS设备,并且将它们的锁屏背景图改成一个英国歌手的照片。
对于恶意软件的开发者来说,他们通过逆向工程定位系统和软件漏洞,利用漏洞渗透进目标主机,获取敏感数据,甚至为所欲为。
对于杀毒软件的开发者来说,他们通过逆向工程剖析病毒样本,观察病毒行为,尝试杀掉被感染主机上的病毒,并总结出可以防范病毒的方法。
3.检查软件后门
开源软件的一大好处是其具有较好的安全性。成千上万的程序员浏览并修改开源软件的代码,代码中几乎不可能存在任何后门,软件的安全问题往往在大白于天下之前就能及时得到解决。而对于闭源软件,逆向工程是检查其软件后门的方法之一,比如我们常会在越狱的iPhone上安装360、金山、腾讯等各家手机安全助手,这些服务程序的权限极高,无一例外都拥有超强的能力,可以访问用户的通话记录、短信记录甚至更多,但我们不知道它们会不会收集不该收集的用户信息,并把这些信息上传到自己的服务器。这种“有或没有”的结论一直是个争议,我们得不到可信的官方数据,那么就只能通过逆向工程来检查该软件是否存在类似的后门。
补充说一句,这些手机安全助手的开发者们本身也是逆向工程的高手,善用矛的同时也善用盾,想要达到同台PK的水平需要积累锻炼足够长的时间才行。
4.去除软件使用限制
iOS开发者通过App Store或Cydia出售自己的App,作为他们最主要的经济来源之一。在软件的世界里,收费与盗版永远是同时存在的,而不少iOS开发者也在自己的App里加入了反盗版的功能。但这场矛与盾的战争永远不会停止,再好的防御也会有被攻破的一天,防止盗版几乎是一项不可能完成的任务。比如,Cydia上最知名的“共享”源xsellize能够在几乎所有收费软件发布后的3天内对其完成破解,让他们的用户免费享受到收费软件的功能。
1.2.2 与开发相关的iOS逆向工程
对于iOS开发者来说,逆向工程是最为实用的技术之一。例如,工程师可以逆向系统调用,在自己的程序里使用一些文档中没有提及的私有功能,还可以逆向一些经典的软件,包括竞争对手的软件,从而研究自己的软件能够借鉴些什么技术。
1.逆向系统调用
程序员编写的软件能够运行在操作系统中,提供各种各样的功能,是因为操作系统本身已经内嵌了这些功能,软件只是拿来重新组合使用罢了。众所周知,能在App Store上架的App的功能十分有限,在苹果公司严格的审核制度下,绝大多数App的实现都源于公开的开发文档,而不能使用诸如锁屏、关机等文档中不涉及的功能。如果你的程序面向Cydia,那么不采用非公开功能将导致程序几乎没有竞争力。如果你的程序想拥有打电话、发短信等不公开的功能,最有效的途径就是逆向iOS系统调用,还原系统实现相应功能的代码,并应用到自己的程序中。
2.借鉴别的软件
逆向工程最受欢迎的应用场合就是“借鉴”他人的软件功能。对于来源是App Store的App来说,大多数技术的实现并不复杂,巧妙的创意和良好的运营才是其成功的关键。如果只是单纯借鉴其功能,那么采用逆向工程,费时费力,性价比不高,从头开发一个功能类似的软件反而要省时省力得多。但是,当我们不知道被借鉴软件中的某个功能是如何实现的时候,逆向工程就能起到关键性的作用。这种情况在大量使用私有函数的Cydia软件中尤其常见,比如2013年3月面世的,号称iOS平台上第一款通话录音软件的Audio Recorder,足够有趣,但我们不知其原理如何,此时使用逆向工程的技术就能够对它了解一二。
有些软件,比如微信,功能经典,结构也非常复杂,所涉及的代码自然十分多。图1-2是使用class-dump获取微信4.5的.h文件目录。
图1-2 通过class-dump获取的微信4.5的.h文件目录
可以看到,在目录中共有2267个.h文件,光是将文件名一个个地看下来,天都要黑了。那这种情况下应该怎么办?当然不可能这样傻傻地一个文件一个文件地读过去,事实上,这时便可以通过合适的逆向分析工具加上丰富的开发经验来帮助定位关键信息点。对于微信这样足够经典的目标程序,使用的技术及框架都非常有借鉴意义,所以也值得我们对它进行逆向工程,收集相关的知识并学习,进而一步步地掌握其精髓。
1.3 iOS软件逆向工程的一般过程
当我们想要逆向一个iOS软件时,应该从何入手?应该怎么思考?这本书的初衷就是引导初学者走进iOS逆向工程的大门,培养读者从逆向的角度思考问题。
所谓的iOS逆向工程初学者,其实至少也是iOS App开发的中高级程序员了,理论上都拥有相当丰富的开发经验。所以在后续的过程中,对于一些非常初级的技术原理,可能会讲得非常简单,甚至直接被忽略,毕竟读那些内容对有经验的开发人员来说是在浪费时间。
一般来说,软件逆向工程可以看做系统分析和代码分析两个阶段的有机结合。在系统分析阶段,要从整体上观察目标程序的行为特征、文件的组织架构,从而找到我们感兴趣的地方。一旦能够较为熟练地操作这个程序,并且找到了我们想要逆向的点,就可以进入代码分析阶段,利用各种工具对程序本身的二进制文件进行分析,达到我们的目的。
1.3.1 系统分析
在系统分析阶段,应在不同的条件下运行目标程序,在程序中进行各种各样的操作,观察程序的行为特征,同时寻找我们感兴趣的功能点。比如:选择哪个选项会弹框,按下哪个按钮会发声,输入什么内容屏幕会有什么显示;同时,还可以浏览文件系统,观察程序显示的图片、程序的配置文件存放在哪里,对应的数据库文件中存放了哪些信息、是否加密等。
以新浪微博App为例,当我们将微博的目录展开时,会看到如图1-3所示的结构。在微博目录下有Documents、Library等子目录,这些目录中放着对应的数据库文件以及缓存的图片文件等。
另外,在Documents目录下还可以看到db_36000_3414827754.dat这样的文件,从文件名上即可识别出它是数据库文件,此时使用SQLite工具打开便可看到如图1-4所示的数据内容。
图1-3 新浪微博App的Documents目录
图1-4 新浪微博App的个人数据文件
此时,我们能够看到在新浪微博里的联系人、所发的微博内容等信息。
因为这些信息已经通过App自身的目录文件结构呈现在我们面前,所以可以看到,对iOS平台以及App的理解程度直接决定了我们在逆向工程时所需要花费的时间和精力,以及所获取信息的性价比。
1.3.2 代码分析
在外围的分析完成之后,接下来就是对程序的可执行文件进行代码这一层级的分析了。
使用逆向分析的方法可以倒推出这个程序的设计思路、内部算法和实现细节,这是一个非常复杂的过程,甚至可以说是一种解构的艺术。要想让自己的逆向工程水平达到艺术的高度,需要对软件开发、CPU工作原理和iOS有透彻的理解。而且很多软件的复杂度很高,即使其代码规范、文档详尽,可是一旦开源,很多人还是会因其具有的复杂度而惊叹,比如Activator这样的系统级插件程序。一点一点地分析程序的底层指令绝非易事,也不是一本书能够完全阐述清楚的。
本书的目标仅仅是向初学者讲述iOS逆向工程入门时所用到的工具和可能的思路,书中所提及的工具及知识均是笔者长期积累的个人经验之谈,对知识点的覆盖不可能面面俱到,期望读者能结合书中的理论和实例举一反三,形成自己的学习方法。
1.4 iOS软件逆向工程用到的工具
对于iOS的逆向工程,除了掌握理论知识之外,最重点的内容就是使用好各种工具了。整个iOS逆向工程所涉及的工具数量达到数十款之多,而且这还未100%覆盖到。因为毕竟在这一方向没有一套统一的教学规范来指明哪些工具该用,哪些工具不该用,各个参与者都是根据自己掌握的深度及喜好来选择最称手的工具的。
好的工具,以及对这些工具的熟练使用能够极大地协助我们进行高效的逆向工程。在本阶段的逆向工程中,介绍的工具集主要可以分为四大类:监测工具、开发工具、反汇编器(disassembler)、调试器(debugger)。
1.4.1 监测工具
在逆向工程中,起到嗅探、监测、记录目标程序行为的工具统称为监测工具。这些工具通常可以记录并显示目标程序的某些操作,如网络活动、文件访问等。iOS逆向常用的监测工具有Reveal、tcpdump、libNotifyWatch和PonyDebugger等。
图1-5中所呈现的是一款监测工具——Reveal,它可用来查看目标App的UI元素。
图1-5 Reveal——用来查看目标App的UI元素的监测工具
使用Reveal可以非常直观地看见App的界面上各个UI元素之间的从属关系,并且轻松、快捷地定位到我们想查看的UI元素。有了类似这样的工具,很多我们原本以为会非常枯燥的分析工作均可以轻松搞定,达到事半功倍的效果。
1.4.2 开发工具
进入代码分析这一层级,就必须掌握开发工具的使用了。实际上监测工具与开发工具一直都是组合使用的,单纯使用某一类工具根本无法深入。
对于有成熟开发经验的iOS程序员来说,Xcode是最常用的开发工具,但在此之外,还有可以用于开发越狱代码的工具,其中最方便也最有名的一个工具就是Theos。这是一个非常简单易用的开发工具,但是它能编译生成最具威力的tweak插件,直刺App心脏,完成我们期望它完成的任务。
图1-6是Theos的创建工程命令行。
图1-6 Theos——tweak开发工具
在后面的工具篇中会详细介绍Theos的使用方法。仅从个人体验来说,这是让笔者最为兴奋的开发工具,在接触、使用Theos之前,笔者感觉自己一直都被限制在普通App的低维世界中,直到学会并掌握了Theos的使用方法,才觉得真正突破了普通App的开发界限,跨越了维度的限制,可以从高维来看待App了。
1.4.3 反编译器
随着自己能力的一步步进阶,反编译器就会出现在我们的视野中。在iOS逆向工程领域,反编译器主要就是IDA。
IDA是逆向工程中最常用的工具之一,横跨Windows/Linux/Mac平台,它会把目标程序的可执行文件作为输入,然后输出这个程序的汇编代码,甚至伪代码。
反编译是跟CPU架构相关的,但像IDA这样强大的反编译器支持多种CPU架构,如图1-7所示。
IDA有免费版本,可以输出函数列表及对应的汇编代码。而相较于免费版的IDA,收费版本所能带来的功能就更为震撼了。图1-8是IDA Pro(收费版)的截图,对于iOS App,它能做到的不仅仅是反汇编,甚至连伪代码都能高度接近。
图1-7 IDA——强大的反编译器
图1-8 IDA反编译App的伪代码
笔者第一次看到这样的伪代码时,不禁感叹:逆向分析工具都强大到了这一步,还有什么是能藏得住的?
1.4.4 调试器
对程序员来说,调试器是相当熟悉的了,最常见、最熟悉的就是在Xcode中的单步调试,程序员可以在某一行代码上设置断点,使调试器能够在那一行代码执行之前暂停程序执行,并且显示程序当前的状态。
因为程序员拥有自己程序的源代码,所以调试器的断点可以指定在源代码的代码行上,单步调试可以以源代码的行为单位执行代码。而熟悉Xcode调试的人也都知道,其实所谓Xcode的调试器,不过就是把GDB(GNU Debugger)或LLDB做了一层图形化的包装,集成在一起更好用而已。
但是在逆向工程中,我们往往没有目标程序的源代码,而且需要在iOS设备上进行调试,此时就需要在iOS设备上运行基于命令行的GDB了。图1-9是使用GDB进行调试的示例。
图1-9 GDB——调试利器
当然,我们同样可以利用调试器设置断点、单步调试,来观察甚至更改程序的执行流程,从而达到分析程序的目的,只不过这个过程不如拥有代码调试那么直观、方便。
1.5 小结
本章介绍了iOS软件逆向工程的基本概念、作用和一般的逆向过程,以及需要用到的一些有代表意义的工具等,旨在让读者对iOS逆向工程有一个概念上的了解,详细的技术内容会在后面的章节中逐一讲解。