将Frida集成到 iOS 项目中
前言
前段时间项目遇到一个偶现的bug,偶尔在一台手机复现,但是这台手机多半不是连接着 xcode 所以调试就比较困难。所以希望把 frida 集成到项目中,最好能指定 debug 包。然后复现之后利用 frida-trace -U Twitter -m "-[NSURL* *HTTP*]"
等方式 hook 方法下断点查看参数与返回值,具体用法参考文档
下载
去官方 Frida releases 下载最新版本的 dylib, 例如写文时最新版本为 15.1.21,在下载列表可以看到:
frida-gadget-15.1.20-ios-universal.dylib
文件
frida-gadget-15.1.20-ios-universal.dylib
是一个胖二进制文件,用 machOView 打开可以看到有x86_64
、ARM64_ALL
等多个架构的动态库。对于笔者当前项目来说只需要 ARM64
架构的, 所以先用 lipo
抽取一下:
lipo frida-gadget-15.1.20-ios-universal.dylib -thin arm64 -output FridaGadget.dylib
得到 FridaGadget.dylib
文件。
lipo
的使用可参考mac 上lipo命令总结
重新签名
FridaGadget.dylib
文件需要先用自己的开发者账号签名一次,否则后边 xcode 会验证不通过,重签分两步:
- 列出钥匙串里可签名的证书
security find-identity -v -p codesigning
- 选择一个证书对
FridaGadget.dylib
签名
codesign -fs 281BEEB4DA14AFA907319146EFCBXXXXXXXXXXXX FridaGadget.dylib
终端输出FridaGadget.dylib: replacing existing signature
重签完成
集成
经过调研有两种方式:
- 动态库集成
- Framework (Pod)集成
动态库集成
- 创建
Frameworks
文件夹
mkdir Frameworks
- 将
FridaGadget.dylib
移动到Frameworks
文件夹中
mv FridaGadget.dylib ./Frameworks/FridaGadget.dylib
- 将
Frameworks
文件夹拖到Xcode
项目中 -
Xcode
-TARGETS
-General
-Frameworks, Libraries, and Embedded Content
, 找到添加的FridaGadget.dylib
库,没有的话点击+
号添加一下,Embed
选项选择Embed & Sign
- 编译运行,APP 运行起来后终端输出
Frida: Listening on 127.0.0.1 TCP port 27042
表示成功
注意
这里必须创建Frameworks
文件夹,如果直接将 FridaGadget.dylib
拖到项目里,程序运行起来就报错:Library not loaded: @executable_path/Frameworks/FridaGadget.dylib
这是因为 FridaGadget.dylib
动态库中 LC_ID_DYLIB
的 Install Name 写死了为@executable_path/Frameworks/FridaGadget.dylib
如果没有
Frameworks
文件夹,最终FridaGadget.dylib
就不能被放到 APP 包内的Frameworks
文件夹中,导致运行因找不到动态库而报错崩溃
Framework (Pod)集成
运行成功后会发现终端输出显示成功,但是 APP 一直卡在启动界面,这是因为 FridaGadget.dylib
为了保证启动流程的控制,默认阻塞了进程,这会导致应用必须在 Frida Console Attach后才会继续运行。但是正向开发中很少用到它,只是在个别情况才会用到它,希望它不影响正常开发流程。这就需要通过修改源码解决。
现在很多项目都用 CocoaPods 管理集成,动态库集成的方式不太方便。为了将FridaGadget.dylib
打成 Pod,首先要将其封装成Framework。
对于常规 Cocoa Touch Dynamic Framework ,其 Install Name 一般为 @rpath/SomeLib.framework/SomeLib
的形式,显然 FridaGadget.dylib
的 Install Name 与其不符。这就要求修改 FridaGadget.dylib
的 Install Name 为正确格式,并将其包装成标准 Framework 格式。
我们可以通过machOView
修改动态库的 Install Name,但是还有进程阻塞问题需要修改源码才能解决,所以我们一并通过修改源码来解决这两个问题
源码
根据 官方文档 clone make 项目,编译过程中会报错找不到签名证书,这时候需要根据 github 里的macOS and iOS
描述创建证书,并倒出到环境中。然后执行编译命令
make core-ios
make gadget-ios
修改默认阻塞行为
文件路径frida/frida-core/lib/gadget/gadget.vala
,搜索on_load
,将WAIT
修改为RESUME
即可,如下为修改后:
public LoadBehavior on_load {
get;
set;
default = LoadBehavior.RESUME;
}
修改 Install Name
文件路径frida/frida-core/lib/gadget/meson.build
,找到如下代码:
if host_os == 'macos'
identity = '@executable_path/../Frameworks/FridaGadget.dylib'
elif host_os == 'ios'
identity = '@executable_path/Frameworks/FridaGadget.dylib'
else
identity = gadget_name
endif
ios
的identity修改,如下:
if host_os == 'macos'
identity = '@executable_path/../Frameworks/FridaGadget.dylib'
elif host_os == 'ios'
identity = '@executable_path/Frameworks/FridaGadget.framework/FridaGadget'
else
identity = gadget_name
endif
修改完成,重新编译,文件 frida/build/frida-ios-arm64/usr/lib/frida/frida-gadget.dylib
就是我们需要的 ARM64
架构的动态库文件,我们可以复制到别处并改名为FridaGadget
(不再需要.dylib后缀),用 machOView
看下:
现在 Install Name是符合要求的了。
Framework 封装
一个 Framework 需要包含 dylib 、info.plist 等文件,否则 Xcode 编译时会报错,这里我们创建一个名为 FridaGadget
的 Cocoa Touch Framework
工程,build 后将二进制文件替换为真正的 FridaGadget
,就完成了 FridaGadget.framework
的封装。(替换后记得对FridaGadget进行重签)
Pod 导入
- 创建
FridaGadget
文件夹
mkdir FridaGadget
cd FridaGadget
将FridaGadget.framework
移动到FridaGadget
文件夹
- 在
FridaGadget
文件夹创建podspec
文件
Pod::Spec.new do |s|
s.name = 'FridaGadget'
s.version = '0.0.1'
s.summary = 'FridaGadget'
s.source = { :path => './' }
s.platform = :ios, '9.0'
s.requires_arc = true
s.author = 'thinkq'
s.vendored_frameworks = 'FridaGadget.framework'
end
- 在 iOS 工程的
Podfile
里引入FridaGadget
pod 'FridaGadget', :path => '../git_pods/FridaGadget'
- install
pod install
- 编译运行项目,APP 运行起来后终端输出
Frida: Listening on 127.0.0.1 TCP port 27042
表示成功。此时 APP 进程不会被阻塞到启动界面
参考:
重新編譯FridaGadget使其更好地用於非越獄機的代碼調試和自動化測試
https://www.shangmayuan.com/a/da1b15c5e65340ea906e9661.html
https://www.jianshu.com/p/d68924e1af25