前言
OC 中对某个对象的方法的调用并不像 C++ 一样直接取得方法的实现的偏移值来调用,所以 C++ 方法与实现的关系在编译时就可确定。而 OC 中方法和实现的关系是在运行时决定的。在调用某个对象的方法时,实际上是调用了 obj_msgsend 向对象发送一个名称为方法名的消息,而我们可以替换这个响应这个消息的实现内容。OC 中比较有力的动态特性 Method Swizzing 就是建立在这个基础之上。
MobieSubstrate
MobieSubstrate 是现有越狱插件运行的基础;它由3部分组成:
- MobileHooker
它的作用是替换函数实现
- MobileLoader
它的作用是加载第三方动态链接库,也就是我们开发的 tweak。在 iOS 启动时,由 launchd 将 MobileLoader 载入内存,然后 MobileLoader 会 dlopen 所有 /Library/MobileSubstrate/DynamicLibraries/ 目录下的动态链接库。
另外我们需要为编写的 tweak 同时编写一个跟 tweak 同名的 plist 文件,指定 tweak 的作用范围。
这个我们要从二进制文件的结构说起,从下面的图来看,Mach-O文件的数据主体可分为三大部分,分别是头部(Header)、加载命令(Load commands)、和最终的数据(Data)。mobileloader会在目标程序启动时,会根据指定的规则检查指定目录是否存在第三方库,如果有,则会通过修改二进制的loadCommands,来把自己注入进所有的app当中,然后加载第三方库。
Safe Mode
bug 是不可避免的,如果寄生的 tweak 出现了 bug 导致 APP 崩溃,那么我们就需要一种机制,将 tweak 禁用掉,跟我们一个机会来 debug。
而 Safe Mode 会捕获 SIGTRAP, SIGABRT, SIGILL, SIGBUS, SIGSEGV, SIGSYS 这6种信号,然后进入安全模式。
在 iOS9.3 越狱时 MobieSubstrate 已经自动安装上了。目前在 Cydia 中也更名为了 Cydia Substrate。
otool
使用 otool 来输出 app 的 load commands,查看 cryptid 这个标志位来判断 app 是否被加密了,1代表加密了,0代表被解密了。otool 是 Xcode tool chain 的一部分,所以并不需要额外安装:
otool -l WeChat.decrypted | grep -B 2 crypt
结果
devzkndeMacBook-Pro:WeChat6.5.20 devzkn$ otool -l WeChat.decrypted | grep -B 2 crypt
WeChat.decrypted (architecture armv7):
--
cmd LC_ENCRYPTION_INFO
cmdsize 20
cryptoff 16384
cryptsize 49430528
cryptid 0
--
dataoff 57651328
datasize 742608
WeChat.decrypted (architecture arm64):
--
cmd LC_ENCRYPTION_INFO_64
cmdsize 24
cryptoff 16384
cryptsize 52854784
cryptid 1
devzkndeMacBook-Pro:WeChat6.5.20 devzkn$
Tweak.xm
Theos 创建工程之后,默认生成的模板源文件是 Tweak.xm,其中有一些预处理命令值得注意:
- %hook: 指定需要 hook 的 class
- %log: 这个指令在 %hook 内部使用,可以将 log 的内容写入 syslog(/var/log/syslog)。
这种是将 log 写入文件的方法。在 iOS9.3 这个文件没有自动生成,如果需要以这种方式查看 log,则需要配置一下,配置方法可以参考 wiki 中的 1.3 内容。而我使用的是 1.1 的方法,利用 socat 这个命令行工具,可以在 cydia 中安装,按照 wiki 的方法实时查看 log
- %orig: 在 %hook 内部使用,执行被 hook 的函数的原始代码。还可以利用它以 C++ 函数的调用方式改变原始函数传入的参数
- %group: 用于将 %hook 分组,与 %init 配合使用,在按条件初始化 hook 代码时非常有用
- %ctor: 用于系统自动初始化默认的未分组 hook 代码
- %new: %hook内部使用,用于给现有的 class 添加新的方法
- %c: %hook内部使用,动态获取一个类的定义
注意点:
另外值得一提,如果需要导入 private framework 的话可以使用 XXX_PRIVATE_FRAMEWORK,但是 iOS SDK 9.3 已经去除了 private frameworks,最后具有 private frameworks 的 sdk 版本是 9.2
打包使用的 make package
打包使用的 make package 命令来自 Theos 本身,其实就是先 make 然后再 dpkg-deb
make package install 命令完成编译打包安装一条龙服务
Theos基本的配置文件
Makefile : 该文件指定工程用到的文件,框架和库等信息. 将这个过程自动化.
xxx.plist : 与APP中的 Info.plist类似, 记录一些配置信息, 描述 tweak的作用范围.
control ,记录了 deb包管理系统所需的基本信息, 会被打包到 deb 包中.(包括版本号)
Tweak.xm : 默认的源文件, x表示支持Logos语法,m表示支持OC语法.
logos小结
%hook : 指定要hook的Class, 必须以%end结尾 .
%log : 要在%hook内使用, 表示打印信息到 syslog , 可以以 %log([(<type>)<expr>,...]) 格式追加打印信息.
%orig : 在%hook 内使用,表示执行被勾住的函数的原始代码.
%group ,组, 用来组合%hook ,必须配合%init使用才能生效组中的替换方法. 如 %group xxx ... %end ,要以end结尾,没有显示声明的 hook都被放在了_ungrouped中.
%init , 用来初始化某个group , 必须放在 %hook,参数为 group 名, 如 %init(_ungrouped).
%subclass : 创建一个新的类, 但是不支持属性, 只能通过关联对象来实现。
%property : 创建一个属性, 可以放在上面的subclass中,写法与 @property相同, 但是实现是用的关联对象.
%ctor , 初始化钩子, 如果不显式定义, 则默认实现 :
%ctor{
%init;
}
%new , 给现有的类添加方法,与 class_addMethod相同. 必须放在%hook中, 即没有声明%new的都视为替换方法, 声明了new才视为新增方法.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。