MUHook 1.7.0

MUHook 1.7.0

Magic-Unique 维护。



MUHook 1.7.0

  • 作者
  • 冷秋

MUHook

CI Status Version License Platform

一种在 iOS 设备上(无需越狱)实现的强大、快速、轻量级 Hook 工具。

在非越狱 iOS 平台上的强大的、快速的、轻量级 Hook 工具。

功能

  1. Hook Objective-C 类的方法。Hook 二进制文件中的类的对象方法
  2. 创建一个二进制文件中的类的子类
    • 新增或重写方法
    • 新增实例变量
    • 新增属性
    • 快速方法编码
  3. 创建二进制文件中类的对象
  4. 向二进制文件中的类发消息(工厂方法)
  5. 支持 Xcode 中的代码提示

使用

CocoaPods

pod 'MUHook'

源代码

MUHookfishhook 文件夹拖到您的项目中

导入

#import <MUHook/MUHook.h>

使用 - 快速调用

原代码

@interface MUFastCallClass : NSObject
{
	NSString *_name;
}

- (instancetype)initWithInteger:(NSInteger)integer object:(id)object;

+ (instancetype)instanceWithInteger:(NSInteger)integer object:(id)object;

@end

Hook 代码

//	Alloc an instance without linking.
//	创建一个对象,如果直接 [[Class alloc] init] 调用,编译时候报 link 错误
MUFastCallClass *instance = MUHAllocInitWith(MUFastCallClass, initWithInteger:1 object:[NSObject new]);

//	Get associated object
//	取关联对象
NSObject *obj = MUHAsct(instance, object, strong);

//	Set associated object, supporting: strong/weak/assign/copy
//	设置关联对象,最后一个值支持: strong、weak、assign、copy
MUHAsct(instance, object, strong) = nil;

//	Get ivar value
//	取实例变量
NSString *name = MUHIvar(instance, _name);

//	Set ivar value
//	设置实例变量
MUHIvar(instance, _name) = @"New Name";

更多信息:MUHookDemo/Sample-FastCall

用法 - 勾住方法

原代码

@interface MUHookClass : NSObject

+ (instancetype)instanceWithInt:(NSInteger)integer object:(id)object;

- (void)voidMethodWithObject:(id)object;

- (id)returnValueMethod;

@end

Hook 代码

//	Define a class method named 'factory' to hook +[MUHookClass instanceWithInt:object:]
//	定义一个新的类方法实现体,称之'factory'(该名称只要自己保证类内唯一性即可)
MUHClassImplementation(MUHookClass, factory, MUHookClass *, NSInteger integer, id object) {
    NSLog(@"__hook__ -[MUHookClass instanceWithInt:object:]");
    MUHookClass *instance = MUHOrig(MUHookClass, factory, integer, object);
    return instance;
}

//	Define an instance method named 'voidMethod' to hook
//	-[MUHookClass voidMethodWithObject:]
//	定义一个新的带参数、无返回值的实例方法实现体
MUHInstanceImplementation(MUHookClass, voidMethod, void, id object) {
    NSLog(@"__hook__ -[MUHookClass voidMethodWithObject:]");
    MUHOrig(MUHookClass, voidMethod, object);
}

//	Define an instance method named 'returnMethod' to hook
//	-[MUHookClass returnValueMethod]
//	定义一个新的带返回值,无参数的实例方法体
MUHInstanceImplementation(MUHookClass, returnMethod, id) {
    NSLog(@"__hook__ -[MUHookClass returnValueMethod]");
    return MUHOrig(MUHookClass, returnMethod);
}

//	Execute hook
//	You need call the function MUHInitClass() in MUHMain()
//	执行 Hook
//	请在 MUHMain() 中手动调用该函数以生效以上 hook
void MUHInitClass(MUHookClass) 
  	//	Hook class method:ClassName,MethodName,SEL
  	//	参数列表:类名,自己取得方法名(与上面的方法体相同),SEL
    MUHHookClassMessage(MUHookClass, factory, instanceWithInt:object:);
  	//	Hook instance method:ClassName,MethodName,SEL
  	//	参数列表:类名,自己取得方法名(与上面的方法体相同),SEL
    MUHHookInstanceMessage(MUHookClass, voidMethod, voidMethodWithObject:);
    MUHHookInstanceMessage(MUHookClass, returnMethod, returnValueMethod);
}

