iOS逆向 -- 逆向初探

1,185 阅读12分钟

由于公司的业务主要是支付方面,所以之前有动力研究了些逆向相关的知识。

鉴于逆向涉及到的知识面既广且杂,而且操作流程也多,用到的工具也多。想着,不妨把操作流程相关知识记录一遍,以备不时之需。(主要是被人问到了,虽然答完了,但也突然有了做这个记录的想法)

本来逆向的章节是打算等底层系列最后几篇文章结束后开始,可是既然被问到了,就没有不总结的道理。于是就有了这篇文章。

需要强调的是,逆向的初衷绝对是保护自己的app

1. 逆向涉及到的知识

涉及到的相关知识主要从我自身学习的感受出发,觉得哪些重要,掌握了对逆向开发有帮助的我就在这里提一下。以下肯定会存在一些纰漏,望指出,后续及时更新,避免误导。

  1. 工具的使用(包括但不限于砸壳工具dump工具静态分析工具动态调试工具界面分析工具等),工具一定要会用,就算不知道对应原理只要会用也能逆向开发

  2. dyldmacho符号表等包含了编译和链接相关的知识,需要分析macho文件内容

  3. ARM64汇编的一些基础指令看得懂,部分关键方法名会被混淆,需要看汇编明白它在做什么

  4. 底层知识知道越多越好,主要是hook相关的,比如Method SwizzlingFishHookInLineHook三种hook方法要懂

  5. iOS系统的文件结构,大概知道不同的文件目录下存储着哪些内容就行

  6. 动态库的原理要知道,注入代码都是以动态库的形式

  7. 基本的终端操作和一点点shell基础,便于使用脚本快速执行

  8. 常见加解密手段和抓包工具,网络传输数据通常会加密,获取到秘钥是关键的步骤

2. 逆向开发流程

刚开始学的时候,也尝试搜了些相关资料,结果发现里面很多专有名词看的一头雾水,很多技术手段单看觉得还好,但不知道该怎么串起来使用,很影响学习下去的兴趣。

想来,大部分初学者多半也是会有这样的感受。我就把通常的逆向开发流程整理下来,有兴趣的小伙伴可以对着流程一步一步的去找相关资料来研究,思路会清晰很多。(不含工具下载配置流程,这部分网上内容很多,只给出工具名和一些基本的讲解)

1.越狱

准备一台越狱手机是逆向开发的第一步。目前,越狱的方式众多,都基本都是傻瓜式操作。我个人目前使用的越狱手段是通过爱思助手

截屏2021-05-19 上午11.13.22.png

根据手机的系统版本选择对应的选项,如果版本较高,选择CheckRa1n,按照提示一步步完成即可越狱。

越狱后,屏幕上多出CheckRa1n应用程序,打开选择安装Cydia,因为我已经安装过了,提示会不一样。

IMG_0329.PNG

安装成功后,界面多出Cydia应用程序。

IMG_0330.PNG

打开Cydia,如果正常运行说明已是越狱环境;如果闪退说明是非越狱环境。

需要注意的是,越狱分为完美越狱非完美越狱两种情况。

  • 完美越狱:越狱很彻底,破解了操作系统的读写权限,完美越狱完成以后可以自由使用,开关机也不影响

  • 非完美越狱:关机后会重新回到非越狱环境

目前,完美越狱只支持到iOS9,所以大家手上的手机大部分肯定只能非完美越狱了。

但是鉴于目前越狱流程及其简单,就算是非完美越狱关机后也只要重新再越狱一次即可回到越狱环境。所以,并非要刻意的追求完美越狱。

然后需要去Cydia中安装一些插件,包括但不限于:

  • Apple File Conduit "2",可以获得根目录访问权限。

  • AppSync Unified,可以绕过签名检测

  • adv-cmds,命令行

  • OpenSSH,远程登录

  • Frida,砸壳

等..

2. Openssh

OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。 SSH协议可以用来进行远程控制, 或在计算机之间传送文件

逆向开发一般使用到手机和电脑两个终端,这两者使用Openssh连接。

Openssh的连接方式有:通过网络连接和通过USB连接。

通过USB连接会更稳定效率也更高,所以我常用的是USB连接。这里连接的终端指令基本又臭又长,需要使用shell适当简化下。

2.砸壳

