一、介绍及安装
1.简介
Theos是一个越狱开发包。与其它工具相比,它的特点就是简单:下载安装简单、Logos语法简单、编译发布简单。
2.安装
2.1 安装Xcode与Command Line Tools
需要注意的是,如果Mac上有安装多个版本的Xcode,则需要使用xcode-select命令指定一个活动Xcode,即Theos默认使用的Xcode。假设安装了2个Xcode,并将它们分别命名为Xcode1.app、Xcode2.app,若要指定Xcode2.app为活动Xcode,则运行如下命令即可:
sudo xcode-select - s /Applications/Xcode2.app/Contents/Developer
2.2 安装dpkg和ldid
ldid是一款二进制授权管理软件,可以对越狱应用进行SHA1运算生成授权,让软件包可以在iPhone上执行。我们使用Homebrew来安装它们。Homebrew是一款Mac上基于Ruby的包管理器。使用如下命令:
brew install dpkg ldid
如果没有安装Homebrew,那么需要先安装Homebrew,使用如下命令即可(可能需要VPN环境):
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
2.3 安装Theos
将Theos安装在/opt/theos,使用如下命令:
sudo Git clone --recursive https://github.com/theos/theos.git /opt/theos
然后把/opt/theos的权限改成你自己:
sudo chown $(id -u):$(id -g) /opt/theos
最后把theos的执行路径加入到环境变量中,在~/.bash_profile中加上:
export THEOS="/opt/theos"
2.4 测试
在任意目录下(不能是/opt/theos下,否则将创建不成功),输入如下命令创建Theos项目:
/opt/theos/bin/nic.pl NIC 2.0 - New Instance Creator
可以看到这里共有12种模板可供选择,这里我们选择tweak -> 输入Package Name(deb包的名字,类似于bundle identifier)-> tweak的名字 -> 输入”MobileSubstrate Bundel filter“,也就是tweak作用对象的bundle identifier,如:com.apple.springboard -> Done完成。
二、工程文件说明
在上一步安装完成Theos并测试通过后,在指定目录会看到一个创建好的新目录,里面会有四个文件。分别是:Makefile、control、NIC.plist、Tweak.xm,正面将一一对其进行说明。
1.Makefile
Makefile文件指定工程用到的文件、框架、库等信息,将整个过程自动化。其内容说明如下(NIC表示项目名称)
include $(THEOS)/makefiles/common.mk
#固定写法,不要更改。TWEAK_NAME = NIC #Tweak名称跟control文件中的”Name“字段对应,一般不要更改(但我注意到,在创建Tweak的时候并没有提示要输入Project Name就默认生成了NIC)。
NIC_FILES = Tweak.xm
#Tweak包含的源文件(不包括头文件),多个文件间以空格分隔,可以按需要更改。
export ARCHS = armv7 arm64
#默认文件未提供。支持的处理器架构,多个以空格分隔。需要注意的是,采用arm64架构的App不兼容armv7/armv7s架构,必须适配arm64架构的dylib。在绝大多数情况下,这里固定填写”arm7 arm64“就可以了。
TARGET = iphone:Base SDK:Deployment Target
#指定SDK版本。如:iphone:8.1:8.0表示指定彩8.1版本的SDK,且发布对象为iOS8.0及以上版本。也可以把”Base SDK“设置为”latest“,指定以Xcode附带的最新版本SDK编译。
export NIC_FRAMEWORKS = framework name
#默认文件未提供。导入framework。如:NIC_FRAMEWORKS = UIKit CoreAudio
export NIC_PRIVATE_FRAMEWORKS = private framework name
#默认文件未提供。导入private framework。如:NIC_FRAMEWORKS = AppSupport ChatKit。需要注意的是:在导入之前一定要确定导入的private framework确实存在,因为private framework是AppStore开发所不允许使用的,它的内容在每个iOS版本之间可能发生变化。如:BaseBoard框架在iOS8以上存在,在iOS7就没有。这种情况通过弱链接或dlopen()、dlsym()和dlclose()系列函数动态调用private framework来解决。
export NIC_LDFLAGS = -lx
#默认文件未提供。链接Mach-O对象。Theos采用GNU Linker来链接Mack-O对象,包括.dylib、.a和.o。-lx代表链接libx.a或libx.dylib,即给”x“加上”lib“的前缀,以及“.a”或“.dylib”的后缀;如果x是“y.o”的形式,则直接链接y.o,不加任何前缀或后缀。如要链接libsqlite3.0.dylib、libz.dylib和dylib1.o,这样写就行:NIC_LDFLAGS = -lz -lsqlite3.0 -dylib1.o
include $(THEOS_MAKE_PATH)/tweak.mk
#根据不同的Theos工程类型,指定不同的.mk文件。可以按需更改。
after-install::install.exec "killall -9 SpringBoard"
#表示在Tweak安装之后杀掉SpringBoard进程,好让CydiaSubstrate在进程启动时加载对应的dylib。
2.Tweak.xm
用Theos创建tweak工程,默认生成的源文件是Tweak.xm。“xm”中的“x”代表这个文件支持Logos语法,如果后缀名是单独一个“x”,说明源文件支持Logos和C语法;如果后缀名是“xm”,说明源文件支持Logos和C/C++语法。(Logos语法在这里不赘述)
3.control
control文件记录了deb包管理系统所需的基本信息,会被打包进deb包里。基本字段说明:
Package:用于描述这个deb包的名字,采用的命名方式同bundle identifier类似,均为反向DNS格式。可以按需更改。Name:用于描述这个工程的名字,可以按需更改。
Depends:用于描述这个deb包的“依赖”。“依赖”指的是这个程序运行的基本条件,可以填写固件版本或其它程序,如果当前iOS不满足“依赖”中定义的条件,则此tweak无法正常运行。如:Depends:mobilesubstrate,firmware(>=8.0)表示当前iOS版本必须在8.0以上,且必须安装CydiaSubstrate才能正常运行这个tweak,可以按需更改。
Version:用于描述这个deb包的版本号,可以按需更改。
Architecture:用于描述deb包安装的目标设备架构,不要更改。
Description:是deb包的简介,可以更改。
Maintainter:用于描述deb包的维护人,可以按需更改。
Author:用于描述tweak的作者,可以按需更改。
Section:用于描述deb包所属的程序类别,不要更改。
4.NIC.plist
该plist文件的作用和App中的Info.plist类似,它记录了一些配置信息,描述了tweak的作用范围。通过Xcode打开该文件,我们可以看到它的最外层是一个Dictionary,只有一个名为“Filter”的键。Filter下是一系列Array,可以分为三类:
Bundle:指定若干bundle为tweak的作用对象。如:com.apple.springboard
Classes:指定若干class为tweak的作用对象。如:NSString
Executables:指定若干可执行文件为tweak的作用对象。如:callservicesd
这三类Array可以混合使用,但当Filter下有不同类的Array时,需要添加一个“Mode: Any”键值对。当Filter下的Array只有一类时,不需要添加。
三、编译、打包、安装
1.编译
Theos采用“make”命令来编译Theos工程。在Theos目录下运行make命令。(需要注意:xm文件语法不要有错误,支持c,oc语法)执行“make”命令后会在工程目录下生成/obj/debug文件(没错误的话),但里面都是空的。(这里与其它资料上不一样)这里先不用管这些,继续执行后面的命令。
2.打包
使用“make package”命令来打包,这里其它是先执行make命令再执行dpkg-deb命令。执行完成后会在工程目录下生成/packages/xxx.deb文件。该文件就是可以直接安装在iOS上的安装包。
3.安装
3.1 图形界面安装
即先将打包好的deb文件通过iFunBox导入手机目录,然后在iPhone手机上通过iFile工具安装。(安装成功后可能需要重启手机,视tweak功能而定,未亲测)。
3.2 命令行安装
3.2.1 安装OpenSSH
在越狱手机上OpenSSH工具,通过命令行安装deb需要用到其中的scp功能。
3.2.2 添加配置行
在Makefile的最上一行(也就是第一行,也必须是第一行,不然会出错)加上手机的IP地址,如:
export THEOS_DEVICE_IP = 10.200.201.22 (手机本地IP)
3.2.3 执行安装命令
在确保Mac与iPhone在同一局域网的前提下,执行以下命令:
make package install
在整个安装过程中会输入两次手机的root密码,如果想在安装过程中实现一次性安装,即不需要输入密码的话,需要设置iOS的authorized_keys。步骤如下:
3.2.3.1 删除Host数据
删除Mac上”/Users/hjs<本机用户名>/.ssh/known_hosts“文件中iOSIP对应的条目。如果你的iPhone's IP是10.112.12.30,那么在该文件对应的数据则是:10.112.12.30=xxxxx<很长一串密钥>,将这一段数据删掉。
3.2.3.2 生成authorized_keys
在Mac终端执行如下命令:
ssh-keygen -t rsa <遇到提示直接回车>
...
cp /Users/hjs<本机用户名>/.ssh/id_rsa.pub ~/authorized_keys
3.2.3.3 配置iOS
在Mac终端通过ssh命令以root用户连接上iPhone(如:ssh root@10.112.12.30),连接上之后执行如下命令:
ssh-keygen <遇到提示直接回车>
...
logout <退出ssh>
scp ~/authorized_keys root@10.112.12.30<手机IP>:/var/root/.ssh
3.2.3.4 清理
在上一步骤中配置好后,再次执行make package install之前需要清理之前生成的文件,否则将安装不成功。执行以下命令达到清理的目的:
make clean
rm -rf ./obj ./packages
再次执行安装命令将不会再要求输入密码,达到一键安装的目的。
4.可能出现的错误
clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of iOS 7
检查.xm文件中是否有语法错误,注释位置是否正确,也有可能是某个框架未导入。
dpkg-deb: error: obsolete compression type 'lzma'; use xz instead
修改opt/theos/makefiles/package/deb.mk中第六行:THEOSPLATFORM_DPKG_DEB_COMPRESSION ?= lzma 将最后的lzma 改成 xz,这样改固然暂时不会报错了,但后面可能还是会出错,所以这里建议直接将lzma 改成 gzip。
Error: /Applications/Xcode.app/Contents/Developer/usr/bin/make install requires that you set THEOS_DEVICE_IP in your environment.
出现这个错误说明没有把3.2中的 export THEOS_DEVICE_IP = 10.200.201.22 (手机本地IP)写在第一行所致。
dpkg-deb (subprocess): unable to execute decompressing archive member (xz): No such file or directorydpkg-deb (subprocess): subprocess decompressing archive member returned error exit status 2dpkg-deb: error: subprocessreturned error exit status 2
dpkg: error processing archive /tmp/_theos_install.deb (--install):
subprocess dpkg-deb --fsys-tarfile returned error exit status 2
Errors were encountered while processing:
/tmp/_theos_install.deb
make: *** [internal-install] Error 1
如果在出现上面第2个错误时是将lzma->xz的话,后面可能会出现此错误,解决方法是将lzma->gzip即可。
/* 本文参考《iOS应用逆向工程》一书所进行的总结,所有步骤也是经过亲自验证,可能与书中有微小的出入 */