//	In the other files(such as: Main.m).
//	Create an entry function to excute all hook.
//	在某个文件中(如 Main.m)
//	创建一个 MUHMain() 函数,来执行以上所有类的 Hook。
void MUHMain() {
	MUHInitClass(MUHookClass);
	MUHInitClass(...);
	...
}

更多信息:MUHookDemo/Sample-Hook

用法 - 创建子类

原始父类代码

@interface MUExtendsSuperClass : NSObject

+ (instancetype)superInstanceWithInt:(NSInteger)integer object:(id)object;

- (void)superVoidMethodWithObject:(id)object;

- (id)superReturnValueMethod;

@end

钩子子类代码

//	Define a class method named 'subInstance' to override
//	+[MUExtendsSuperClass superInstanceWithInt:object:]
MUHClassImplementation(MUExtendsSubClass, subInstance, MUExtendsSubClass *, NSInteger integer, id object) {
    NSLog(@"+[MUExtendsSubClass superInstanceWithInt:(NSInteger)%ld object:(id)%@]", integer, object);
    integer += 1; // Modify arguments
    MUExtendsSubClass *subInstancce = MUHSuper(MUExtendsSubClass, subInstance, integer, object);
    return subInstancce;
}

//	Define an instance method named 'voidMethod' to override
//	+[MUExtendsSuperClass superVoidMethodWithObject:]
MUHInstanceImplementation(MUExtendsSubClass, voidMethod, void, id object) {
    NSLog(@"+[MUExtendsSubClass superVoidMethodWithObject:(id)%@]", object);
    object = [MUExtendsSuperClass new]; // Modify arguments
    MUHSuper(MUExtendsSubClass, voidMethod, object);
}

//	Define an instance method named 'returnMethod' to override
//	+[MUExtendsSuperClass superReturnValueMethod]
MUHInstanceImplementation(MUExtendsSubClass, returnMethod, id) {
    NSLog(@"+[MUExtendsSubClass superReturnValueMethod]");
    id returnValue = MUHSuper(MUExtendsSubClass, returnMethod);
    return returnValue;
}

//	Define a property with setter and getter implementation
//	@property (nonatomic, strong) NSObject *name;
MUHPropertyImplementation(MUExtendsSubClass, strong, NSObject *, name);

void MUHInitClass(MUExtendsSubClass) {
	/**
	 * PS: When you call MUHCreateClass(), it will call createClass() and registerClassPair().
	 * So you can't add any ivar to this class.
	 * Please use association-object if you want to add propertys to the new class.
	 * 
	 * 注意:当你调用 MUHCreateClass(),会自动调用 createClass() 和 registerClassPair() 函数。
	 * 所以你不能自定义添加实例变量到新的子类中
	 * 如果你需要定义属性,请使用关联对象
	 */
  	//	Create a subclass
    MUHCreateClass(MUExtendsSubClass, MUExtendsSuperClass);
    
	/**
	 * PS: If you want to add ivar to the new class, you must use MUHook (> 1.3.0).
	 * And use this code:
	 * Ivar only support: `strong` for object , `assign` for base type.
	 * 
	 * 注意:当你想加入实例变量到新的类中时,你必须使用 1.3.0 以上的 MUHook,并使用一下代码:
	 * 实例变量只支持 `strong` 修饰对象,`assign` 修饰基本数据类型。
	 */
    MUHCreateClass(MUExtendsSubClass, MUExtendsSuperClass) withIvarList {
    	MUHAddIvar(NSString *, _name);
    	MUHAddIvar(NSUInteger, _age);
    	MUHAddIvar(CGRect, _frame);
    };
    
    /*
     *	MUHAddMethod
     * ClassName, ImplementationName, return type, selector, [argument type list]
     * 类名, 实现体名, 返回值类型, selector, [参数类型列表]
     **/
    MUHAddClassMethod(MUExtendsSubClass, subInstance, id, superInstanceWithInt:object:, NSInteger, id);
    MUHAddInstanceMethod(MUExtendsSubClass, voidMethod, void, superVoidMethodWithObject:, id);
    MUHAddInstanceMethod(MUExtendsSubClass, returnMethod, id, superReturnValueMethod);
    /**
     *	MUHAddProperty
     * ClassName, PropertyType, PropertyName, Setter, Getter
     */
    MUHAddProperty(MUExtendsSubClass, NSObject *, name, setName:, name);
}

