iOS逆向 -- 逆向初探

共 5819字,需浏览 12分钟

 ·

2021-07-07 17:29


本文由作者 小峰子 投稿,文章来源于掘金,点击阅读原文查看作者更多文章

https://juejin.cn/post/6963963222936256519


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

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

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

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



逆向涉及到的知识


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

• 工具的使用(包括但不限于砸壳工具,dump工具,静态分析工具,动态调试工具,界面分析工具等),工具一定要会用,就算不知道对应原理只要会用也能逆向开发
• dyld,macho,符号表等包含了编译和链接相关的知识,需要分析macho文件内容
• ARM64汇编的一些基础指令看得懂,部分关键方法名会被混淆,需要看汇编明白它在做什么
• 底层知识知道越多越好,主要是hook相关的,比如Method Swizzling,FishHook,InLineHook三种hook方法要懂
• iOS系统的文件结构,大概知道不同的文件目录下存储着哪些内容就行
• 动态库的原理要知道,注入代码都是以动态库的形式
• 基本的终端操作和一点点shell基础,便于使用脚本快速执行
• 常见加解密手段和抓包工具,网络传输数据通常会加密,获取到秘钥是关键的步骤



逆向开发流程


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

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

1.越狱

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

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

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

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

打开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适当简化下。

3.砸壳

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

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

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

动态砸壳的原理主要是:

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

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

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

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

终端执行

./dump.py -l

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

然后通过

./dump.py 应用名称

即可实现一行代码砸壳。

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

区分是否砸壳的标志是macho中cryptid的值是否为0

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

otool -l macho路径 | grep crypt

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

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

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

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

苹果的加密处理在砸壳工具泛滥的今日,不仅防不住,还会增加应用程序的包体积,是否还有存在的必要?

4. class-dump

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

class-dump的主要原理是:

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

通过指令:

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

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

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

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

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

5. 静态分析工具

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

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

iOS主要使用的静态分析工具有Hopper和IDA。

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

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

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

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

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

6. 动态调试工具

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

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

LLDB的原理是这样的:

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

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

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

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

当遇到某些内容被混淆甚至加密的情况下,掌握了动态调试,混淆和加密基本上就失去了意义。
因为无论如何混淆和加密,在内存中总会有一个时刻需要解混淆和解密进行调用,只要捕获到这个时刻,通过动态调试可以很轻松的获取这个时刻关键值,混淆和加密工作即使做得再花里胡哨也起不了作用。

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

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

6. 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的一般是他人所写的方法,直接方法交换存在崩溃的风险,所以逆向开发底层一般使用getimp和setimp的处理方式。对应的是使用Theos写tweak的logos语法。

iOS的代码一般包含:

• oc方法
• 系统c函数
• 自定义c函数

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

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

7. 代码注入

代码注入也有三种方式:

• 将动态库上传到DynamicLibraries目录下
• 使用dyld中的DYLD_INSERT_LIBRARIES环境变量
• 使用optool或者yololib工具给macho新增Load command

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



总结


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

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

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

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

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

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



推荐阅读

☞  打造一个通用、可配置、多句柄的数据上报 SDK
☞  京东APP中Flutter探索及优化
☞  iOS Pod 构建缓存方案


分享,收藏,点赞,在看四连,就差您了 👇👇👇

浏览 99
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报