从新编译 FridaGadget 使其更好地用于非越狱机的代码调试和自动化测试

背景

Frida 在设计之初主要是用于应用的逆向工程,使用方法通常是在越狱环境下动态注入,在非越狱环境下使用 FridaGadget 时,因为其写死了 LC_ID_DYLIBInstall Name@rpath/Framework/FridaGadget.dylib,致使直接使用时必须在工程中建立一个名为 Framework 的实体目录。对于正向开发而言,须要对这类动态库进行环境控制,即仅在 Debug 模式下引入,通常方法为将动态库打成 Pod,而后基于 CocoaPods 的语法去作环境控制。ios

对于常规的 Cocoa Touch Dynamic Framework,其 Install Name 通常为 @rpath/SomeLib.framework/SomeLib 的形式,显然 FridaGadget 的 Install Name 与其不符,为了将 FridaGadget 打成 Pod,咱们不得不将其封装成 Framework,以享受 CocoaPods 的自动签名功能,这就要求修改 FridaGadget 的 Install Name 为正确格式,并将其包装成标准的 Framework 格式。git

其次,FridaGadget 为了保证对启动流程的控制,默认阻塞了进程,这会致使应用必须在 Frida Console Attach 后才会继续运行,这很适用于逆向工程,但对于正向开发者和测试者十分不利,更为麻烦的是,FridaGadget.config 彷佛在非越狱环境下不生效,从而致使咱们没法修改 FridaGadget 的默认行为,这个问题彷佛只有修改源码并从新编译才能解决。github

封装 Framework

修改 Install Name

对于包装成 Framework 的问题,其实没必要从新编译 FridaGadget,只须要用 MachOView 打开动态库文件,找到每一个架构的 LC_ID_DYLIB 并修改 Name 字段: macos

这里的注意点是,Name 的存储方法比较巧妙,是将其直接存储在 LC_ID_DYLIB 这一条 Load Command 的尾部,经过第三个字段 String Offset 指定基于当前 Load Command 的偏移量,这一条指令的总长度为 72,字符串从第 24 个字节开始存储,所以字符串的总长度不能超过 47 (须要额外一位来存储\0),MachOView 提供了直接修改字符串值的方法,双击 Name 的 Data 行便可修改,图中所示的就是修改后的值,字符串和二进制互转可使用这个网站npm

建立 Framework

一个 Framework 须要包含 dylib、Info.plist 和 modulemap 等信息,不然 Xcode 在编译时会报错(特别是缺乏 Info.plist),这里有个取巧的方案是建立一个名为 FridaGadget 的 Cocoa Touch Framework 工程,Build 后将二进制替换为真正的 FridaGadget,即完成了 FridaGadget.framework 的包装。ruby

这里注意一个签名问题,FridaGadget.dylib须要先用本身的开发者帐号从新签名一次,不然bash

打成 Pod 库

若是直接使用动态库,须要在 Xcode 中手动配置一个 Copy File 的 Build Phase 来实现对动态库的签名和拷贝,为了将这个过程自动化,咱们能够将 FridaGadget.framework 打成 Pod 库,一方面 Pod 会为咱们自动生成工程配置,另外一方面也能够基于 Podfile 的 configurations 实现环境控制。架构

CocoaPods 包含动态库的方式很简单,只须要声明一个 vendored_frameworks测试

s.vendored_frameworks = "FridaGadget.framework"
复制代码

对于声明了 vendored_frameworks 的 Pod 库,CocoaPods 会自动为其建立 Pods-ProjectName-frameworks.sh 的脚本,并添加一个 Embed Pods Framework 的 Build Phase 来完成动态库的签名,这里有个坑咱们须要先手动重签名依次 FridaGadget.dylib,不然可能会致使 Pods 脚本中签名失败,重签名的方法可参考 Frida Doc网站

随后,将 Pod 库部署到企业私有环境或是公库下,便可经过 Podfile 直接引入 FridaGadget:

