编写HOOK插件
创建工程
1 2 3 4 5 6 7 8
| 1. 终端输入nic.pl 2. Choose a Template (required): 10 3. Project Name (required): 工程名 4. Package Name [com.yourcompany.tututest]: 包名:com.xxx.xxx 5. Author/Maintainer Name [lk]: 作者 6. [iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: 要Hook的包名 7. [iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: 回车默认
|
工程文件简介
创建好的工程下共有4个文件
Makefile
指定工程用到的文件,框架,库等信息,将整个过程自动化
1 2 3 4 5 6 7 8 9 10
| INSTALL_TARGET_PROCESSES = SpringBoard
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = demo001
demo001_FILES = Tweak.x demo001_CFLAGS = -fobjc-arc
include $(THEOS_MAKE_PATH)/tweak.mk
|
- INSTALL_TARGET_PROCESSES = SpringBoard 目标安装的项目
- include $(THEOS)/makefiles/common.mk 固定写法
- TWEAK_NAME = demo001 tweak的名称
- demo001_FILES = Tweak.x tweak源文件,多个文件以空格分隔
- include $(THEOS_MAKE_PATH)/tweak.mk 通过include命令指定不同的.mk文件
除了上面的信息格式,我们还可以添加以下信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 我们如何通过进行指定SDK? TARGET = iPhone:latest:8.0
我们如何导入framework? demo001_FRAMWORKS = UIKit
我们如何指定处理器架构 ARCHS = armv7 arm64
我么如何链接Mach-O对象 demo001_LDFLAGS = -lx 注意 -lx 代表链接libx.a或libx.dylib,即给x加上lib的前缀,以及.a或.dylib的后缀,可以根据自己的项目进行调整
|
Tweak.x
xm 中的x代表这个文件支持Logos语法
x 如果后缀名是单独的x,说明源文件支持Logos和C语法;
xm 如果后缀名是xm,说明源文件支持Logos和C/C++语法.
.xi 将首先作为objective-c进行预处理,然后Logos将处理结果,然后将进行编译。
.xmi 将首先作为objective-c ++进行预处理,然后Logos将处理结果,然后将进行编译。
demo001.plist
用于指定需要注入的目标文件的Bundle ID
control
指定deb包的一些信息,包括名字,描述,版本号等
编写HOOK代码
编辑tweak.x
1 2 3 4 5 6 7 8 9 10
|
%hook ViewController
- (void)test{
NSLog(@"🍺🍺🍺HOOK🍺🍺🍺"); }
%end
|
设置环境变量
1 2
| export THEOS_DEVICE_IP = localhost export THEOS_DEVICE_PORT = 2222
|
编译安装
使用iproxy转发手机22端口到本地2222
终端输入 make;make package install
1 2
| make make package install
|
Logos语法
1
| http://iphonedevwiki.net/index.php/Logos
|
Logos语法 |
功能解释 |
事例 |
%hook |
需要hook哪个类 |
%hook Classname |
%end |
代码块结束标记 |
%end |
%group |
分组 |
%group Groupname |
%new |
添加新方法 |
%new(signature) |
%ctor |
构造函数 |
%ctor { … } |
%dtor |
析构函数 |
%dtor { … } |
%log |
输出打印 |
%log; %log([(), …]); |
%orig |
保持原有方法 |
%orig;%orig(arg1, …); |
%c |
动态获取类 |
%c([+/-]Class); |
1. %hook %end
指定需要hook的class,必须以%end结尾。
1 2 3 4 5 6 7 8
| %hook SpringBorad - (void)_menuButtonDown:(id)down { NSLog(@"111111"); %orig; // 调用原始的_menuButtonDown函数 } %end
|
2.%group
该指令用于将%hook分组,便于代码管理及按条件初始化分组,必须以%end结尾。
一个%group可以包含多个%hook,所有不属于某个自定义group的%hook会被隐式归类到%group_ungrouped中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| %group iOS8 %hook IOS8_SPECIFIC_CLASS
%end // end hook %end // end group ios8
%group iOS9 %hook IOS9_SPECIFIC_CLASS
%end // end hook %end // end group ios9
%ctor { if (kCFCoreFoundationVersionNumber > 1200) { %init(iOS9); } else { %init(iOS8); } }
|
3.%new
在%hook内部使用,给一个现有class添加新函数,功能与class_addMethod相同.
注:
Objective-C的category与class_addMethod的区别:
前者是静态的而后者是动态的。使用%new添加,而不需要向.h文件中添加函数声明,如果使用category,可能与遇到这样那样的错误.
1 2 3 4 5 6 7
| %hook SpringBoard %new - (void)addNewMethod { NSLog(@"动态添加一个方法到SpringBoard"); } %end
|
4.%ctor
tweak的constructor,完成初始化工作;如果不显示定义,Theos会自动生成一个%ctor,并在其中调用%init(_ungrouped)。
%ctor一般可以用来初始化%group,以及进行MSHookFunction等操作,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #ifndef KCFCoreFoundationVersionNumber_iOS_8_0 #define KCFCoreFoundationVersionNumber_iOS_8_0 1140.10 #endif
%ctor { %init;
if (KCFCoreFoundationVersionNumber >= KCFCoreFoundationVersionNumber_iOS_7_0 && KCFCoreFoundationVersionNumber > KCFCoreFoundationVersionNumber_iOS_8_0) %init(iOS7Hook); if (KCFCoreFoundationVersionNumber >= KCFCoreFoundationVersionNumber_iOS_8_0) %init(iOS8Hook); MSHookFunction((void *)&AudioServicesPlaySystemSound,(void *)&replaced_AudioServerPlaySystemSound,(void **)&orginal_AudioServicesPlaySystemSound); }
|
5.%dtor
Generate an anonymous deconstructor (of default priority).
6.%log
该指令在%hook内部使用,将函数的类名、参数等信息写入syslog,可以%log([(),…..])的格式追加其他打印信息。
1 2 3 4 5 6 7
| %hook SpringBorad - (void)_menuButtonDown:(id)down { %log((NSString *)@"iosre",(NSString *)@"Debug"); %orig; // 调用原始的_menuButtonDown方法 } %end
|
7.%orig
该指令在%hook内部使用,执行被hook的函数的原始代码;也可以用%orig更改原始函数的参数。
1 2 3 4 5 6
| %hook SpringBorad - (void)setCustomSubtitleText:(id)arg1 withColor: (id)arg2 { %orig(@"change arg2",arg2);// 将arg2的参数修 改为"change arg2" } %end
|
8.%init
该指令用于初始化某个%group,必须在%hook或%ctor内调用;如果带参数,则初始化指定的group,如果不带参数,则初始化_ungrouped.
注: 切记,只有调用了%init,对应的%group才能起作用!
9.%c
该指令的作用等同于objc_getClass或NSClassFromString,即动态获取一个类的定义,在%hook或%ctor内使用 。
调用ViewController中的Method方法
1
| [[[%c(ViewController) alloc ] init]Method];
|
日志打印
hook demo方法并添加打印入参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #import "ViewController.h"
@interface ViewController () - (IBAction)compute;
@end
@implementation ViewController
- (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)compute { [self demo:@"66"]; } - (void)demo:(NSString *)str{ NSString *res = [str stringByAppendingString:@"🐂🐂🐂"]; NSLog(res); } @end
|
logify.pl生成.xm文件
1 2
| logify.pl ViewController.h >Tweak.x
|
我们之关系程序中自己写的方法
1 2 3 4 5 6 7 8
|
%hook ViewController - (void)demo:(id)arg1 { %log; %orig; } %end
|
将生成的Tweak.x文件替换theos生成的Tweak.x文件后编译安装即可
查看打印日志