更多信息:MUHookDemo/Sample-Extends

用法 - 添加属性

// Method 1: add `NSString *name` and `NSUInteger age`
// Method 2: add `CGRect frame`
// Method 3: add `NSString *nickName`

//	Method 1: for normal, define setter and getter implementation
//	方法1,自己实现 setter 和 getter 的方法体
MUHInstanceImplementation(MUExtendsSubClass, setName, void, NSString *name) {
    MUHSelfIvar(_name) = [name copy];
}

MUHInstanceImplementation(MUExtendsSubClass, getName, NSString *) {
    return MUHSelfIvar(_name);
}

MUHInstanceImplementation(MUExtendsSubClass, setAge, void, NSUInteger age) {
    MUHSelfIvar(_age) = @(age);
}

MUHInstanceImplementation(MUExtendsSubClass, getAge, NSUInteger) {
    return [MUHSelfIvar(_age) unsignedIntegerValue];
}

//	Method 3: for object, define property implementation
//	方法3,直接实现一个 property 的实现体
MUHPropertyImplementation(MUExtendsSubClass, strong, NSString *, nickName);

void MUHMain() {
    //  Add property - 添加属性
    
    //  Method 1: for normal, support base type, struct and object, custom with association-object and ivar. support readonly
    //  方法 1:支持基本数据类型、结构体、对象,支持自定义 ivar 或者关联对象。代码多,灵活度高,可只读
    //  Usage with MUHInstanceImplementation()
    MUHAddInstanceMethod(MUExtendsSubClass, setName, void, setName:, NSString *);
    MUHAddInstanceMethod(MUExtendsSubClass, getName, NSString *, name);
    MUHAddInstanceMethod(MUExtendsSubClass, setAge, void, setAge:, NSUInteger);
    MUHAddInstanceMethod(MUExtendsSubClass, getAge, NSUInteger, age);
    
    //  Method 2: for struct, custom with association-object or ivar. manual transform it in getter and setter. support readonly
    //  方法 2:支持基本数据类型、结构体、对象,支持自定义 ivar 或者关联对象,非对象需要自己转换,代码中等,灵活度中等,可只读
    MUHAddPropertyGetter(MUExtendsSubClass, CGRect, frame, frame) {
		//	Can not use `_cmd` in this method
		return [(NSValue *)MUHSelfIvar(_frame) rectValue];
    };
    MUHAddPropertySetter(MUExtendsSubClass, CGRect, frame, setFrame:) {
		//	Can not use `_cmd` in this method
		MUHSelfIvar(_frame) = [NSValue valueWithRect:frame];
    };
    
    //  Method 3: for object, only support association-object with strong,copy,weak,assign. unsupport readonly
    //  方法 3:仅支持对象,仅支持关联对象,代码少、灵活度低,不可只读
    //  Usage with MUHPropertyImplementation()
    MUHAddProperty(MUExtendsSubClass, NSString *, nickName, setNickName:, nickName);
}

更多信息:MUHookDemo/Sample-Extends

用法 - 符号函数(由fishhook提供支持)

// Define function to hook malloc()
//	定义一个新的 malloc 函数实现体
MUHSymbolImplementation(malloc, void *, size_t size) {
    printf("malloc(%lu)\n", size);
    return MUHSymbolOrig(malloc, size);
}

// Define function to hook getchar()
//	定义一个新的 getchar 函数实现体
MUHSymbolImplementation(getchar, int) {
    printf("New temp\n");
    return MUHSymbolOrig(getchar);
}

//	Hook functions.
//	You need call the function in MUHMain().
//	执行本文件的模块 hook
//	该函数需要在 MUHMain() 中被调用,以上实现才生效
void initMUHookSymbolSample() {
    MUHHookSymbolFunction(getchar);
    MUHHookSymbolFunction(malloc);
}