# 注意我尚未将其上传到公库,所以你没法直接这么引入
pod 'FridaGadget', :configurations => ['Debug']
复制代码

问题

这种方式完美解决了 FridaGadget 的环境控制问题,可是启动时自动阻塞进程不是咱们想要的(毕竟是正向开发环境,只是偶尔使用 Frida 来调试和自动化测试),这个问题在于 Frida 默认采用了阻塞方式,要修改能够经过在工程中建立一个 FridaGadget.config 来修改 on_load 策略,但非越狱环境 FridaGadget 下彷佛读不到 Main Bundle 中的 config 文件,所以咱们只剩下一条路:修改源码。

修改源码

修改默认行为

首先下载 Frida 源码,具体方式请参考 Build Frida,先完成 clone 便可,随后咱们须要定位到 on_load 相关逻辑的代码,全工程搜索 on_load 首先会找到一堆看起来不像是人写的 C 代码,这些代码是由 Vala Language 自动生成的,所以核心代码都在 Vala 里,随后咱们找到 gadget.vala,从中搜索 on_load 可找到默认等待的逻辑,将 WAIT 修改成 RESUME 便可:

public LoadBehavior on_load {
	get;
	set;
	default = LoadBehavior.RESUME;
}

public enum LoadBehavior {
	RESUME,
	WAIT
}
复制代码

很显然,将 default 改成 LoadBehavior.RESUME 便可。

修改 Install Name

既然要从新编译,咱们能够直接指定 Install Name 为 Framework 须要的形式,这个配置位于 Makefile.macos.mk 的第 36四、371 行,直接修改便可:

build/.core-macos-stamp-%: build/%/lib/pkgconfig/frida-core-1.0.pc
	@if [ -z "$$MAC_CERTID" ]; then echo "MAC_CERTID not set, see https://github.com/frida/frida#macos-and-ios"; exit 1; fi
	. build/frida-meson-env-macos-$(build_arch).rc \
		&& $$CODESIGN -f -s "$$MAC_CERTID" -i "re.frida.Server" build/$*/bin/frida-server \
		## Install Name
		&& $$INSTALL_NAME_TOOL -id @rpath/../FridaGadget.framework/FridaGadget build/$*/lib/frida-gadget.dylib \
		&& $$CODESIGN -f -s "$$MAC_CERTID" build/$*/lib/frida-gadget.dylib
	@touch $@
build/.core-ios-stamp-%: build/%/lib/pkgconfig/frida-core-1.0.pc
	@if [ -z "$$IOS_CERTID" ]; then echo "IOS_CERTID not set, see https://github.com/frida/frida#macos-and-ios"; exit 1; fi
	. build/frida-meson-env-macos-$(build_arch).rc \
		&& $$CODESIGN -f -s "$$IOS_CERTID" --entitlements frida-core/server/frida-server.xcent build/$*/bin/frida-server \
		## Install Name
		&& $$INSTALL_NAME_TOOL -id @rpath/FridaGadget.framework/FridaGadget build/$*/lib/frida-gadget.dylib \
		&& $$CODESIGN -f -s "$$IOS_CERTID" build/$*/lib/frida-gadget.dylib
	@touch $@
复制代码

从新编译

Frida 的编译相对比较简单,参考 官方文档 便可,这里说几个编译过程当中遇到的坑。

  1. 建议使用 Node 8.0 及以上的环境;
  2. 先执行 make core-ios 再执行 make gadget-ios
  3. Build 过程须要建立一个证书来签名,具体方式参考 官方文档
  4. 在 Node 高版本执行失败时,先切换到低版本(例如 Node 5.9.1),随后可能会在 npm install 过程当中遇到错误,再切换到高版本便可;

随后再按照相同的步骤,将 FridaGadget 封装成 Framework,再打包成 Pod 库,再结合环境控制,便可完美的将 FridaGadget 用于正向开发过程当中,环境控制也强有力的保证了 FridaGadget 不会被打包到正式环境。

相关文章
相关标签/搜索