-
使用tweak创建工程
➜ tweak /opt/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): MyFirstRePoject Package Name [com.yourcompany.myfirstrepoject]: com.iosre.myfirstrepoject Author/Maintainer Name [chenzhou]: chuck [iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.apple.springboard [iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: SpringBoard Instantiating iphone/tweak in myfirstrepoject/... Done.
- Choose a Template (required): 选择tweak工程
- Project Name (required): 工程名
- Package Name [com.yourcompany.myfirstrepoject]: deb包的名字
- Author/Maintainer Name [chenzhou]: 作者
- [iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: tweak作用对象的bundle indentifier
- [iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: tweak安装完成后需要重启的应用
-
tweak 工程目录结构介绍
- Makefile
默认文件信息: // 工程包含的通用头文件 include $(THEOS)/makefiles/common.mk // 创建工程时指定的“Project Name,指定好之后一般不要再更改 TWEAK_NAME = MyFirstReProject // tweak包含的源文件,指定多个文件时用空格隔开 MyFirstReProject_FILES = Tweak.xm // tweak工程的头文件,一般有application.mk、tweak.mk和tool.mk几类 include $(THEOS_MAKE_PATH)/tweak.mk // 指定tweak安装之后,需要做的事情,这里是杀掉SpringBoard进程 after-install:: install.exec "killall -9 SpringBoard" 补充: // 编译debug或者release DEBUG = 0 // 越狱iPhone的ip地址 THEOS_DEVICE_IP = 192.168.1.113 // 指定支持的处理器架构 ARCHS = armv7 arm64 // 指定需要的SDK版本iphone:Base SDK:Deployment Target TARGET = iphone:latest:8.0 //最新的SDK,程序发布在iOS8.0以上 // 导入框架,多个框架时用空格隔开 MyFirstReProject_FRAMEWORKS = UIKit MyFirstReProject_PRIVATE_FRAMEWORKS = AppSupport // 链接libsqlite3.0.dylib、libz.dylib和dylib1.o MyFirstReProject_LDFLAGS = -lz –lsqlite3.0 –dylib1.o // make clean clean:: rm -rf ./packages/*
-
tweak文件
- xm中的x代表这个文件支持logos语法,如果后缀名单独是一个x说明源文件支持logos和c语法;如果后缀名是xm,说明源文件支持logos和c/c++语法。
- %hook指定需要hook的class,必须以%end结尾
- %log该指令在%hook内部是使用,将函数名的类名、参数等信息写入syslog,Cydia内搜索安装syslog
- %orig该指令在%hook内部使用,执行被钩住(hook)的函数的原始代码。
- tewak工程创建的代码
/* 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 */
- 修改tewak工程的xm文件之后的代码,hook Springboard当按下home键触发的函数,并打印信息
%hook SpringBoard - (void)_menuButtonDown:(id)arg1 { NSLog(@"x=%d, y=%d", 10, 20); %log((NSString *)@"iOSRE", (NSString *)@"Debug"); %orig; // call the original _menuButtonDown: } %end
-
control
- control文件记录了deb包管理系统所需的基本信息,会被打包deb包里。
-
MyFirstRePoject.plist
- 做用对象的文件
➜ myfirstrepoject plutil -p MyFirstRePoject.plist { "Filter" => { "Bundles" => [ 0 => "com.apple.springboard" ] } }
-
编译工程
# Makefile文件直接make执行 ➜ myfirstrepoject make # 错误 ➜ myfirstrepoject make Makefile:1: /makefiles/common.mk: No such file or directory Makefile:6: /tweak.mk: No such file or directory make: *** No rule to make target `/tweak.mk'. Stop. # 修改export THEOS=/opt/theos未设置 export THEOS=/opt/theos # 重启shell在执行make # 最终生成的文件在./.theos/obj/debug/*.dylib
-
打包工程
➜ myfirstrepoject make package > Making all for tweak MyFirstRePoject… make[2]: Nothing to be done for `internal-library-compile'. > Making stage for tweak MyFirstRePoject… Can't locate IO/Compress/Lzma.pm in @INC (you may need to install the IO::Compress::Lzma module) (@INC contains: /usr/local/Cellar/perl/5.26.2/lib/perl5/site_perl/5.26.2/darwin-thread-multi-2level /usr/local/Cellar/perl/5.26.2/lib/perl5/site_perl/5.26.2 /usr/local/Cellar/perl/5.26.2/lib/perl5/5.26.2/darwin-thread-multi-2level /usr/local/Cellar/perl/5.26.2/lib/perl5/5.26.2 /usr/local/lib/perl5/site_perl/5.26.2/darwin-thread-multi-2level /usr/local/lib/perl5/site_perl/5.26.2) at /opt/theos/bin/dm.pl line 12. BEGIN failed--compilation aborted at /opt/theos/bin/dm.pl line 12. make: *** [internal-package] Error 2 # 打印错误详细信息 ➜ myfirstrepoject make package messages=yes # 清楚make记录 ➜ myfirstrepoject make clean # 错误缺少IO::Compress::Lzma文件 # 通过cpan来安装就可以了 sudo cpan IO::Compress::Lzma # 然后在执行make命令 ➜ myfirstrepoject make clean ==> Cleaning… ➜ myfirstrepoject make package > Making all for tweak MyFirstRePoject… ==> Preprocessing Tweak.xm… ==> Compiling Tweak.xm (armv7)… ==> Linking tweak MyFirstRePoject (armv7)… clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of iOS 7 [-Wdeprecated] ==> Generating debug symbols for MyFirstRePoject (armv7)… ==> Preprocessing Tweak.xm… ==> Compiling Tweak.xm (arm64)… ==> Linking tweak MyFirstRePoject (arm64)… clang: warning: libstdc++ is deprecated; move to libc++ with a minimum deployment target of iOS 7 [-Wdeprecated] ==> Generating debug symbols for MyFirstRePoject (arm64)… ==> Merging tweak MyFirstRePoject… ==> Signing MyFirstRePoject… > Making stage for tweak MyFirstRePoject… dm.pl: building package `com.iosre.myfirstrepoject:iphoneos-arm' in `./packages/com.iosre.myfirstrepoject_0.0.1-6+debug_iphoneos-arm.deb' # ./packages/com.iosre.myfirstrepoject_0.0.1-6+debug_iphoneos-arm.deb 即为打出的deb包。
-
查看包(使用dpkg来查看deb包的信息)
➜ packages dpkg -I com.iosre.myfirstrepoject_0.0.1-6+debug_iphoneos-arm.deb new Debian package, version 2.0. size 3682 bytes: control archive=311 bytes. 247 bytes, 10 lines control Package: com.iosre.myfirstrepoject Name: MyFirstRePoject Depends: mobilesubstrate Architecture: iphoneos-arm Description: An awesome MobileSubstrate tweak! Maintainer: chuck Author: chuck Section: Tweaks Version: 0.0.1-6+debug Installed-Size: 120
-
把deb包拷贝到iPhone上去
➜ packages scp com.iosre.myfirstrepoject_0.0.1-6+debug_iphoneos-arm.deb root@192.168.6.107:/tmp
-
在iPhone里使用dpkg安装包
# 如果没有dpkg使用 apt-get install dpkg 或者直接在Cydia里搜索安装 iPhone:/tmp root# apt-get install dpkg # 使用 dpkg -i deb包 进行安装 iPhone:/tmp root# dpkg -i com.iosre.myfirstrepoject_0.0.1-6+debug_iphoneos-arm.deb Selecting previously unselected package com.iosre.myfirstrepoject. (Reading database ... 4614 files and directories currently installed.) Preparing to unpack com.iosre.myfirstrepoject_0.0.1-6+debug_iphoneos-arm.deb ... Unpacking com.iosre.myfirstrepoject (0.0.1-6+debug) ... Setting up com.iosre.myfirstrepoject (0.0.1-6+debug) ...
-
重启SpringBoard
# Springboard是系统应用,杀死进程后会自动重启 iPhone:/tmp root# killall -9 SpringBoard
-
查看日志
# 在Cydia搜索“syslogd to/var/log/syslog”并安装 # 打印最近的10条日志,并实时更新 iPhone:~ root# tail -f /var/log/syslog # 错误 tail : command not found # 在Cydia搜索“Core Utilities”并安装 # 看了我的Cydia里装了Core utilties还是不能使用的话重新装一遍就可以使用了 # 打印出了我第一个tewak工程的输出 Apr 25 10:44:24 iPhone SpringBoard[91]: [MyFirstRePoject] Tweak.xm:5 DEBUG: -[<SpringBoard: 0x150022800> _menuButtonDown:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Timestamp: 8674105041 Total Latency: 21490 us SenderID: 0x0000000100000196 BuiltIn: 1 AttributeDataLength: 36 AttributeData: 01 00 00 00 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ValueType: Absolute EventType: Keyboard UsagePage: 12 Usage: 64 Down: 1 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ]: iOSRE, Debug # 或者直接打印SpringBoard的日志 iPhone:/tmp root# tail -f /var/log/syslog | grep SpringBoard Apr 25 10:54:15 iPhone SpringBoard[91]: x=10, y=20 Apr 25 10:54:15 iPhone SpringBoard[91]: [MyFirstRePoject] Tweak.xm:5 DEBUG: -[<SpringBoard: 0x150022800> _menuButtonDown:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Apr 25 10:54:15 iPhone SpringBoard[91]: [MPUSystemMediaControls] Enabling lock screen media controls updates for screen turning on. Apr 25 10:54:15 iPhone SpringBoard[91]: [MPUSystemMediaControls] Updating supported commands for now playing application. Apr 25 10:54:16 iPhone SpringBoard[91]: -[UABestAppSuggestionManager notifyBestAppChanged:type:options:bundleIdentifier:activityType:dynamicIdentifier:when:confidence:deviceName:deviceIdentifier:deviceType:] (null) UASuggestedActionType=0 (null)/(null) opts=(null) when=2018-04-25 02:54:16 +0000 confidence=1 from=(null)/(null) (UABestAppSuggestionManager.m #319) Apr 25 10:54:19 iPhone SpringBoard[91]: x=10, y=20 Apr 25 10:54:19 iPhone SpringBoard[91]: [MyFirstRePoject] Tweak.xm:5 DEBUG: -[<SpringBoard: 0x150022800> _menuButtonDown:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Apr 25 10:54:22 iPhone SpringBoard[91]: x=10, y=20 Apr 25 10:54:22 iPhone SpringBoard[91]: [MyFirstRePoject] Tweak.xm:5 DEBUG: -[<SpringBoard: 0x150022800> _menuButtonDown:+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
修改Makefile文件
include $(THEOS)/makefiles/common.mk # 发布release版本 DEBUG = 1 # 安装的ip THEOS_DEVICE_IP = 192.168.6.107 # 支持的架构 ARCHS = armv7 arm64 # 支持的iPhone版本 TARGET =iphone:latest:8.0 TWEAK_NAME = MyFirstRePoject MyFirstRePoject_FILES = Tweak.xm include $(THEOS_MAKE_PATH)/tweak.mk after-install:: install.exec "killall -9 SpringBoard" # 清楚 clean:: rm -rf ./package/* tip: # 错误 需要把新添加的信息放到include $(THEOS)/makefiles/common.mk前面,第一行就可以了 ➜ myfirstrepoject make install ==> 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. make: *** [internal-install] Error 1 # 然后执行直接安装到手机上 make clean make make package make install
-
Deb包介绍 官网
- deb包本质是一个压缩包文件,里面包含一些特定的目录和文件。安装过程就是dpkg程序按照指定的规则去拷贝和执行脚本。
# 安装deb包 dpkg -i filename # 查看目录结构 ➜ packages dpkg -c com.iosre.myfirstrepoject_0.0.1-10+debug_iphoneos-arm.deb drwxr-xr-x root/wheel 0 2018-04-25 13:45 . drwxr-xr-x root/wheel 0 2018-04-25 13:45 ./Library drwxr-xr-x root/wheel 0 2018-04-25 13:45 ./Library/MobileSubstrate drwxr-xr-x root/wheel 0 2018-04-25 13:45 ./Library/MobileSubstrate/DynamicLibraries -rw-r--r-- root/wheel 57 2018-04-25 13:45 ./Library/MobileSubstrate/DynamicLibraries/MyFirstRePoject.plist -rwxr-xr-x root/wheel 132896 2018-04-25 13:45 ./Library/MobileSubstrate/DynamicLibraries/MyFirstRePoject.dylib
- DEBIAN目录-存放control文件、及安装和卸载时需要执行的文件等
- control文件
➜ DEBIAN cat control # deb包的名字,卸载和查询信息都用这个名字 Package: com.iosre.myfirstrepoject # 工程名 Name: MyFirstRePoject # 依赖包(可以指定多个,用,分割) Depends: mobilesubstrate # 描述软件支持的平台架构 Architecture: iphoneos-arm # deb简介 Description: An awesome MobileSubstrate tweak! # deb包维护人联系方式 Maintainer: chuck # 软件作者 Author: chuck # deb包归属类别 Section: Tweaks # 版本 Version: 0.0.1-10+debug Installed-Size: 136
- 脚本文件(解释器文件 #!/bin/sh)
-
preinst
- 在Deb包文件解包之前,将会运行该脚本。许多“preinst”脚本的任务是停止作用于待升级软件包的服务,直到软件包安装或升级完成。
-
postinst
- 该脚本的主要任务是完成安装包时的配置工作。许多“postinst”脚本负责执行有关命令为新安装或升级的软件重启服务。
-
prerm
- 该脚本负责停止与软件包相关联的daemon服务。它在删除软件包关联文件之前执行。
-
postrm
- 该脚本负责修改软件包链接或文件关联,或删除由它创建的文件。
-
# 创建script文件夹创建打包脚本,在安装和卸载的时候都重启SpringBoard ➜ myfirstrepoject cd script ➜ script ls ➜ script vim preinst ➜ script vim postinst ➜ script vim prerm ➜ script vim postrm ➜ script chmod +x ./* ➜ script ls postinst postrm preinst prerm
postinst #!/bin/sh killall -9 SpringBoard
postrm #!/bin/sh killall -9 SpringBoard
- 编写Makefile
# 把脚本拷贝到DEBIAN目录下,在最后添加 before-package:: cp ./script/postinst ./.theos/_/DEBIAN/ cp ./script/postrm ./.theos/_/DEBIAN/
- 查看
# 查看 ➜ myfirstrepoject cd .theos/_/DEBIAN ➜ DEBIAN ls control postinst postrm # 拷贝到手机上 ➜ packages scp com.iosre.myfirstrepoject_0.0.1-11+debug_iphoneos-arm.deb root@192.168.6.107:/tmp # 在手机上安装deb包的时候就会自动的重启SpringBoard iPhone:/tmp root# dpkg -i com.iosre.myfirstrepoject_0.0.1-11+debug_iphoneos-arm.deb # 查看包的信息 iPhone:/tmp root# dpkg -I com.iosre.myfirstrepoject_0.0.1-11+debug_iphoneos-arm.deb new debian package, version 2.0. size 3722 bytes: control archive=384 bytes. 248 bytes, 10 lines control 34 bytes, 3 lines * postinst #!/bin/sh 34 bytes, 3 lines * postrm #!/bin/sh Package: com.iosre.myfirstrepoject Name: MyFirstRePoject Depends: mobilesubstrate Architecture: iphoneos-arm Description: An awesome MobileSubstrate tweak! Maintainer: chuck Author: chuck Section: Tweaks Version: 0.0.1-11+debug Installed-Size: 136 # 通过包的名称来卸载包 Package: com.iosre.myfirstrepoject iPhone:/tmp root# dpkg -r com.iosre.myfirstrepoject
- Library (/myfirstrepoject/.theos/_/Library)
/myfirstrepoject/.theos/_/Library 会镜像映射到目标设备 iPhone:/tmp root# cd /Library/MobileSubstrate/DynamicLibraries/
- layout
- dpkg打包时会复制当前目录下layout目录下的所有文件和目录,这些文件和目录会镜像到目标设备上(layout相对于设备的根目录)
➜ myfirstrepoject mkdir layout ➜ myfirstrepoject cd layout ➜ layout mkdir -p usr/bin ➜ layout ls usr ➜ layout touch chuck01 ➜ layout cd usr/bin ➜ bin touch chuck02 ➜ bin cd .. ➜ usr cd .. ➜ layout ls chuck01 usr ➜ layout mkdir tmp ➜ layout ls chuck01 tmp usr ➜ layout cd tmp ➜ tmp touch chuck03 ➜ tmp
# 在重新make package就可以看到我们直接创建的目录 ➜ packages dpkg -c com.iosre.myfirstrepoject_0.0.1-12+debug_iphoneos-arm.deb drwxr-xr-x root/whee l 0 2018-04-25 14:48 . -rw-r--r-- root/wheel 0 2018-04-25 14:45 ./chuck01 drwxr-xr-x root/wheel 0 2018-04-25 14:44 ./usr drwxr-xr-x root/wheel 0 2018-04-25 14:45 ./usr/bin -rw-r--r-- root/wheel 0 2018-04-25 14:45 ./usr/bin/chuck02 drwxr-xr-x root/wheel 0 2018-04-25 14:48 ./Library drwxr-xr-x root/wheel 0 2018-04-25 14:48 ./Library/MobileSubstrate drwxr-xr-x root/wheel 0 2018-04-25 14:48 ./Library/MobileSubstrate/DynamicLibraries -rw-r--r-- root/wheel 57 2018-04-25 14:48 ./Library/MobileSubstrate/DynamicLibraries/MyFirstRePoject.plist -rwxr-xr-x root/wheel 132896 2018-04-25 14:48 ./Library/MobileSubstrate/DynamicLibraries/MyFirstRePoject.dylib drwxr-xr-x root/wheel 0 2018-04-25 14:45 ./tmp -rw-r--r-- root/wheel 0 2018-04-25 14:45 ./tmp/chuck03
再 dpkg -r package 的时候这些目录会被删除
deb包用解压工具解压出来的就是打包进去文件和目录
-
常见的Logos语法 维基百科wiki
- block-level
- %hook 制定需要hook的Class,必须以%end结尾。可以被多个%group包含
%hook SBApplicationController - (void)uninstallApplication:(SBApplication *)application { NSLog(@"Hey, we're hooking uninstallApplication:!"); %orig; // Call the original implementation of this method return; } %end
- %group 该指令用于将%hook分组,便于代码管理及按条件初始化分组,必须以%end结尾。一个%group可以包含多个%hook,所有不属于某个自定义group的%hook会被隐式归类到%group_ungrouped中。
%group iOS8 %hook IOS8_SPECIFIC_CLASS // your code here %end // end hook %end // end group ios8 %group iOS9 %hook IOS9_SPECIFIC_CLASS // your code here %end // end hook %end // end group ios9 %ctor { if (kCFCoreFoundationVersionNumber > 1200) { %init(iOS9); } else { %init(iOS8); } }
- %new 通过在方法定义之上添加这个指令,将一个新方法添加到钩子类或子类中。签名是新方法的Objective-C类型编码;如果省略,将生成一个。必须在%hook块内。
// 使用 // %new
// %new(signature)
%hook SBApplicationController
- (void)uninstallApplication:(SBApplication *)application {
NSLog(@"Hey, we're hooking uninstallApplication:!");
%orig; // Call the original implementation of this method
return;
}
%new
- (void)namespaceNewMethod {
NSLog(@"We've added a new method to SpringBoard.");
}
%end
```
* Top level
* %ctor tweak的构造函数,完成初始化工作;如果不显示定义,Theos会自动生成一个%ctor,并在其中调用%init(_ungrouped)。
* %dtor tweak的构造函数,完成收尾。如果不显示定义,Theos会自动生成一个%dtor。
* Function level
* %init 该指令用于初始化某个%group,必须在%hook或%ctor内调用;如果带参数,则初始化指定的group,如果不带参数,则初始化_ungrouped。注: 切记,只有调用了%ini,对应的%group才能起作用!
```
%ctor {
if (kCFCoreFoundationVersionNumber > 1200) %init(iOS9);
else %init(iOS8);
}
```
* %c 该指令的作用等同于objc_getClass或NSClassFromString,即动态获取一个类的定义,在%hook或%ctor内使用 。
```
%hook SpringBoard
- (void)_menuButtonDown:(id)down
{
%orig;
SBScreenShotter *shotter = [%c(SBScreenShotter) sharedInstance];
[shotter saveScreenshot:YES];
}
%end@
```
* %log 该指令在%hook内部使用,将函数的类名、参数等信息写入syslog,可以%log([(),…..])的格式追加其他打印信息。
* %orig 该指令在%hook内部使用,执行被hook的函数的原始代码;也可以用%orig更改原始函数的参数。
-
使用Logos语法,点击home建截屏,%new新添加实例方法和类方法
//练习 @interface SBScreenshotter: NSObject + (id)sharedInstance; - (void)saveScreenshot: (BOOL)arg1; @end @interface SpringBoard + (void)_AutoScreenSave2; - (void)_AutoScreenSave; @end %hook SpringBoard - (void)applicationDidFinishLaunching:(id)application { %orig; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hello,chuck!" message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } %new - (void)_AutoScreenSave { NSLog(@"instance method"); SBScreenShotter *shotter = [%c(SBScreenShotter) sharedInstance]; [shotter saveScreenshot:YES]; } %new + (void)_AutoScreenSave2 { NSLog(@"class method"); SBScreenShotter *shotter = [%c(SBScreenShotter) sharedInstance]; [shotter saveScreenshot:YES]; } - (void)_menuButtonDown:(id)arg1 { // NSLog(@"x=%d, y=%d", 10, 20); // %log((NSString *)@"iOSRE", (NSString *)@"Debug"); // 实例方法调用 [self _AutoScreenSave]; // 类方法调用 [%c(SpringBoard) _AutoScreenSave2]; %log((NSString *)@"iOSRE", (NSString *)@"Debug"); %orig; // call the original _menuButtonDown: } %end