前言
本文仅作为技术分享,对于一些 iOS SDK 开发以及保护所遇到的场景问题进行解决,例如:
- 客户想提前通晓线上 App 集成咱们 SDK 后,是否会有 SDK 兼容性问题,例如 Crash,符号抵触
- 客户线上 App 集成了咱们 SDK,呈现了问题,如何进行排查
- 咱们想测试 SDK 在某一款 App 中是否性能失常
对于这些问题,一般来说咱们无奈拿到 App 的源码,想要解决这些场景,就须要拿到客户 App 文件并注入代码,接下来咱们从 iOS 越狱、frida 砸壳、MonkeyDev 来讲述如何实现。
iOS 越狱
为什么须要越狱?因为失常状况下,咱们无奈从手机中获取到 App 的包文件,只能通过越狱机 动静砸壳 取得 ipa 包,应用目前支流的 unc0ver 进行越狱。
unc0ver
对于 iOS 的越狱,这里应用的是 unc0ver,最新版本反对 iOS 11 – iOS 14.3 版本的非完满越狱,这里采纳应用 iphone 5S,iOS 12.4.9 为例,进行 非完满越狱
越狱有分为“完满越狱”和“不完满越狱”。完满越狱简略地说就是越狱很彻底,破解了操作系统的读写权限,完满越狱实现当前能够自在应用,开关机,下载等。称为“完满越狱”。而不完满越狱,则示意 iPhone 或 iPad 不能像越狱之前一样随时能够关机,关机重启后越狱生效,须要再进行越狱操作。
对于 unc0ver,咱们应用 Xcode + iOS App Signer 形式进行装置 unc0ver App
通过上述步骤生成的 unc0ver ipa 是合乎苹果要求的,你也能够通过 i4 助手(爱思助手)进行快捷装置到手机中。
关上 unc0ver,点击 Jailbreak 进行越狱,期间弹出 REBEL 不要管它,叉掉,持续。提醒你重启就重启,该容许的容许,而后持续关上 unc0ver 持续,直到 unc0ver 实现越狱,越狱好后,手机界面会多出 Cydia 和 Substitude,同时关上 unc0ver 显示 Re-Jailbreak。
配置 Cydia
- 点击 Cydia-> 软件源 -> 编辑 -> 增加 增加源 build.frida.re,apt.cydiami.com, 并进行更新。
- 搜寻 SSH,抉择 OpenSSH 进行装置
- 搜寻 frida,因为是 5S,咱们抉择 Frida for pre-A12 devices
- 搜寻 AFC,装置 AFC2 iOS12 系统文件拜访
至此,越狱实现,能够拜访系统文件了。
Frida 砸壳
砸壳的目标是为了获取 ipa 包,因为 Appstore 默认给应用程序加了壳(并不知道其应用了那种加密形式),所以须要先砸壳(相当于获取解密后的文件),你能够通过 AppStore 下载你须要砸壳的 App,也能够下载 i4 助手 上的 App,装置到手机上后,咱们进行动静砸壳。
动静砸壳:在运行过程内存中的可执行程序映像动手,将内存中的内容进行转储解决来实现砸壳。该办法绝对简略,并且不必关怀利用所应用的加密技术。
对于各种砸壳计划,这里应用的 Frida 砸壳:
- 下拉 frida-ios-dump
git clone https://github.com/AloneMonke…
下拉仓库。 - 装置 Python
brew install python - 装置 wget
brew install wget - 装置 pip
wget https://bootstrap.pypa.io/get… sudo python get-pip.py - 装置 frida
sudo pip install frida –-upgrade –ignore-installed six - 装置脚本依赖环境
cd frida-ios-dump 目录下
csudo pip install -r requirements.txt --upgrade
- 装置 usbmuxd 与手机通信
brew install usbmuxd - 通过 USB 应用 ssh 连贯设施,将 22 映射到电脑上的 2222 端口
iproxy 2222 22
- 另开终端退出连贯 明码为设施的登录明码 alpine,须要放弃连贯
ssh -p 2222 root@127.0.0.1
或 ssh root@127.0.0.1 -p 2222
- 因为是动静砸壳,咱们关上须要砸壳的 app,应用 frida-ps -Ua 查看正在运行的应用程序,记录下标识
PID Name Identifier
---- ----- ---------------------
4621 爱思极速版 rn.notes.best
4650 番茄小说 com.dragon.read
4720 设置 com.apple.Preferences
4547 邮件 com.apple.mobilemail
- 而后 cd 到 frida-ios-dump 目录下,执行 dump.py 命令
dump.py com.dragon.read
- 这里第一次运行在 0.00B [00:00, ?B/s] 卡住了,执行 Ctrl + C 勾销,再从新开始 dump.py
- 最终在 frida-ios-dump 目录下失去砸壳 ipa 文件
MonkeyDev
原有 iOSOpenDev 的降级,非越狱插件开发集成神器,这里仅仅应用了其局部性能,具体的装置步骤阐明见 MonkeyDev 装置。
应用
拿着之前通过 Frida 砸壳获取的 ipa 包(例如:某宝,某度,某某音乐),先创立一个 MonkeyDev 工程。这里以 PlayTheApp 为例
- 将砸壳的 ipa 放到 PlayTheApp/TargetApp/ 下,而后拖拽至工程文件中。
- 设置主工程的证书,dylib 的不必设置
提醒 Showing All Messages Signing for “PlayTheAppDylib” requires a development team. Select a development team in the Signing & Capabilities editor.,此时抉择 PlayTheAppDylib->Build Settings->Add User-Defined Setting
增加 CODE_SIGNING_ALLOWED 为 NO,再运行即可。
- file not found: /usr/lib/libstdc++.dylib 问题
起因是新版本 xcode 去掉了 libstdc++ 这个库,从老版本复制过去即可,这里间接应用 Github 上的 GitHub – devdawei/libstdc-: Xcode 10、11 和 12 中删除的 libstdc++ 库 (目录权限问题这里不再论述)
注入 SDK
能够运行之后,咱们在工程中初始化 pod,
批改 pod 文件,正文 use_frameworks!
# platform :ios, '9.0'
target 'PlayTheApp' do
# Comment the next line if you don't want to use dynamic frameworks
# use_frameworks!
pod 'GrowingAnalytics-cdp/Autotracker'
# Pods for PlayTheApp
end
target 'PlayTheAppDylib' do
# Comment the next line if you don't want to use dynamic frameworks
# use_frameworks!
pod 'GrowingAnalytics-cdp/Autotracker'
# Pods for PlayTheAppDylib
end
- 查找对应的 appdelegate 类,应用 class-dump 命令
1class-dump -H xxx.app -o yourDir/Headers
发现其 AppDelegate 类叫 XXXXAppDelegate
- 而后应用 logos 注入 SDK 初始化代码,应用文档查看官网 Logos – iPhone Development Wiki
// See <http://iphonedevwiki.net/index.php/Logos>
#import <UIKit/UIKit.h>
#import "GrowingAutotracker.h"
static NSString *const kGrowingProjectId = @"91eaf9b283361032";
%hook XXXXAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
BOOL result = %orig;
GrowingTrackConfiguration *configuration = [GrowingTrackConfiguration configurationWithProjectId:kGrowingProjectId];
configuration.debugEnabled = YES;
configuration.impressionScale = 1.0;
configuration.dataCollectionServerHost = @"https://run.mocky.io/v3/08999138-a180-431d-a136-051f3c6bd306";
[GrowingAutotracker startWithConfiguration:configuration launchOptions:launchOptions];
return result;
}
%end
而后再编译运行,曾经能够在 App 中调试 SDK,并有相干日志输入了。
至此咱们解决了 前言 中所述的第 1 以及第 3 个场景问题,对于第 2 个问题,如何排查线上 App 所呈现的 SDK 问题,则须要通过 MonkeyDev 运行之后察看日志输入,搭配注入代码,找准适合的入口办法或函数,进行办法替换,测试批改后,断定呈现问题的点再判断如何解决。
局限性
对于此计划仍有有余
- 对于局部 App,即便砸壳后也无奈失常应用。
- 如果 App 集成了老版本 SDK,想要注入新版本 SDK,就须要替换原文件或重命名。
此计划仍具备局限性,但足以应酬大多数状况,后续咱们也在欠缺这些有余,向自动化平台计划倒退。