前言
iOS逆向小知识:将功能独立的tweak 合并到同一个deb 包
开始介绍Theos之前,先来回顾下Logos语法
Logos作为Theos开发组件的一部分,通过一组特殊的预处理指令,可以让编写函数钩子(hook)代码变得非常简单和清晰,Logos是随着Theos发布的
- %hook 指定需要hook的类名,以%end结尾
- %log 用来打印log的,将信息输入到syslog中,如%log((NSString *)@"ZeluLi")
- %orig 执行被hook函数的原始代码,类似于super.method功能
- %group 该指令用于%hook的分组,%group后边跟的是组名,%group也是必须以%end结尾,其中可以包含多个%hook
- %init 该指令用来初始化某个%group,一个group只有被初始化后才可生效,init必须在hook中进行执行。
- %ctor tweak的构造器,用来初始化,如果不显式定义,Theos就会自动生成一个%ctor,并在其中调用%init(_ungrouped). 如:%ctor { %init(_ungrouped)}
- %new 该指令用来给现有的class添加一个新的函数。与Runtime中的class_addMethod相同。
- %c 该指令用来获取一个类的名称,相当于
objc_getClass
。
I 工程目录下文件介绍
新建工程的命令:$THEOS/bin/nic.pl
devzkndeMacBook-Pro:~ devzkn$ $THEOS/bin/nic.pl NIC 2.0 - New Instance Creator ------------------------------ [1.] iphone/activator_event [2.] iphone/application_modern [3.] iphone/cydget [4.] iphone/flipswitch_switch [5.] iphone/framework [6.] iphone/ios7_notification_center_widget [7.] iphone/library [8.] iphone/notification_center_widget [9.] iphone/preference_bundle_modern [10.] iphone/tool [11.] iphone/tweak [12.] iphone/xpc_service Choose a Template (required): 11 Project Name (required): testTweakDemo Package Name [com.yourcompany.testtweakdemo]: Author/Maintainer Name [devzkn]: [iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.apple.UIKit [iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: Instantiating iphone/tweak in testtweakdemo/... Done.
参数Package Name :deb包的名字 参数Bundle filter :tweak的目标app的bundle identifier
比如wechat的bundle Id :com.tentcent.xin
iOS 系统的桌面应用的bundle Id:com.apple.springboard tweak注入到所有的app,那么Bundle filter应该填 com.apple.UIKit`
新建一个工程之后,会生成四个文件:control、plist、Makefile、Tweak.xm,这几个文件分别有什么用?
$ ls -lrt total 32 -rw-r--r-- 1 devzkn staff 51 Aug 10 17:07 testTweakDemo.plist -rw-r--r-- 1 devzkn staff 223 Aug 10 17:07 control -rw-r--r-- 1 devzkn staff 1045 Aug 10 17:07 Tweak.xm -rw-r--r-- 1 devzkn staff 189 Aug 10 17:07 Makefile
1.1 control文件
control文件存储项目有关的信息:名称、版本、开发者
Package: com.yourcompany.testtweakdemo Name: testTweakDemo Depends: mobilesubstrate Version: 0.0.1 Architecture: iphoneos-arm Description: An awesome MobileSubstrate tweak! Maintainer: devzkn Author: devzkn Section: Tweaks
1.2 plist文件
devzkndeMacBook-Pro:testtweakdemo devzkn$ more testTweakDemo.plist { Filter = { Bundles = ( "com.apple.UIKit" ); }; }
plist文件的作用:设置目标app的bundle Id,如果tweak要注入多个APP,就在Bundles数组中添加其bundle Id。
1.3 Makefile文件
$ more Makefile include $(THEOS)/makefiles/common.mk TWEAK_NAME = testTweakDemo testTweakDemo_FILES = Tweak.xm include $(THEOS_MAKE_PATH)/tweak.mk after-install:: install.exec "killall -9 SpringBoard" devzkndeMacBook-Pro:testtweakdemo devzkn$
Makefile文件设置需要用到的文件、框架、库。
testTweakDemo_FILES
设置工程需要引用的文件,多个文件之间以空格分隔。格式:工程名FILES = 要编译的文件名
testTweakDemo_FILES = Tweak.xm MyClass1.m MyClass2.m
include $(THEOS)/makefiles/common.mk
很多关键的变量都在common.mk中
- 工程名字_FRAMEWORKS : 设置工程需要引用的第三方库,多个库之间以空格分隔:
工程名字_FRAMEWORKS = UIKit UIFoundation
4.after-install
在tweak安装之后,执行的一些辅助任务,比如杀掉目标进程,好让 CydiaSubstrate在进程重启的过程加载对应的dylib。
1.4 Tweak.xm
用于编写注入的代码,其中的%hook,%orig,%log符合是theos对cydia Substrate提供的函数的宏封装.cydia Substrate提供的方法的介绍可以参考Cydia_Substrate。
MobileHooker is used to replace system functions. This process is known as hooking. There are 2 APIs that one would use:
IMP MSHookMessage(Class class, SEL selector, IMP replacement, const char* prefix); // prefix should be NULL. void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP *result); void MSHookFunction(void* function, void* replacement, void** p_original);
Tweak.xm的文件名后缀x代表的含义
- Tweak.xm的文件名后缀x代表支持Logos语法, 如果只有一个x代表源文件支持Logos和C语法;如果是xm,说明源文件支持Logos和C/C++语法。
2.其中的%hook,%orig,%log等都是Logos语法支持的内容,详细语法说明请参考Logos
$ more Tweak.xm /* How to Hook with Logos Hooks are written with syntax similar to that of an Objective-C @implementation. You don't need to #include <substrate.h>, it will be done automatically, as will the generation of a class list and an automatic constructor. %hook ClassName // Hooking a class method + (id)sharedInstance { return %orig; } // Hooking an instance method with an argument. - (void)messageName:(int)argument { %log; // Write a message about this call, including its class, name and arguments, to the system log. %orig; // Call through to the original function with its original arguments. %orig(nil); // Call through to the original function with a custom argument. // If you use %orig(), you MUST supply all arguments (except for self and _cmd, the automatically generated ones.) } // Hooking an instance method with no arguments. - (id)noArguments { %log; id awesome = %orig; [awesome doSomethingElse]; return awesome; } // Always make sure you clean up after yourself; Not doing so could have grave consequences! %end */
1.5 编译和安装deb
使用命令 make package
编译,其中packages文件夹下保留的是每一次编译成功产生的deb安装包文件。theos编译之后,会生成一个deb包.deb安装到手机上面,有多种方式:
- 通过iFile进行安装
使用iTools等工具将这个deb包拷贝到手机中,利用iFile浏览进行安装。
- 通过SSH进行安装。
需要使用到openssh服务,确保你手机上已经安装了该服务(cydia中搜索安装OpenSSH)。这种安装方式需要在Makefile文件的首行添加你手机设备的IP地址` THEOS_DEVICE_IP = 10.200.201.22 (手机本地IP)
安装的时确保证 iOS 设备和 Mac 在同一局域网的同一网段中,打开终端,先cd到你工程的目录下,然后输入编译安装命令
make package install
`3. 通过cydia 源进行安装
`
1.6 免输密码进行SSH
https://blog.csdn.net/z929118967/article/details/78234772
使用 make package instal
l命令可以一次性完成编译、打包、安装,这个过程中可能需要要你两次输入ssh的root密码(一次是签名打包,一次是安装))
brew安装openssh(brew install openssl)和 ssh-copy-id(brew install ssh-copy-id) 【可选】
- 创建 rsa文件 :
ssh-keygen -t rsa -b 2048
按提示输入存放keygen存放的目录和文件名 - 配置ssh config
# Private 192.168.2.125 Host iPhone HostName 192.168.2.125 User root IdentityFile ~/.ssh/id_rsa_Theos125
- 添加对应的公钥到对应的远程服务器 :
ssh-copy-id
千万不要把私钥泄漏!只是把公钥(*.pub 文件)复制给远程服务器;ssh-copy-id root@<iP Address of your device>
ssh-copy-id 指定认证文件
$ ssh-copy-id -i id_rsa_Theos125 root@192.168.2.131
$ ssh-copy-id root@192.168.2.212 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/devzkn/.ssh/id_rsa_Theos.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@192.168.2.212's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'root@192.168.2.212'" and check to make sure that only the key(s) you wanted were added.
II 常见问题
2.1 问题1:压缩方式不被支持
原因是dpkg有两个不同的版本,最新版本不支持lzma。
$ make package > Making all for tweak testTweakDemo… ==> Preprocessing Tweak.xm… ==> Compiling Tweak.xm (armv7)… ==> Linking tweak testTweakDemo (armv7)… clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of iOS 7 [-Wdeprecated] ==> Preprocessing Tweak.xm… ==> Compiling Tweak.xm (arm64)… ==> Linking tweak testTweakDemo (arm64)… clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of iOS 7 [-Wdeprecated] ==> Merging tweak testTweakDemo… ==> Signing testTweakDemo… > Making stage for tweak testTweakDemo… dpkg-deb: error: obsolete compression type 'lzma'; use xz instead Type dpkg-deb --help for help about manipulating *.deb files; Type dpkg --help for help about installing and deinstalling packages. make: *** [internal-package] Error 2
解决方案:修改lzma 为xz
$ find /opt/theos -type f -name "*.mk" | xargs grep "lzma" /opt/theos/makefiles/package/deb.mk:_THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= lzma
修改/opt/theos/makefiles/package/deb.mk第六行为_THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= xz
- 另外一个办法是直接使用旧版本,命令如下:
Debian 'dpkg' package management program version 1.18.24 (darwin-amd64).
brew switch dpkg 1.18.10 brew link dpkg brew pin dpkg 1.18.10
验证是否修复
$ make package > Making all for tweak testTweakDemo… make[2]: Nothing to be done for `internal-library-compile'. > Making stage for tweak testTweakDemo… dpkg-deb: building package 'com.yourcompany.testtweakdemo' in './packages/com.yourcompany.testtweakdemo_0.0.1-2+debug_iphoneos-arm.deb'.
另如果只修改为XZ的话,届时安装的时候仍会报错:
root@192.168.2.212's password: Selecting previously unselected package com.yourcompany.testtweakdemo. (Reading database ... 1848 files and directories currently installed.) Preparing to unpack /tmp/_theos_install.deb ... Unpacking com.yourcompany.testtweakdemo (0.0.1-8+debug) ... dpkg-deb (subprocess): unable to execute decompressing archive member (xz): No such file or directory dpkg-deb (subprocess): subprocess decompressing archive member returned error exit status 2 dpkg-deb: error: subprocess <decompress> returned 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
如果在出现上面错误时是将lzma->xz的话,后面可能会出现此错误,解决方法是将lzma->gzip即可。
_THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?=gzip
验证是否成功
$ make package install > Making all for tweak testTweakDemo… make[2]: Nothing to be done for `internal-library-compile'. > Making stage for tweak testTweakDemo… dpkg-deb: building package 'com.yourcompany.testtweakdemo' in './packages/com.yourcompany.testtweakdemo_0.0.1-9+debug_iphoneos-arm.deb'. ==> Installing… root@192.168.2.212's password: (Reading database ... 1848 files and directories currently installed.) Preparing to unpack /tmp/_theos_install.deb ... Unpacking com.yourcompany.testtweakdemo (0.0.1-9+debug) ... Setting up com.yourcompany.testtweakdemo (0.0.1-9+debug) ... install.exec "killall -9 SpringBoard" root@192.168.2.212's password:
2.2 问题2:THEOS_DEVICE_IP设置错误
$ make package install > Making all for tweak testTweakDemo… make[2]: Nothing to be done for `internal-library-compile'. > Making stage for tweak testTweakDemo… dpkg-deb: building package 'com.yourcompany.testtweakdemo' in './packages/com.yourcompany.testtweakdemo_0.0.1-3+debug_iphoneos-arm.deb'. ==> Error: /Applications/Xcode.app/Contents/Developer/usr/bin/make install requires that you set THEOS_DEVICE_IP in your environment. ==> Notice: It is also recommended that you have public-key authentication set up for root over SSH, or you will be entering your password a lot.
解决:THEOS_DEVICE_IP = 10.200.201.22 (手机本地IP)
首先得保证你的 iOS 设备和 Mac 在同一局域网的同一网段中。打开终端,输入 ssh root@192.168.xxx.xxx 输入 iOS 设备密码,默认 alpine。
$ ping 192.168.2.212 PING 192.168.2.212 (192.168.2.212): 56 data bytes 64 bytes from 192.168.2.212: icmp_seq=0 ttl=64 time=34.303 ms 64 bytes from 192.168.2.212: icmp_seq=1 ttl=64 time=28.949 ms 64 bytes from 192.168.2.212: icmp_seq=2 ttl=64 time=25.753 ms 64 bytes from 192.168.2.212: icmp_seq=3 ttl=64 time=5.306 ms 64 bytes from 192.168.2.212: icmp_seq=4 ttl=64 time=106.028 ms 64 bytes from 192.168.2.212: icmp_seq=5 ttl=64 time=84.643 ms 64 bytes from 192.168.2.212: icmp_seq=6 ttl=64 time=44.845 ms ^C --- 192.168.2.212 ping statistics --- 7 packets transmitted, 7 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 5.306/47.118/106.028/32.913 ms devzkndeMacBook-Pro:testtweakdemo devzkn$ ssh root@192.168.2.212 The authenticity of host '192.168.2.212 (192.168.2.212)' can't be established. RSA key fingerprint is SHA256:/. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.2.212' (RSA) to the list of known hosts. root@192.168.2.212's password: Permission denied, please try again. root@192.168.2.212's password: iPhone:~ root#