分析应用的前提是要先获取应用的安装包。iOS主要的下载渠道是appstore,可是appstore上下载的包苹果会对__TETX段里面的内容进行加密,如果不解密无法做后续操作。

所以砸壳技术就应运而生了。

砸壳分为静态砸壳和动态砸壳,主流的形式是动态砸壳。

动态砸壳的原理主要是:

虽然macho中的__TEXT段被苹果加密了,但是系统如果要运行程序,肯定需要对内容进行解密。所以就不去主动的砸掉原有的加密壳,而是当应用程序运行后,壳被系统砸掉后,在内存中把砸壳后的数据取出来,也就达到了砸壳的目的。

砸壳的工具也比较多,我个人目前使用的是frida。至于安装步骤配置啥的,网上教程也很多,这里就不说明了。

安装完来到frida-ios-dump目录下,

截屏2021-05-19 下午1.28.37.png

通过dump.py脚本执行对应的命令。

终端执行

./dump.py -l

截屏2021-05-19 下午1.30.07.png

会列出手上已经安装的app,如果是运行状态,还有对应的pid

然后通过

./dump.py 应用名称

截屏2021-05-19 下午1.33.07.png

即可实现一行代码砸壳。

砸完壳后的包在frida-ios-dump目录内。

区分是否砸壳的标志是machocryptid的值是否为0

一般使用otool指令查看对应的macho的段和对应的值。

otool -l macho路径 | grep crypt

截屏2021-05-19 下午1.53.46.png

可以看到,cryptid的值为0,说明这是砸壳后的macho了。

当然也可以把macho拖入MachoView(查看macho的软件)中直接查看:

截屏2021-05-19 下午2.59.25.png

来到LC_ENCRYPTION_INFO_64段下,Crypt ID同样是0

获取到包后,可以先查看包内容。里面有图片文件,声音文件,plist文件,动态库信息,glsl文件等,通过这些信息就可以对应用程序有个大致的了解了。

3. class-dump

class-dump就是用来dump头文件的工具,简单好用。

class-dump的主要原理是:

编译后,macho中就存放着存放着类名和方法名等信息,通过内存地址的偏移,可以找到它们对应的段,然后依次输出内容,也就能获得头文件信息了。

截屏2021-05-19 下午3.36.03.png

通过指令:

class-dump -H app包路径或者app可执行文件路径 -o 输出的路径

截屏2021-05-19 下午3.45.42.png

一顿输出后,获取到了微信的头文件,有20000多个..

随便打开一个文件看看内容,

截屏2021-05-19 下午3.49.33.png

头文件里面包括了这个类所有的属性方法协议等关键信息,其中很多甚至可以见名知意。

有些app会对关键属性名和方法名做混淆处理,这时候显示的就是混淆后的乱码了,遇到这种情况也不用慌,可以使用静态分析工具大概查看它的实现逻辑,虽然麻烦些,但还是可以解决的。

4. 静态分析工具

静态分析工具是能够将macho文件的机器语言代码反编译成汇编代码、OC伪代码或者Swift伪代码,同时可以快速查看关键字符串信息。

这就很强大了,意味着可以通过查看方法的执行流程,判断条件等信息明白它在做什么,如果本地字符串未做混淆,也可以直接被获取到(比如有些app秘钥明文存储本地,这就危险了)。

iOS主要使用的静态分析工具有HopperIDA

IDA更强大,它能够翻译成的伪代码更接近于高级语言,但是它的收费也是昂贵的。

Hopper虽然不如IDA强大,但也是够用的了,所以我个人使用的是Hopper

把macho文件直接拖入Hopper,尝试搜索你感兴趣或者头文件中存在的字符,会得到如下界面:

截屏2021-05-19 下午4.51.54.png

如果你有汇编基础,能够直接分析最好,如果没有的话也不是束手无策。

或者有些经过混淆的方法名和字符串,通过静态分析是无法直接得到,这些时候就需要动态调试的帮助了。

5. 动态调试工具

动态调试就是将程序运行起来,通过打断点(LLDB需要)、打印等方式,查看参数、返回值、函数调用流程等信息,通过输出界面信息迅速定位目标代码,还可以动态的修改内存和寄存器中的参数,达到绕过检测,更改执行流程等目的。

动态调试主要有LLDBCyCript两种工具,两种都很好强大,也各有各的好,建议两种方式都需要学习。

