目录

iOS反逆向方案建设思路

此文为加密收费内容添加我微信支付后可看:

https://tool.lu/netcard/

iOS反逆向方案建设思路

地球人都知道,iOS不是安全的,iOS APP更不是安全的。那如果想要提升APP的安全性,就得在网络、数据存储等方面进行建设。而对于iOS APP来说,最常见的安全能力,就是反逆向的能力。

我们先看下逆向的大致步骤,我们之前也在这篇帖子(iOS逆向学习(一)基础)里聊过,基本能分成这么几步:

1). 越狱 2). 砸壳 3). 静态分析 4). 动态调试 5). 重签多开

所以下面我们就按照这个顺序,简单分析每一步常见的技术方案,然后总结下有什么有用的信息,可以用来反逆向能力建设。

1、越狱

目前来看,越狱是一切逆向操作的首要前提。毕竟只有在越狱环境下,才能砸壳拿到ipa包。同时在越狱环境下,还可以直接进行有限的动态调试。

对于怎么防止iPhone被越狱,这是Apple的工作,就算我们想做也做不到。但是,我们可以尽自己所能的,避免自己的APP在越狱环境下运行。那就需要我们第一,能检测到当前的环境是不是越狱环境。第二,阻止APP启动,或者退出运行中的APP。

怎么检测越狱环境呢?我们得从越狱的目的上来找答案。越狱的目的显而易见,就是获得iOS系统的最高权限。我们先不管怎么去达成这个目的,只要获得了系统的最高权限,我们的APP就能调用一些本来受限的方法,比如getenv。同时越狱工具,也会在文件系统中,遗留一些特有的文件,比如MobileSubstrate之类。总之检测当前是否为越狱环境的方法千千万,就算有些方法会被攻击者使用xCon之类的工具绕过,我们还是能找出更多的方法。

那么检测到了越狱环境以后,我们理所当然的,就要阻止APP的运行,或者停用部分功能。停用部分功能的话,直接在代码里埋开关就可以了。而阻止APP的运行,要么不让APP启动,要么就退出APP。对于阻止APP启动来说,因为启动过程是由系统控制的,所以实现起来有难度,但是我们可以轻而易举的做到退出APP。我们可以构造crah,或者直接调用exit,甚至于间接的执行系统调用,来退出我们的APP。但是,退出APP的方法,都是有局限容易被攻破的,这块后面我们再详细聊。

2、砸壳

砸壳这块我们能做的其实不多,因为砸壳工具的原理,是和我们APP自身逻辑无关的。所以我们只好在上一步预防,也就是阻止我们的APP在越狱环境运行。

更多关于砸壳原理的介绍,可以参照之前的帖子:

3、静态分析

到了这里,攻击者已经拿到了ipa文件。接下来,攻击者会使用下面这些常见的手段,来对我们的ipa进行静态分析:

  • class-dump:导出所有OC代码的.h文件并分析
  • MachOView:直接阅读分析Mach-O文件
  • IDA/Hopper:进行反编译并分析汇编代码

那该怎么阻止静态分析呢?答案就是混淆。

混淆分成两种,一种是高级语言层面的混淆,也就是大家常说的代码混淆、硬编码混淆。我们平时写代码的时候,为了阅读方便,写的类名、方法名,都会多多少少的跟代码功能挂钩。比如用到了manager字样的,大多就是管理器,但是这也同样方便了攻击者进行静态分析。所以代码混淆的目的,就是在编译打包环节,把易于理解的类名、方法名,通过一定规则,替换成难以理解的形式,比如直接MD5。不过需要注意的是,大规模乱码式的代码混淆,可能会面临审核被拒的风险。其次硬编码混淆的作用,就是对代码中的字符串硬编码进行加密,以避免攻击者可以直接阅读。对于高级语言层面的混淆,更多的细节讨论,可以参照我之前的帖子:

iOS硬编码混淆

除了上面说的高级语言层面的混淆,我们还可以做汇编语言层面的混淆。这块的实现,主要是建立在LLVM的修改上的。具体细节我还没开始研究,不过这里有个开源的工具链接,感兴趣的话可以先自己研究下:

Obfuscator-LLVM

4、动态调试

动态调试的方法其实很多,可以在越狱环境下,直接运行APP以后,使用LLDB指令或者Cycript工具进行调试。也可以把ipa包集成到MonkeyDev工程里,然后在非越狱环境下,使用XCode进行动态调试。先不管两种方式的区别,其共同点都在于,我们的APP能正常运行,或者说至少不退出,攻击者才有机会进行操作。那该怎样操作呢?

对于在越狱环境下的动态调试,我们可以采用越狱环境检测+APP主动退出的方案。而对于非越狱环境下的XCode调试,就可以采用debug状态检测+APP主动退出的方案。越狱环境检测的方案前面说过了,我们来聊下debug状态检测+APP主动退出。现在常见的检测方案大致有下面几种:

  • ptrace:直接阻止XCode调试,更多原理分析可以参照之前的帖子:细说ptrace反调试
  • sysctl:检测是否处于debug状态,需要手动退出APP
  • isatty:同上
  • ioctl:同上

其他的方案大家也可以自己搜索一下,总的来说。debug状态检测的技术实现方案并不多,就算加上汇编化之类的变种也是有限的。所以攻击者可以消耗较少的精力,来绕过这些检测。

除去上面说的两种防御方案,我们发现攻击者采用的动态调试方案,大多还是依赖dylib注入的。所以我们还可以通过__RESTRICT设置,来禁止dylib注入。但是很不幸,__RESTRICT可以通过修改可执行文件的源文件绕过,所以也比较容易攻破。

5、重签多开

重签多开的意思,是指攻击者用自己的证书,对我们的ipa包进行重签名,并同时运行多个,这是黑产常用的一种手段。那怎么预防?老样子,先检测。

我们知道,每个iOS应用都有着唯一的ID,也就是bundleID,而想要实现重签多开,就必然要改变原有的bundleID。所以,这个环节的防御,我们主要还是集中在对Info.plist文件的改动检测上。我们可以直接通过系统API NSBundle来读取Info.plist文件信息,也可以通过对应的CoreFoundation方法来做。当然这两种方式显而易见是不安全的,攻击者随手写个hook就可以攻破。所以我们就换个方式,使用其他的方案直接读取Info.plist文件,比如NSData、mmap、拷贝一份改个名字再读等等等等。反正读取文件的方式千千万,可以让攻击者疲于奔命。

那检测到了以后,怎么阻止呢?也是同样的道理,我们可以选择功能关闭或者退出APP。而在前面的部分,我们也说过主动退出APP的方式是不好的,至于为什么不好,我们现在来聊一聊。

我们可以选择的主动退出APP的方案,其实并不多。主要就是构造crash、调用terminateWithSuccess之类的上层API、调用exit之类的系统底层API。要想攻破这些并不困难,对于crash可以根据栈帧定位我们的崩溃代码,上层API直接hook就好。exit之类的底层API,如果是直接使用那也就直接hook搞定。如果是汇编化的变种,直接使用IDA修改源文件就行。

更多的APP主动退出方法,可以参照我的开源实验工程:https://github.com/BenArvin/iOSAppExitTest

6、反逆向方案

前面我们聊完了攻击者常用的逆向方法,和对应的防御方案,那么我们的反逆向方案应该设计成什么样子呢?

首先,我们要明白,我们的一切工作,都不能完全的防御所有攻击,我们所做的只是增加攻击者的攻击成本。所以,对于主动退出APP这种技术方案有限,攻击者在攻击时有迹可循的防御方案,我们都不应该投入精力去建设。相应的,我们的反逆向方案,应该建设成下面的样子:

  • 1)编写阶段:对核心功能,采用C语言、汇编语言等静态语言编写
  • 2)编译阶段混淆:代码混淆、硬编码混淆、资源文件混淆、汇编混淆等
  • 3)运行阶段逆向检测:越狱环境检测、重签多开检测等
  • 4)运行阶段功能限制:代码开关、封号、封手机等