恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
iOS逆向第一道门槛:FairPlay加密与砸壳原理及Frida实战
首页
资讯中心
/
iOS逆向第一道门槛:FairPlay加密与砸壳原理及Frida实战
iOS逆向第一道门槛:FairPlay加密与砸壳原理及Frida实战
发布时间:2026/10/14 15:54:06
1. 机会藏在细节里为什么说“砸壳”是iOS逆向的第一道门槛做iOS逆向的人无论你是想分析某个App的接口逻辑、学习第三方SDK的实现方式还是排查崩溃堆栈里那些陌生的符号几乎都会在第一周遇到同一个词——砸壳。我在拿到第一台越狱测试机的时候其实完全不懂砸壳的意义。当时只是照着教程敲命令看到一串日志刷过去然后就“成功”了。后来开始系统做应用分析才发现这一步搞得糊里糊涂后面会处处踩坑。尤其是当你处理的目标App带着App Store的FairPlay加密而你又必须在静态分析工具里看清它的真实代码时这一层壳就是你必须迈过去的第一道坎。应用砸壳本身倒不复杂核心思路就是用工具把目标进程在内存中解密后的可执行文件完整导出然后把Mach-O二进制重新打包成可以静态分析的“裸文件”。整个过程快的话几十秒慢的话可能需要几分钟取决于目标App的体积和你的设备环境。这篇文章不打算写成纯命令粘贴手册我尽量把背后的原理、命令行里的每一个细节、以及我实际调试过程中碰到的几种翻车情况都讲清楚。如果你刚接触iOS逆向或者已经在逆向的路上但砸壳总出奇怪问题这篇文章应该能帮你省下不少折腾时间。2. 壳的本质与砸壳原理拆解2.1 App Store的加密机制到底做了什么很多人听到“壳”这个字以为它像PC软件那样是某种加壳工具把代码压缩混淆后套了一层。iOS里完全不是这么回事。App Store的加密机制叫FairPlay DRM它并不是把整个App压缩成某种自解压包而是在Mach-O二进制的可执行文件上做了一层加密处理。系统在安装或启动App时由内核态负责解密App被执行时内存中的镜像已经是解密后的明文代码了。所以问题的关键就变成了磁盘上拿到的文件是加密的但内存里跑着的是明文的。砸壳本质上就是“在代码运行起来的那一刻把内存里的明文镜像重新保存下来”。这也是为什么所有砸壳方案都绕不开“动态执行”这个前提——静态分析那个加密文件是没有任何意义的。具体点说App的Mach-O文件里有一个加载命令叫LC_ENCRYPTION_INFO它记录了加密偏移范围。你在终端里用otool -l查看一个从App Store下载的App会看到类似输出cmd LC_ENCRYPTION_INFO cmdsize 24 cryptoff 16384 cryptsize 245760 cryptid 1这个cryptid字段是1就代表当前文件是加密状态。砸壳完成之后你再去查看同一个文件cryptid会变成0同时整个二进制的代码段已经被明文填充了。2.2 两种典型的砸壳思路理解了加密的位置之后砸壳方案无非两条路。第一种是古老的dylib注入方式。你通过环境变量DYLD_INSERT_LIBRARIES向目标进程注入一个动态库让它在App启动早期就开始运行。动态库在运行期拿到被解密后的Mach-O内存布局然后把进程的整个镜像dump下来最后做一次地址修正写回成一个新的可执行文件。经典工具dumpdecrypted就是这条路线。第二种是更现代的Frida方案。Frida本身就是一个动态插桩框架它可以在目标进程运行时注入JavaScript脚本脚本遍历进程内存中的Mach-O结构将各个segment的数据读出来重新组装成一个未加密的二进制文件。frida-ios-dump是这条路线里最有名的一套脚本。两条路线的最终产物是一样的区别只在于你控制进程生命周期的方式和脚本功能的丰富程度。Frida方案明显更灵活所以我后来的工作流基本都固定在第二种方案上。当然原理必须都懂因为实际场景里总会有工具失灵的时候这时候你就得自己拼一个方案出来。2.3 你需要的环境清单与核心工具砸壳发生在iOS设备侧但真正操控它的主机通常是一台Mac或者Linux电脑。我先列一下我实际环境里的东西你可以作为参考项说明测试设备越狱iPhone系统版本和越狱工具要匹配主力机绝对不要用越狱环境越狱工具装好之后确保ailaunchd或者类似服务启动正常主机一台能跑Python的电脑Mac或Linux都行SSH设备端安装OpenSSH方便传输文件Frida设备端安装frida主机端安装frida-tools辅助工具frida-ios-dump脚本、otool、lipo、class-dump读到这里你应该已经理解了砸壳这件事的一个矛盾点越狱本身就是为了能跑不受限制的代码而砸壳又是依赖于这种不受限制环境的。所以如果你的测试机没有越狱后面的所有内容基本都走不通。3. 从零开始一次完整的手把手砸壳实录3.1 环境搭建与联通检查别急着上来就dump。很多初学者第一个坑就是设备端和主机端的Frida版本对不上导致后面出现的错误莫名其妙。我建议先把两边的Frida都装到最新稳定版。设备端通过Cydia或Sileo安装frida主机端用pip安装pip install frida-tools装完之后先在SSH里确认设备端frida版本ssh root设备IP frida --version再回到主机端验证frida-server在设备上是否正常运行frida-ps -U这里有个细节如果你看到“unable to communicate with frida-daemon”不要慌大部分是frida-server进程没启动或者版本匹配出了问题。重启一下frida-server或者把越狱商店里的Frida重新装一遍基本都能恢复。我自己调试的时候遇到过特别诡异的情况frida-ps -U能列出进程但执行dump脚本时连接直接断开。后来排查发现是目标App在启动早期做了反调试检测主动杀掉了被注入的进程。这个问题我会在后面专门讲。3.2 定位目标App的安装路径与进程名砸壳之前必须先搞清楚你要砸哪个App以及它的可执行文件躺在哪里。这一步看起来简单实际操作起来有一些需要注意的地方。先在主机端运行frida-ps -U这会列出设备上所有正在运行的进程。注意有些App如果开了防调试或者不活跃可能不会出现在列表里你可以在设备上手动点开目标App再执行一次。对于安装在越狱设备上的App它的安装路径一般是/var/containers/Bundle/Application/UUID/应用名.app/可执行文件这个UUID是每次安装时系统随机生成的所以路径不能靠猜。你可以用SSH直接在设备上find出来find /var/containers/Bundle/Application -name *.app找到目标App的.app目录之后可执行文件名通常和App显示名称一致也可能有一些特殊情况比如多target的App。进去看看就知道了ls -l /var/containers/Bundle/Application/UUID/应用名.app/3.3 执行砸壳操作的标准流程现在环境通了路径也有了可以正式开始操作。如果你选择了frida-ios-dump这套脚本使用方式已经相当傻瓜化。先准备一台主机把脚本clone下来安装依赖git clone https://github.com/AloneMonkey/frida-ios-dump cd frida-ios-dump pip install -r requirements.txt --upgrade然后在目录里修改dump.py的配置把手机IP、SSH账号密码填进去。接着列出应用并指定目标python dump.py 目标App名脚本会通过SSH启动一个frida-server的转发通道然后以spawn方式启动目标App注入JavaScript逐段读取明文内存并重组成新的Mach-O最后打包成一个解密后的ipa文件。整个流程正常跑完你的当前目录下就会多出一个目标App名_debug.ipa之类的文件。如果你出于学习目的想自己动手实现一个简化版的砸壳器思路也很直接。用Frida hook住目标进程后遍历镜像的segment command把每个segment的地址范围记下来然后逐一读取内存。以下是我写过的一个简化脚本核心import frida import sys def on_message(message, payload): if message[type] send: print(message[payload]) session frida.get_usb_device().attach(目标进程名) script session.create_script( var baseAddress Module.findBaseAddress(目标模块名); var header baseAddress.readByteArray(4); // 解析mach_header、load commands并dump出各个segment )当然手工实现的难点在于Mach-O解析的完整性和对内存布局的守卫尤其要处理那些内存地址不连续、有空洞的情况。所以我推荐先用现成脚本完成业务目标再逐步研究它的内部实现。3.4 验证砸壳是否成功拿到产物只是第一步你还要确认它到底是“真壳”还是“假壳”。验证方法非常直接用之前说的otool再查一次加密信息otool -l 目标可执行文件 | grep -A 4 LC_ENCRYPTION_INFO如果cryptid变成了0说明加密段已经被解除砸壳成功。如果cryptid还是1说明脚本跑了个寂寞该文件仍然被加密。第二个验证方法是用一个能解析Mach-O的工具打开它比如IDA、Ghidra或者甚至macOS自带的nmnm 目标可执行文件 | head -50正常砸壳后的二进制能列出大量符号和函数名而加密状态下基本什么都看不到。4. 常见问题排查与避坑记录4.1 工具连接失败与进程退出砸壳过程中最让人头疼的问题是工具连不上设备或者连上了但目标App一启动就退出。我之前的排查顺序是这样的先看SSH是否能正常连接设备。如果SSH连不上大概率是设备端sshd没起来或者端口被改了。建议在Cydia里重装OpenSSH。再看frida-server状态。很多越狱工具安装Frida后frida-server不会自动常驻需要手动执行。然后用命令行测试连通性frida-ls-devices如果只显示local没有USB设备说明你的USB通道没有正确映射。在macOS上有时候需要重启usbmuxd服务。最后还要检查目标App是否做了反调试。你可以用frida尝试attach到一个系统的普通进程测试一下如果系统进程能挂载而目标App不行那大概率就是目标App的安全防护在作怪。4.2 砸出来的文件有问题符号缺失、地址错乱、崩溃有几次我砸完壳文件是生成了otool看cryptid也是0但用IDA加载起来却非常奇怪函数没几个字符串全是乱的再仔细看发现segment地址全偏移了。这个问题的根源通常是“Mach-O的File内存和加载后的内存不一致”。App运行时系统会把可执行文件按page映射进内存内存中的地址和文件中的偏移并不是一一对应的。如果你只dump了内存数据却不调整segment的fileoff与vmsize关系最终文件就会是一个错乱的镜像。解决方式是严格按照Mach-O的segment信息做重组。frida-ios-dump这类成熟脚本已经处理好了这个问题所以如果是自己实现的dump逻辑一定要认真读mach_header和load_command把每个segment的数据放到正确的文件偏移位置上。还有一个常见坑是fat binary问题。越狱设备上的主可执行文件往往是arm64和arm64e的fat架构dump脚本默认只处理当前进程运行的架构。如果目标App在arm64e设备上运行你dump到的可能是arm64e版本而分析工具不支持该架构就会显示失败。这时就需要用lipo把fat文件拆出来或者用lazy加载方式强制进程以arm64模式运行。我在实践中的处理方式是lipo -thin arm64 目标可执行文件 -output 目标_arm64可执行文件4.3 越狱检测与反砸壳的全方位对抗现在稍微正式一点的应用基本都有越狱检测和反调试逻辑。有些App比较温和检测到越狱后只是隐藏部分功能有些App则直接在启动时exit或者对调试器、注入库进行主动防御。如果目标App有越狱检测最简单的方式是先绕过越狱检测再砸壳。方案有几种使用越狱隐藏插件。越狱检测插件并不是所有设备都能稳定运行但值得先试。用Frida提前hook掉检测函数。你可以通过类的加载逻辑定位到检测方法例如常见的[NSFileManager fileExistsAtPath:]、dlopen检测、fork()检测然后全部return一个假值。先把App解压重签名去掉检测逻辑再安装这种方案往往会在重签阶段碰到新的坑因为App的签名校验和完整性校验很可能会再次触发。如果允许用调试器辅助你可以通过debugserver启动进程然后在检测函数处下断点直接改寄存器或者栈数据绕过检测后再继续运行。这种方法更底层但配置起来也更复杂。我个人的经验是不要一上来就想着绕过全套防御。先看看目标App的检测逻辑到底检测了什么再对症下药。很多“无法砸壳”的情况其实是它检测到了Frida的注入痕迹我们只需要让Frida在加载期间保持低调就行。4.4 快速问题速查表异常现象可能原因解决偏好SSH无法连接sshd没启动 / 端口被占用重装OpenSSH重启越狱环境frida-ps无设备USB通道异常 / server版本不匹配重启usbmuxd统一frida版本spawn启动后马上退出目标App有反调试或越狱检测hook检测点绕过后再dumpdump体积异常小只读取了部分segment检查架构使用thin或arm64模式二进制可打开但函数缺失符号剥离或壳没有完全去干净先确认cryptid0再看headerIDA加载呈现“歪乘”segment地址映射错乱用成熟frida脚本重新dump5. 砸壳之后的下一步四个方向帮你用好这次成果5.1 静态分析从明文二进制里挖信息拿到了砸壳后的ipa文件第一步当然是把它解压把里面的主可执行文件拿出来丢到IDA或者Ghidra里。看到大量objc_msgSend、objc_retain等Objective-C runtime调用时你知道这文件已经“活”过来了。Objective-C的Method dispatch是有迹可循的类名和sel都非常清晰几乎等于官方给了你一张代码地图。先用strings扫一眼strings 目标可执行文件 | grep -E https?://|API|key|secret|token这块信息量极大经常能直接挖出API地址、AK/SK之类的敏感配置偶尔还能看到一堆注释字符串。再从字符串的上下文反推代码逻辑可以少走很多弯路。5.2 Header文件导出让类结构一眼到底如果你是做iOS开发出身对class-dump一定不陌生。砸壳之后用class-dump导出头文件几乎是分析工作的标配class-dump -H 目标可执行文件 -o ./HeaderOutput得到一套完整的头文件之后整个App的类结构、继承关系、协议实现全都躺在你面前。虽然有些App故意混淆了类名但大部分情况下类的命名仍然能透露其业务模块的划分。比如看到XXXNetworkManager你就能确定它的网络层在这个类里看到XXXLoginViewController就可以顺着这个页面去分析认证流程。5.3 动态验证与协议分析静态分析完了你会积累出一堆“理论上应该是这样”的猜测。接下来就要回到真机环境跑起来验证。你可以重新安装砸壳后的App借助Charles或者Burp Suite抓一下网络请求把之前从静态代码里看到的URL和参数校验一遍。这个时候你会发现有些App的加密参数根本不是从硬编码里生成的而是运行时计算的。所以动态分析需要配合lldb调试或者Frida脚本在关键函数处打印入参、返回值才能把逻辑链路彻底串起来。5.4 了解反砸壳手段反向评估你的防护策略砸壳不只是用来分析别人的App它对开发者的意义同样重要。如果你自己负责的App被人砸了壳那就意味着它的加密机制基本无效了代码逻辑暴露只是时间问题。所以当你掌握了砸壳技术之后反过来思考“如何让自己的App更难被砸”是一件很有价值的事。虽然完全阻止砸壳在当前环境下并不现实但你可以通过以下手段提高攻击门槛添加反调试和越狱检测让自动砸壳工具直接失效。核心逻辑下沉到服务端客户端只做展示和交互。这是最有效的方案。对关键函数做控制流混淆增加静态分析的成本。对敏感字符串进行加密存储不要明文躺在二进制里。做了这些之后你的App面对的一般脚本型攻击就会麻烦许多攻击者必须定制专门的工具来绕过工程量自然上去了。6. 写完收工前的几句大实话我自己在砸壳这件事上踩的坑比任何一篇教程里写的都多。光“越狱环境被系统更新搞坏”这种情况我就重装了至少三轮。后来我学乖了一台专门的测试机系统版本固定住越狱工具尽量选与系统版本匹配的稳定版本绝对不随便升级系统。还有一点真心想说的砸壳本身只是逆向分析的一个准备工作而不是最终目的。很多初学者砸完壳就以为万事大吉了结果打开IDA看了一眼Objective-C的stub代码顿感人麻。真正有挑战的部分在于怎么从明文二进制里还原出业务逻辑、算法和交互流程。那才是iOS逆向真正吃功夫的地方。如果你正在学习这条路我建议你先拿自己写过的小App练手编译成一个Release版装到越狱设备上再试试砸壳、dump头文件、静态分析这一整套流程。等这套基本功熟了再去看别人家的App难度会小很多。最后再补一句所有练习请只在你自己的测试设备和合法授权范围内进行这是技术这条路上最基本的一条线。