LLDB的原理是这样的:

Xcode启动程序的时候,就会在自动在手机上安装一个debugserver程序,XcodeLLDB工具会跟debugserver进程进行交互,将lldb指令传输给debugserver进程,debugserver进程又会将lldb指令传输给AppApp执行完之后,会将返回值传输给debugserver进程,debugserver程序又发给LLDB,在控制台显示出结果。

至于LLDBCyCript的主要区别在于,LLDB需要卡住进程进行调试,而CyCript调试时需要进程处于活动状态。

二者也都可以提供一些高级用法,lldb可以取别名和开发插件的形式使用,常用的指令也可以放入.lldbinit文件;而cycript也可以进行高级封装,对外提供简单易懂的调用名即可。

说实话,动态调试占用逆向开发的流程的时间比重是很大的。因为逆向开发主要的工作就是分析和查找定位关键代码的行为。动态调试的熟练程度基本决定了逆向开发的耗时。

当遇到某些内容被混淆甚至加密的情况下,掌握了动态调试,混淆和加密基本上就失去了意义。

因为无论如何混淆和加密,在内存中总会有一个时刻需要解混淆和解密进行调用,只要捕获到这个时刻,通过动态调试可以很轻松的获取这个时刻关键值,混淆和加密工作即使做得再花里胡哨也起不了作用。

退一步来说,比如app里面使用了这些值做了流程判断,检测之类的,即使无法还原这些关键值,也完全可以动态调试修改值查看不同的执行流程,如果是检测类的代码就更简单了,直接hook后固定返回YES

当通过动态调试定位到关键代码,并且确定该如何修改后,就需要使用动态库写hook代码并注入了。

5. Hook

在ios系统中常用的hook技术有三种:

  • Cydia Substrate

  • Symbol Table

  • Method Swizzing

Cydia Substrate的方式会修改被hook的函数的前8个字节,使该函数跳转到我们设定的新的函数地址,这种方式叫做inline hook,是在运行期间hook的,对应的框架是Dobby

Symbol Table符号表的hook是修改符号表所指向的内存地址,在编译期就进行了交换,对应的框架是FaceBook发布的fishHook框架。

Method Swizzing是ios开发常用的记录,但是逆向开发的 Method Swizzing是有别于开发过程所使用的。开发时hook基本是hook系统已存在的类,而逆向开发hook的一般是他人所写的方法,直接方法交换存在崩溃的风险,所以逆向开发底层一般使用getimpsetimp的处理方式。对应的是使用Theostweaklogos语法。

iOS的代码一般包含:

  • oc方法

  • 系统c函数

  • 自定义c函数

这三种方式刚好对应使用上面三种hook方式。

写好hook代码的动态库,需要注入到原目标应用里才能生效。

6. 代码注入

代码注入也有三种方式:

  • 将动态库上传到DynamicLibraries目录下

  • 使用dyld中的DYLD_INSERT_LIBRARIES环境变量

  • 使用optool或者yololib工具给macho新增Load command

需要注意的是,前两种方式必须在越狱环境才能使用;而对应用进行重签名后,就可以在非越狱环境下使用第三种方法了。

3. 总结

逆向开发的流程可以总结如下:

准备一台越狱手机,对目标应用进行砸壳,然后class-dump出头文件,使用静态分析工具对应用进行初步分析和关键内容提取,使用动态调试工具通过界面信息等迅速定位目标代码,修改和调试关键值和流程,然后使用动态库写hook代码,注入目标应用,重签应用。

越狱 --> 砸壳 --> class-dump --> 静态分析 --> 动态调试 --> hook --> 注入 --> 重签(非必须)

最后,介绍一款工具叫MonKeyDev。它是对以上众多逆向开发工具和步骤的整合,可很快捷的实现上述一系列操作。

截屏2021-05-19 下午7.08.19.png

直接把目标应用包丢进TargetApp目录下,写对应的logos,就可以一步到位实现重签,注入,然后下载到手机的步骤。

以上是对逆向开发流程部分原理,所涉及到的相关知识点的整理。而涉及到具体的工具下载,配置和使用就不展开了,这些展开也有不少内容且网上教程也很多,本文的定位也只是逆向初探,了解逆向是在做什么即可,后续的章节可能会对这些内容做适当的补充。

敬请关注。