CaptainHook 源码分析(五):Hook 对象方法 && 类方法

Hook 对象方法(CHMethod + CHHook)

  • CaptainHook.h 中,宏接口 CHMethod 用于生成 Hook 对象方法的代码,其定义为:

    // @param.count		对象方法的参数个数
    // @param.args		可变的参数列表
    #define CHMethod(count, args...) \
    CHMethod ## count(args)
    

    宏接口 CHMethod 会根据要 Hook 的对象方法的参数个数,分别调用宏接口 CHMethod0 ~ CHMethod9

    // @param.return_type	对象方法返回值的类型
    // @param.class_type	对象方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
    // @param.name1			对象方法第一部分的方法名称
    // @param.type1			对象方法第一个参数的类型
    // @param.arg1			对象方法第一个参数的名称
    // @param.name2			对象方法第二部分的方法名称
    // @param.type2			对象方法第二个参数的类型
    // @param.arg2			对象方法第二个参数的名称
    // ...
    // @param.name9			对象方法第九部分的方法名称
    // @param.type9			对象方法第九个参数的类型
    // @param.arg9			对象方法第九个参数的名称
    
    // 生成(Hook 具有 0 个参数的对象方法的)代码
    #define CHMethod0(return_type, class_type, name) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name, name, CHDeclareSig0_(return_type), (self, _cmd))
    // 生成(Hook 具有 1 个参数的对象方法的)代码
    #define CHMethod1(return_type, class_type, name1, type1, arg1) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $, name1:, CHDeclareSig1_(return_type, type1), (self, _cmd, arg1), type1 arg1)
    // 生成(Hook 具有 2 个参数的对象方法的)代码
    #define CHMethod2(return_type, class_type, name1, type1, arg1, name2, type2, arg2) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $, name1:name2:, CHDeclareSig2_(return_type, type1, type2), (self, _cmd, arg1, arg2), type1 arg1, type2 arg2)
    // 生成(Hook 具有 3 个参数的对象方法的)代码
    #define CHMethod3(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $, name1:name2:name3:, CHDeclareSig3_(return_type, type1, type2, type3), (self, _cmd, arg1, arg2, arg3), type1 arg1, type2 arg2, type3 arg3)
    // 生成(Hook 具有 4 个参数的对象方法的)代码
    #define CHMethod4(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, name1:name2:name3:name4:, CHDeclareSig4_(return_type, type1, type2, type3, type4), (self, _cmd, arg1, arg2, arg3, arg4), type1 arg1, type2 arg2, type3 arg3, type4 arg4)
    // 生成(Hook 具有 5 个参数的对象方法的)代码
    #define CHMethod5(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, name1:name2:name3:name4:name5:, CHDeclareSig5_(return_type, type1, type2, type3, type4, type5), (self, _cmd, arg1, arg2, arg3, arg4, arg5), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
    // 生成(Hook 具有 6 个参数的对象方法的)代码
    #define CHMethod6(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $, name1:name2:name3:name4:name5:name6:, CHDeclareSig6_(return_type, type1, type2, type3, type4, type5, type6), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6)
    // 生成(Hook 具有 7 个参数的对象方法的)代码
    #define CHMethod7(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $, name1:name2:name3:name4:name5:name6:name7:, CHDeclareSig7_(return_type, type1, type2, type3, type4, type5, type6, type7), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7)
    // 生成(Hook 具有 8 个参数的对象方法的)代码
    #define CHMethod8(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $, name1:name2:name3:name4:name5:name6:name7:name8:, CHDeclareSig8_(return_type, type1, type2, type3, type4, type5, type6, type7, type8), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8)
    // 生成(Hook 具有 9 个参数的对象方法的)代码
    #define CHMethod9(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8, name9, type9, arg9) \
    	CHMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $ ## name9 ## $, name1:name2:name3:name4:name5:name6:name7:name8:name9:, CHDeclareSig9_(return_type, type1, type2, type3, type4, type5, type6, type7, type8, type9), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8, type9 arg9)
    

    宏接口 CHMethod0 ~ CHMethod9 会组织传入的宏参数,生成对宏接口 CHMethod_ 的调用

    关于宏接口 CHMethod_ 的介绍,请参考:
    CaptainHook 源码分析(三):交换 Objective-C 方法实现的核心代码(使用 RunTime API)
    CaptainHook 源码分析(四):交换 Objective-C 方法实现的核心代码(使用 Cydia Substrate)

  • CaptainHook.h 中,宏接口 CHHook 用于调用 Hook 对象方法的代码,其定义为:

    // @param.count		对象方法的参数个数
    // @param.args		可变的参数列表
    #define CHHook(count, args...) CHHook ## count(args)
    

    宏接口 CHHook 会根据要 Hook 的对象方法的参数个数,分别调用宏接口 CHHook0 ~ CHHook9

    // @param.class		对象方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
    // @param.name1		对象方法第一部分的方法名称
    // @param.name2		对象方法第二部分的方法名称
    // ...
    // @param.name9		对象方法第九部分的方法名称
    
    // 调用(Hook 具有 0 个参数的对象方法的)代码
    #define CHHook0(class, name) CHHook_(class, name)
    // 调用(Hook 具有 1 个参数的对象方法的)代码
    #define CHHook1(class, name1) CHHook_(class, name1 ## $)
    // 调用(Hook 具有 2 个参数的对象方法的)代码
    #define CHHook2(class, name1, name2) CHHook_(class, name1 ## $ ## name2 ## $)
    // 调用(Hook 具有 3 个参数的对象方法的)代码
    #define CHHook3(class, name1, name2, name3) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $)
    // 调用(Hook 具有 4 个参数的对象方法的)代码
    #define CHHook4(class, name1, name2, name3, name4) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $)
    // 调用(Hook 具有 5 个参数的对象方法的)代码
    #define CHHook5(class, name1, name2, name3, name4, name5) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $)
    // 调用(Hook 具有 6 个参数的对象方法的)代码
    #define CHHook6(class, name1, name2, name3, name4, name5, name6) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $)
    // 调用(Hook 具有 7 个参数的对象方法的)代码
    #define CHHook7(class, name1, name2, name3, name4, name5, name6, name7) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $)
    // 调用(Hook 具有 8 个参数的对象方法的)代码
    #define CHHook8(class, name1, name2, name3, name4, name5, name6, name7, name8) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $)
    // 调用(Hook 具有 9 个参数的对象方法的)代码
    #define CHHook9(class, name1, name2, name3, name4, name5, name6, name7, name8, name9) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $ ## name9 ## $)
    

    宏接口 CHHook0 ~ CHHook9 会组织传入的宏参数,生成对宏接口 CHHook_ 的调用

    // @param.class_name	对象方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
    // @param.name			对象方法的方法标识
    #define CHHook_(class_name, name) \
    	$ ## class_name ## _ ## name ## _register()
    

    宏接口 CHHook_ 会组织传入的宏参数,生成对注册函数 $类名_方法标识_register() 的调用

    关于注册函数 $类名_方法标识_register() 的介绍,请参考:
    CaptainHook 源码分析(三):交换 Objective-C 方法实现的核心代码(使用 RunTime API)
    CaptainHook 源码分析(四):交换 Objective-C 方法实现的核心代码(使用 Cydia Substrate)

  • 以 Hook 具有 2 个参数的对象方法 -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge] 为例:

    #import "HcgPerson.h"
    #import "CaptainHook.h"
    
    CHDeclareClass(HcgPerson)
    
    // -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
    
    CHMethod(2, HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
    {
        NSLog(@"hzp done!!!");
        return nil;
    }
    
    CHConstructor
    {
        CHLoadLateClass(HcgPerson);
        CHHook(2, HcgPerson, initWithName, age);
    }
    

    等价于

    #import "HcgPerson.h"
    #import "CaptainHook.h"
    
    CHDeclareClass(HcgPerson)
    
    // -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
    
    CHMethod2(HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
    {
        NSLog(@"hzp done!!!");
        return nil;
    }
    
    CHConstructor
    {
        CHLoadLateClass(HcgPerson);
        CHHook2(HcgPerson, initWithName, age);
    }
    

    等价于

    #import "HcgPerson.h"
    #import "CaptainHook.h"
    
    CHDeclareClass(HcgPerson)
    
    // -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
    
    CHMethod_(HcgPerson*, 
    		  HcgPerson*, 
    		  HcgPerson, 
    		  CHClass(HcgPerson),
    		  CHSuperClass(HcgPerson), 
    		  initWithName$age$, 
    		  initWithName:age:, 
    		  CHDeclareSig2_(HcgPerson*, NSString*, int), 
    		  (self, _cmd, aName, anAge), 
    		  NSString* aName, 
    		  int anAge)
    {
        NSLog(@"hzp done!!!");
        return nil;
    }
    
    CHConstructor
    {
        CHLoadLateClass(HcgPerson);
        CHHook_(HcgPerson, initWithName$age$);
    }
    

    等价于

    ...
    
    static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
    
    static HcgPerson* $HcgPerson_initWithName$age$_closure(HcgPerson* self, SEL _cmd, NSString* aName, int anAge)
    {
        ...
    }
    
    static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge);
    
    __attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register()
    {
        ...
    }
    
    // -[HcgPerson initWithName:age:] 方法的替换实现
    static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson* self, SEL _cmd, NSString* aName, int anAge)
    {
        NSLog(@"hzp done!!!");
        return ((void *)0);
    }
    
    static __attribute__((constructor)) void CHConstructor8()
    {
        ...
        $HcgPerson_initWithName$age$_register();
    }
    

Hook 对象方法(CHDeclareMethod)

CaptainHook.h 中,宏接口 CHDeclareMethod 用于生成并调用 Hook 对象方法的代码,其定义为:

// @param.count		对象方法的参数个数
// @param.args		可变的参数列表
#define CHDeclareMethod(count, args...) \
	CHDeclareMethod ## count(args)

宏接口 CHDeclareMethod 会根据要 Hook 的对象方法的参数个数,分别调用宏接口 CHDeclareMethod0 ~ CHDeclareMethod9

// @param.return_type	对象方法返回值的类型
// @param.class_type	对象方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.name1			对象方法第一部分的方法名称
// @param.type1			对象方法第一个参数的类型
// @param.arg1			对象方法第一个参数的名称
// @param.name2			对象方法第二部分的方法名称
// @param.type2			对象方法第二个参数的类型
// @param.arg2			对象方法第二个参数的名称
// ...
// @param.name9			对象方法第九部分的方法名称
// @param.type9			对象方法第九个参数的类型
// @param.arg9			对象方法第九个参数的名称

// 生成并调用(Hook 具有 0 个参数的对象方法的)代码
#define CHDeclareMethod0(return_type, class_type, name) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name, name, CHDeclareSig0_(return_type), (self, _cmd))
// 生成并调用(Hook 具有 1 个参数的对象方法的)代码
#define CHDeclareMethod1(return_type, class_type, name1, type1, arg1) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $, name1:, CHDeclareSig1_(return_type, type1), (self, _cmd, arg1), type1 arg1)
// 生成并调用(Hook 具有 2 个参数的对象方法的)代码
#define CHDeclareMethod2(return_type, class_type, name1, type1, arg1, name2, type2, arg2) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $, name1:name2:, CHDeclareSig2_(return_type, type1, type2), (self, _cmd, arg1, arg2), type1 arg1, type2 arg2)
// 生成并调用(Hook 具有 3 个参数的对象方法的)代码
#define CHDeclareMethod3(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $, name1:name2:name3:, CHDeclareSig3_(return_type, type1, type2, type3), (self, _cmd, arg1, arg2, arg3), type1 arg1, type2 arg2, type3 arg3)
// 生成并调用(Hook 具有 4 个参数的对象方法的)代码
#define CHDeclareMethod4(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, name1:name2:name3:name4:, CHDeclareSig4_(return_type, type1, type2, type3, type4), (self, _cmd, arg1, arg2, arg3, arg4), type1 arg1, type2 arg2, type3 arg3, type4 arg4)
// 生成并调用(Hook 具有 5 个参数的对象方法的)代码
#define CHDeclareMethod5(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, name1:name2:name3:name4:name5:, CHDeclareSig5_(return_type, type1, type2, type3, type4, type5), (self, _cmd, arg1, arg2, arg3, arg4, arg5), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
// 生成并调用(Hook 具有 6 个参数的对象方法的)代码
#define CHDeclareMethod6(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $, name1:name2:name3:name4:name5:name6:, CHDeclareSig6_(return_type, type1, type2, type3, type4, type5, type6), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6)
// 生成并调用(Hook 具有 7 个参数的对象方法的)代码
#define CHDeclareMethod7(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $, name1:name2:name3:name4:name5:name6:name7:, CHDeclareSig7_(return_type, type1, type2, type3, type4, type5, type6, type7), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7)
// 生成并调用(Hook 具有 8 个参数的对象方法的)代码
#define CHDeclareMethod8(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $, name1:name2:name3:name4:name5:name6:name7:name8:, CHDeclareSig8_(return_type, type1, type2, type3, type4, type5, type6, type7, type8), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8)
// 生成并调用(Hook 具有 9 个参数的对象方法的)代码
#define CHDeclareMethod9(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8, name9, type9, arg9) \
	CHDeclareMethod_(return_type, class_type *, class_type, CHClass(class_type), CHSuperClass(class_type), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $ ## name9 ## $, name1:name2:name3:name4:name5:name6:name7:name8:name9:, CHDeclareSig9_(return_type, type1, type2, type3, type4, type5, type6, type7, type8, type9), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8, type9 arg9)

宏接口 CHDeclareMethod0 ~ CHDeclareMethod9 会组织传入的宏参数,生成对宏接口 CHDeclareMethod_ 的调用

// @param.return_type		方法返回值的类型
// @param.class_type		方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
// @param.class_name		方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.class_val			方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
// @param.super_class_val	上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
// @param.name				方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
// @param.sel				方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
// @param.sigdef			计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
// @param.supercall			调用闭包函数 xxx_closure 的参数列表
// @param.args...			方法的形参列表
#define CHDeclareMethod_(return_type, class_type, class_name, class_val, super_class_val, name, sel, sigdef, supercall, args...) \
	static inline void $ ## class_name ## _ ## name ## _register(); \
	__attribute__((constructor)) \
	static inline void $ ## class_name ## _ ## name ## _constructor() { \
		CHLoadLateClass(class_name); \
		$ ## class_name ## _ ## name ## _register(); \
	} \
	CHMethod_(return_type, class_type, class_name, class_val, super_class_val, name, sel, sigdef, supercall, ##args)

宏接口 CHDeclareMethod_ 做了以下三件事:

  1. 根据要 Hook 的方法的标识,为要 Hook 的方法单独生成一个构造函数
  2. 在单独生成的构造函数中,加载要 Hook 的类,并调用注册函数 Hook 对应的方法
  3. 调用宏接口 CHMethod_ 生成交换方法实现的核心代码(里面包含注册函数)

以 Hook 具有 2 个参数的对象方法 -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge] 为例:

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]

CHDeclareMethod(2, HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"hzp done!!!");
    return nil;
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]

CHDeclareMethod2(HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"hzp done!!!");
    return ((void *)0);
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]

CHDeclareMethod_(HcgPerson*,
                 HcgPerson *,
                 HcgPerson,
                 CHClass(HcgPerson),
                 CHSuperClass(HcgPerson),
                 initWithName$age$,
                 initWithName:age:,
                 CHDeclareSig2_(HcgPerson*, NSString*, int),
                 (self, _cmd, aName, anAge),
                 NSString* aName,
                 int anAge)
{
    NSLog(@"hzp done!!!");
    return ((void *)0);
}

等价于

...

static inline void $HcgPerson_initWithName$age$_register();

// 1.根据要 Hook 的方法的标识,为要 Hook 的方法单独生成一个构造函数
__attribute__((constructor)) static inline void $HcgPerson_initWithName$age$_constructor()
{
	// 2.在单独生成的构造函数中,加载要 Hook 的类,并调用注册函数 Hook 对应的方法
    CHLoadClass_(&HcgPerson$, objc_getClass("HcgPerson"));
    $HcgPerson_initWithName$age$_register();
}

// 3.调用宏接口 CHMethod_ 生成交换方法实现的核心代码(里面包含注册函数)

static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson * self, SEL _cmd, NSString* aName, int anAge);

static HcgPerson* $HcgPerson_initWithName$age$_closure(HcgPerson * self, SEL _cmd, NSString* aName, int anAge)
{
    ...
}

static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson * self, SEL _cmd, NSString* aName, int anAge);

__attribute__((always_inline)) static inline void $HcgPerson_initWithName$age$_register()
{
    ...
}

static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson * self, SEL _cmd, NSString* aName, int anAge)
{
    NSLog(@"hzp done!!!");
    return ((void *)0);
}

CHMethod 与 CHDeclareMethod 的区别

在使用宏接口 CHMethod Hook 对象方法时,开发者需要自己手动调用宏接口 CHConstructor 生成构造函数
并在手动生成的构造函数中,手动调用宏接口 CHLoadLateClass 加载要 Hook 的类,以及手动调用宏接口 CHHook 触发交换方法实现的注册函数

在使用宏接口 CHDeclareMethod Hook 对象方法时,会自动生成构造函数
并在自动生成的构造函数中,自动加载要 Hook 的类,以及自动触发(交换方法实现的)注册函数

宏接口 CHConstructor 会根据其在源文件中的行号来生成构造函数
宏接口 CHDeclareMethod 会根据其要 Hook 的方法名称来成构造函数

Hook 类方法(CHClassMethod + CHClassHook)

  • CaptainHook.h 中,宏接口 CHClassMethod 用于生成 Hook 类方法的代码,其定义为:

    // @param.count		类方法的参数个数
    // @param.args		可变的参数列表
    #define CHClassMethod(count, args...) \
    	CHClassMethod ## count(args)
    

    宏接口 CHClassMethod 会根据要 Hook 的类方法的参数个数,分别调用宏接口 CHClassMethod0 ~ CHClassMethod9

    // @param.return_type	类方法返回值的类型
    // @param.class_type	类方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
    // @param.name1			类方法第一部分的方法名称
    // @param.type1			类方法第一个参数的类型
    // @param.arg1			类方法第一个参数的名称
    // @param.name2			类方法第二部分的方法名称
    // @param.type2			类方法第二个参数的类型
    // @param.arg2			类方法第二个参数的名称
    // ...
    // @param.name9			类方法第九部分的方法名称
    // @param.type9			类方法第九个参数的类型
    // @param.arg9			类方法第九个参数的名称
    
    // 生成(Hook 具有 0 个参数的类方法的)代码
    #define CHClassMethod0(return_type, class_type, name) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name, name, CHDeclareSig0_(return_type), (self, _cmd))
    // 生成(Hook 具有 1 个参数的类方法的)代码
    #define CHClassMethod1(return_type, class_type, name1, type1, arg1) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $, name1:, CHDeclareSig1_(return_type, type1), (self, _cmd, arg1), type1 arg1)
    // 生成(Hook 具有 2 个参数的类方法的)代码
    #define CHClassMethod2(return_type, class_type, name1, type1, arg1, name2, type2, arg2) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $, name1:name2:, CHDeclareSig2_(return_type, type1, type2), (self, _cmd, arg1, arg2), type1 arg1, type2 arg2)
    // 生成(Hook 具有 3 个参数的类方法的)代码
    #define CHClassMethod3(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $, name1:name2:name3:, CHDeclareSig3_(return_type, type1, type2, type3), (self, _cmd, arg1, arg2, arg3), type1 arg1, type2 arg2, type3 arg3)
    // 生成(Hook 具有 4 个参数的类方法的)代码
    #define CHClassMethod4(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, name1:name2:name3:name4:, CHDeclareSig4_(return_type, type1, type2, type3, type4), (self, _cmd, arg1, arg2, arg3, arg4), type1 arg1, type2 arg2, type3 arg3, type4 arg4)
    // 生成(Hook 具有 5 个参数的类方法的)代码
    #define CHClassMethod5(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, name1:name2:name3:name4:name5:, CHDeclareSig5_(return_type, type1, type2, type3, type4, type5), (self, _cmd, arg1, arg2, arg3, arg4, arg5), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
    // 生成(Hook 具有 6 个参数的类方法的)代码
    #define CHClassMethod6(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $, name1:name2:name3:name4:name5:name6:, CHDeclareSig6_(return_type, type1, type2, type3, type4, type5, type6), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6)
    // 生成(Hook 具有 7 个参数的类方法的)代码
    #define CHClassMethod7(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $, name1:name2:name3:name4:name5:name6:name7:, CHDeclareSig7_(return_type, type1, type2, type3, type4, type5, type6, type7), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7)
    // 生成(Hook 具有 8 个参数的类方法的)代码
    #define CHClassMethod8(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $, name1:name2:name3:name4:name5:name6:name7:name8:, CHDeclareSig8_(return_type, type1, type2, type3, type4, type5, type6, type7, type8), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8)
    // 生成(Hook 具有 9 个参数的类方法的)代码
    #define CHClassMethod9(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8, name9, type9, arg9) \
    	CHMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $ ## name9 ## $, name1:name2:name3:name4:name5:name6:name7:name8:name9:, CHDeclareSig9_(return_type, type1, type2, type3, type4, type5, type6, type7, type8, type9), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8, type9 arg9)
    

    宏接口 CHClassMethod0 ~ CHClassMethod9 会组织传入的宏参数,生成对宏接口 CHMethod_ 的调用

    关于宏接口 CHMethod_ 的介绍,请参考:
    CaptainHook 源码分析(三):交换 Objective-C 方法实现的核心代码(使用 RunTime API)
    CaptainHook 源码分析(四):交换 Objective-C 方法实现的核心代码(使用 Cydia Substrate)

  • CaptainHook.h 中,宏接口 CHClassHook 用于调用 Hook 类方法的代码,其定义为:

    // @param.count		类方法的参数个数
    // @param.args		可变的参数列表
    #define CHClassHook(count, args...) CHClassHook ## count(args)
    

    宏接口 CHClassHook 会根据要 Hook 的类方法的参数个数,分别调用宏接口 CHClassHook0 ~ CHClassHook9

    // @param.class		类方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
    // @param.name1		类方法第一部分的方法名称
    // @param.name2		类方法第二部分的方法名称
    // ...
    // @param.name9		类方法第九部分的方法名称
    
    // 调用(Hook 具有 0 个参数的类方法的)代码
    #define CHClassHook0(class, name) CHHook_(class, name)
    // 调用(Hook 具有 1 个参数的类方法的)代码
    #define CHClassHook1(class, name1) CHHook_(class, name1 ## $)
    // 调用(Hook 具有 2 个参数的类方法的)代码
    #define CHClassHook2(class, name1, name2) CHHook_(class, name1 ## $ ## name2 ## $)
    // 调用(Hook 具有 3 个参数的类方法的)代码
    #define CHClassHook3(class, name1, name2, name3) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $)
    // 调用(Hook 具有 4 个参数的类方法的)代码
    #define CHClassHook4(class, name1, name2, name3, name4) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $)
    // 调用(Hook 具有 5 个参数的类方法的)代码
    #define CHClassHook5(class, name1, name2, name3, name4, name5) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $)
    // 调用(Hook 具有 6 个参数的类方法的)代码
    #define CHClassHook6(class, name1, name2, name3, name4, name5, name6) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $)
    // 调用(Hook 具有 7 个参数的类方法的)代码
    #define CHClassHook7(class, name1, name2, name3, name4, name5, name6, name7) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $)
    // 调用(Hook 具有 8 个参数的类方法的)代码
    #define CHClassHook8(class, name1, name2, name3, name4, name5, name6, name7, name8) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $)
    // 调用(Hook 具有 9 个参数的类方法的)代码
    #define CHClassHook9(class, name1, name2, name3, name4, name5, name6, name7, name8, name9) CHHook_(class, name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $ ## name9 ## $)
    

    宏接口 CHClassHook0 ~ CHClassHook9 会组织传入的宏参数,生成对宏接口 CHHook_ 的调用

    // @param.class_name	类方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
    // @param.name			类方法的方法标识
    #define CHHook_(class_name, name) \
    	$ ## class_name ## _ ## name ## _register()
    

    宏接口 CHHook_ 会组织传入的宏参数,生成对注册函数 $类名_方法标识_register() 的调用

    关于注册函数 $类名_方法标识_register() 的介绍,请参考:
    CaptainHook 源码分析(三):交换 Objective-C 方法实现的核心代码(使用 RunTime API)
    CaptainHook 源码分析(四):交换 Objective-C 方法实现的核心代码(使用 Cydia Substrate)

  • 以 Hook 具有 2 个参数的类方法 +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge] 为例:

    #import "HcgPerson.h"
    #import "CaptainHook.h"
    
    CHDeclareClass(HcgPerson)
    
    // +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]
    
    CHClassMethod(2, HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
    {
        NSLog(@"hcg done!!!");
        return nil;
    }
    
    CHConstructor
    {
        CHLoadLateClass(HcgPerson);
        CHClassHook(2, HcgPerson, personWithName, age);
    }
    

    等价于

    #import "HcgPerson.h"
    #import "CaptainHook.h"
    
    CHDeclareClass(HcgPerson)
    
    // +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]
    
    CHClassMethod2(HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
    {
        NSLog(@"hcg done!!!");
        return nil;
    }
    
    CHConstructor
    {
        CHLoadLateClass(HcgPerson);
        CHClassHook2(HcgPerson, personWithName, age);
    }
    

    等价于

    #import "HcgPerson.h"
    #import "CaptainHook.h"
    
    CHDeclareClass(HcgPerson)
    
    // +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]
    
    CHMethod_(HcgPerson*, 
    		  id, 
    		  HcgPerson, 
    		  CHMetaClass(HcgPerson), 
    		  object_getClass(CHMetaClass(HcgPerson)), 
    		  personWithName$age$, 
    		  personWithName:age:, 
    		  CHDeclareSig2_(HcgPerson*, NSString*, int), 
    		  (self, _cmd, aName, anAge), 
    		  NSString* aName, 
    		  int anAge)
    {
    	NSLog(@"hcg done!!!");
    	return nil;
    }
    
    CHConstructor
    {
    	CHLoadLateClass(HcgPerson);
    	CHHook_(HcgPerson, personWithName$age$);
    }
    

    等价于

    ...
    
    static HcgPerson* (*$HcgPerson_personWithName$age$_super)(id self, SEL _cmd, NSString* aName, int anAge);
    
    static HcgPerson* $HcgPerson_personWithName$age$_closure(id self, SEL _cmd, NSString* aName, int anAge)
    {
        ...
    }
    
    static HcgPerson* $HcgPerson_personWithName$age$_method(id self, SEL _cmd, NSString* aName, int anAge);
    
    __attribute__((always_inline)) static inline void $HcgPerson_personWithName$age$_register()
    {
        ...
    }
    
    static HcgPerson* $HcgPerson_personWithName$age$_method(id self, SEL _cmd, NSString* aName, int anAge)
    {
        NSLog(@"hcg done!!!");
        return ((void *)0);
    }
    
    static __attribute__((constructor)) void CHConstructor8()
    {
        ...
        $HcgPerson_personWithName$age$_register();
    }
    

Hook 类方法(CHDeclareClassMethod)

CaptainHook.h 中,宏接口 CHDeclareClassMethod 用于生成并调用 Hook 类方法的代码,其定义为:

// @param.count		类方法的参数个数
// @param.args		可变的参数列表
#define CHDeclareClassMethod(count, args...) \
	CHDeclareClassMethod ## count(args)

宏接口 CHDeclareClassMethod 会根据要 Hook 的类方法的参数个数,分别调用宏接口 CHDeclareClassMethod0 ~ CHDeclareClassMethod9

// @param.return_type	类方法返回值的类型
// @param.class_type	类方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.name1			类方法第一部分的方法名称
// @param.type1			类方法第一个参数的类型
// @param.arg1			类方法第一个参数的名称
// @param.name2			类方法第二部分的方法名称
// @param.type2			类方法第二个参数的类型
// @param.arg2			类方法第二个参数的名称
// ...
// @param.name9			类方法第九部分的方法名称
// @param.type9			类方法第九个参数的类型
// @param.arg9			类方法第九个参数的名称

// 生成并调用(Hook 具有 0 个参数的类方法的)代码
#define CHDeclareClassMethod0(return_type, class_type, name) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name, name, CHDeclareSig0_(return_type), (self, _cmd))
// 生成并调用(Hook 具有 1 个参数的类方法的)代码
#define CHDeclareClassMethod1(return_type, class_type, name1, type1, arg1) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $, name1:, CHDeclareSig1_(return_type, type1), (self, _cmd, arg1), type1 arg1)
// 生成并调用(Hook 具有 2 个参数的类方法的)代码
#define CHDeclareClassMethod2(return_type, class_type, name1, type1, arg1, name2, type2, arg2) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $, name1:name2:, CHDeclareSig2_(return_type, type1, type2), (self, _cmd, arg1, arg2), type1 arg1, type2 arg2)
// 生成并调用(Hook 具有 3 个参数的类方法的)代码
#define CHDeclareClassMethod3(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $, name1:name2:name3:, CHDeclareSig3_(return_type, type1, type2, type3), (self, _cmd, arg1, arg2, arg3), type1 arg1, type2 arg2, type3 arg3)
// 生成并调用(Hook 具有 4 个参数的类方法的)代码
#define CHDeclareClassMethod4(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, name1:name2:name3:name4:, CHDeclareSig4_(return_type, type1, type2, type3, type4), (self, _cmd, arg1, arg2, arg3, arg4), type1 arg1, type2 arg2, type3 arg3, type4 arg4)
// 生成并调用(Hook 具有 5 个参数的类方法的)代码
#define CHDeclareClassMethod5(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, name1:name2:name3:name4:name5:, CHDeclareSig5_(return_type, type1, type2, type3, type4, type5), (self, _cmd, arg1, arg2, arg3, arg4, arg5), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)
// 生成并调用(Hook 具有 6 个参数的类方法的)代码
#define CHDeclareClassMethod6(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $, name1:name2:name3:name4:name5:name6:, CHDeclareSig6_(return_type, type1, type2, type3, type4, type5, type6), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6)
// 生成并调用(Hook 具有 7 个参数的类方法的)代码
#define CHDeclareClassMethod7(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $, name1:name2:name3:name4:name5:name6:name7:, CHDeclareSig7_(return_type, type1, type2, type3, type4, type5, type6, type7), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7)
// 生成并调用(Hook 具有 8 个参数的类方法的)代码
#define CHDeclareClassMethod8(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $, name1:name2:name3:name4:name5:name6:name7:name8:, CHDeclareSig8_(return_type, type1, type2, type3, type4, type5, type6, type7, type8), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8)
// 生成并调用(Hook 具有 9 个参数的类方法的)代码
#define CHDeclareClassMethod9(return_type, class_type, name1, type1, arg1, name2, type2, arg2, name3, type3, arg3, name4, type4, arg4, name5, type5, arg5, name6, type6, arg6, name7, type7, arg7, name8, type8, arg8, name9, type9, arg9) \
	CHDeclareMethod_(return_type, id, class_type, CHMetaClass(class_type), object_getClass(CHMetaClass(class_type)), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $ ## name9 ## $, name1:name2:name3:name4:name5:name6:name7:name8:name9:, CHDeclareSig9_(return_type, type1, type2, type3, type4, type5, type6, type7, type8, type9), (self, _cmd, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6, type7 arg7, type8 arg8, type9 arg9)

宏接口 CHDeclareClassMethod0 ~ CHDeclareClassMethod9 会组织传入的宏参数,生成对宏接口 CHDeclareMethod_ 的调用

// @param.return_type		方法返回值的类型
// @param.class_type		方法中 self 的类型(对象方法中 self 的类型为:ClassName*,类方法中 self 的类型为:id)
// @param.class_name		方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.class_val			方法的存储位置(对象方法存储在类对象中,类方法存储在元类对象中)
// @param.super_class_val	上一个参数(class_val)的父对象(注意:类对象的父对象是父类对象,元类对象的父对象是根元类对象。任何元类对象的父对象,都是根元类对象)
// @param.name				方法的标识,用于拼接到要生成的(函数指针与函数)的名称中
// @param.sel				方法的 SEL 名称(直接写方法名称,不需要加关键字 @selector,不需要加 @"" 或者 "")
// @param.sigdef			计算方法类型编码的宏定义(CHDeclareSig0_ ~ CHDeclareSig9_)
// @param.supercall			调用闭包函数 xxx_closure 的参数列表
// @param.args...			方法的形参列表
#define CHDeclareMethod_(return_type, class_type, class_name, class_val, super_class_val, name, sel, sigdef, supercall, args...) \
	static inline void $ ## class_name ## _ ## name ## _register(); \
	__attribute__((constructor)) \
	static inline void $ ## class_name ## _ ## name ## _constructor() { \
		CHLoadLateClass(class_name); \
		$ ## class_name ## _ ## name ## _register(); \
	} \
	CHMethod_(return_type, class_type, class_name, class_val, super_class_val, name, sel, sigdef, supercall, ##args)

宏接口 CHDeclareMethod_ 做了以下三件事:

  1. 根据要 Hook 的方法的标识,为要 Hook 的方法单独生成一个构造函数
  2. 在单独生成的构造函数中,加载要 Hook 的类,并调用注册函数 Hook 对应的方法
  3. 调用宏接口 CHMethod_ 生成交换方法实现的核心代码(里面包含注册函数)

以 Hook 具有 2 个参数的类方法 +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge] 为例:

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]

CHDeclareClassMethod(2, HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"hcg done!!!");
    return nil;
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]

CHDeclareClassMethod2(HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"hcg done!!!");
    return ((void *)0);
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]

CHDeclareMethod_(HcgPerson*,
                 id,
                 HcgPerson,
                 CHMetaClass(HcgPerson),
                 object_getClass(CHMetaClass(HcgPerson)),
                 personWithName$age$,
                 personWithName:age:,
                 CHDeclareSig2_(HcgPerson*, NSString*, int),
                 (self, _cmd, aName, anAge),
                 NSString* aName,
                 int anAge)
{
    NSLog(@"hcg done!!!");
    return ((void *)0);
}

等价于

...

static inline void $HcgPerson_personWithName$age$_register();

// 1.根据要 Hook 的方法的标识,为要 Hook 的方法单独生成一个构造函数
__attribute__((constructor)) static inline void $HcgPerson_personWithName$age$_constructor()
{
	// 2.在单独生成的构造函数中,加载要 Hook 的类,并调用注册函数 Hook 对应的方法
    CHLoadClass_(&HcgPerson$, objc_getClass("HcgPerson"));
    $HcgPerson_personWithName$age$_register();
}

// 3.调用宏接口 CHMethod_ 生成交换方法实现的核心代码(里面包含注册函数)

static HcgPerson* (*$HcgPerson_personWithName$age$_super)(id self, SEL _cmd, NSString* aName, int anAge);

static HcgPerson* $HcgPerson_personWithName$age$_closure(id self, SEL _cmd, NSString* aName, int anAge)
{
    ...
}

static HcgPerson* $HcgPerson_personWithName$age$_method(id self, SEL _cmd, NSString* aName, int anAge);

__attribute__((always_inline)) static inline void $HcgPerson_personWithName$age$_register()
{
    ...
}

static HcgPerson* $HcgPerson_personWithName$age$_method(id self, SEL _cmd, NSString* aName, int anAge)
{
    NSLog(@"hcg done!!!");
    return ((void *)0);
}

CHClassMethod 与 CHDeclareClassMethod 的区别

在使用宏接口 CHClassMethod Hook 类方法时,开发者需要自己手动调用宏接口 CHConstructor 生成构造函数
并在手动生成的构造函数中,手动调用宏接口 CHLoadLateClass 加载要 Hook 的类,以及手动调用宏接口 CHClassHook 触发交换方法实现的注册函数

在使用宏接口 CHDeclareClassMethod Hook 类方法时,会自动生成构造函数
并在自动生成的构造函数中,自动加载要 Hook 的类,以及自动触发(交换方法实现的)注册函数

宏接口 CHConstructor 会根据其在源文件中的行号来生成构造函数
宏接口 CHDeclareClassMethod 会根据其要 Hook 的方法名称来成构造函数

调用被 Hook 的方法的原始实现(CHSuper)

CaptainHook.h 中,宏接口 CHSuper 用于调用被 Hook 的方法的原始实现,其定义为:

// @param.count		对象方法或者类方法的参数个数
// @param.args		可变的参数列表
#define CHSuper(count, args...) \
	CHSuper ## count(args)

宏接口 CHSuper 会根据要调用原始实现的对象方法或者类方法的参数个数,分别调用宏接口 CHSuper0 ~ CHSuper9

// @param.class_type	对象方法或者类方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param.name1			对象方法或者类方法第一部分的方法名称
// @param.val1			对象方法或者类方法第一个参数的值
// @param.name2			对象方法或者类方法第二部分的方法名称
// @param.val2			对象方法或者类方法第二个参数的值
// ...
// @param.name9			对象方法或者类方法第九部分的方法名称
// @param.val9			对象方法或者类方法第九个参数的值

// 生成(调用具有 0 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper0(class_type, name) \
	CHSuper_(class_type, @selector(name), name)
// 生成(调用具有 1 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper1(class_type, name1, val1) \
	CHSuper_(class_type, @selector(name1:), name1 ## $, val1)
// 生成(调用具有 2 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper2(class_type, name1, val1, name2, val2) \
	CHSuper_(class_type, @selector(name1:name2:), name1 ## $ ## name2 ## $, val1, val2)
// 生成(调用具有 3 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper3(class_type, name1, val1, name2, val2, name3, val3) \
	CHSuper_(class_type, @selector(name1:name2:name3:), name1 ## $ ## name2 ## $ ## name3 ## $, val1, val2, val3)
// 生成(调用具有 4 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper4(class_type, name1, val1, name2, val2, name3, val3, name4, val4) \
	CHSuper_(class_type, @selector(name1:name2:name3:name4:), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $, val1, val2, val3, val4)
// 生成(调用具有 5 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper5(class_type, name1, val1, name2, val2, name3, val3, name4, val4, name5, val5) \
	CHSuper_(class_type, @selector(name1:name2:name3:name4:name5:), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $, val1, val2, val3, val4, val5)
// 生成(调用具有 6 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper6(class_type, name1, val1, name2, val2, name3, val3, name4, val4, name5, val5, name6, val6) \
	CHSuper_(class_type, @selector(name1:name2:name3:name4:name5:name6:), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $, val1, val2, val3, val4, val5, val6)
// 生成(调用具有 7 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper7(class_type, name1, val1, name2, val2, name3, val3, name4, val4, name5, val5, name6, val6, name7, val7) \
	CHSuper_(class_type, @selector(name1:name2:name3:name4:name5:name6:name7:), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $, val1, val2, val3, val4, val5, val6, val7)
// 生成(调用具有 8 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper8(class_type, name1, val1, name2, val2, name3, val3, name4, val4, name5, val5, name6, val6, name7, val7, name8, val8) \
	CHSuper_(class_type, @selector(name1:name2:name3:name4:name5:name6:name7:name8:), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $, val1, val2, val3, val4, val5, val6, val7, val8)
// 生成(调用具有 9 个参数的对象方法或者类方法的原始实现)的代码
#define CHSuper9(class_type, name1, val1, name2, val2, name3, val3, name4, val4, name5, val5, name6, val6, name7, val7, name8, val8, name9, val9) \
	CHSuper_(class_type, @selector(name1:name2:name3:name4:name5:name6:name7:name8:name9:), name1 ## $ ## name2 ## $ ## name3 ## $ ## name4 ## $ ## name5 ## $ ## name6 ## $ ## name7 ## $ ## name8 ## $ ## name9 ## $, val1, val2, val3, val4, val5, val6, val7, val8, val9)

宏接口 CHSuper0 ~ CHSuper9 会组织传入的宏参数,生成对宏接口 CHSuper_ 的调用

// @param.class_type	对象方法或者类方法所属类的名称(无论是对象方法还是类方法,都是当前类 ClassName 的方法,所以都为 ClassName)
// @param._cmd			对象方法或者类方法的 Selector
// @param.name			对象方法或者类方法的方法标识
// @param.args			对象方法或者类方法的参数列表
#define CHSuper_(class_type, _cmd, name, args...) \
	$ ## class_type ## _ ## name ## _super(self, _cmd, ##args)

以 Hook
具有 2 个参数的对象方法 -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
具有 2 个参数的类方法 +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]
为例:

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
CHDeclareMethod(2, HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"Hook Instance Method");
    return CHSuper(2, HcgPerson, initWithName, @"hzp", age, 30);
}

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]
CHDeclareClassMethod(2, HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"Hook Class Method");
    return CHSuper(2, HcgPerson, personWithName, @"hcg", age, 20);
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
CHDeclareMethod(2, HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"Hook Instance Method");
    return CHSuper2(HcgPerson, initWithName, @"hzp", age, 30);
}

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]
CHDeclareClassMethod(2, HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"Hook Class Method");
    return CHSuper2(HcgPerson, personWithName, @"hcg", age, 20);
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
CHDeclareMethod(2, HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"Hook Instance Method");
    return CHSuper_(HcgPerson, @selector(initWithName:age:), initWithName$age$, @"hzp", 30);
}

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]
CHDeclareClassMethod(2, HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"Hook Class Method");
    return CHSuper_(HcgPerson, @selector(personWithName:age:), personWithName$age$, @"hcg", 20);
}

等价于

#import "HcgPerson.h"
#import "CaptainHook.h"

CHDeclareClass(HcgPerson)

// -(instancetype)[HcgPerson initWithName:(NSString *)aName age:(int)anAge]
CHDeclareMethod(2, HcgPerson*, HcgPerson, initWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"Hook Instance Method");
    return $HcgPerson_initWithName$age$_super(self, @selector(initWithName:age:), @"hzp", 30);
}

// +(instancetype)[HcgPerson personWithName:(NSString *)aName age:(int)anAge]
CHDeclareClassMethod(2, HcgPerson*, HcgPerson, personWithName, NSString*, aName, age, int, anAge)
{
    NSLog(@"Hook Class Method");
    return $HcgPerson_personWithName$age$_super(self, @selector(personWithName:age:), @"hcg", 20);
}

等价于

...

// 供宏接口 CHSuper_ 调用的函数指针,用于指向 -[HcgPerson initWithName:age:] 方法的原始实现
// 1.如果 -[HcgPerson initWithName:age:] 方法的原始实现存储在 HcgPerson 的类对象中
//     则该函数指针指向 HcgPerson 的类对象中的 -initWithName:age: 方法实现
// 2.如果 -[HcgPerson initWithName:age:] 方法的原始实现存储在 HcgPerson 的父类对象中
//   则该函数指针指向闭包函数 $HcgPerson_initWithName$age$_closure
//   而闭包函数 $HcgPerson_initWithName$age$_closure 会负责调用 HcgPerson 的父类对象中的 -initWithName:age: 方法实现
static HcgPerson* (*$HcgPerson_initWithName$age$_super)(HcgPerson * self, SEL _cmd, NSString* aName, int anAge);

...

static HcgPerson* $HcgPerson_initWithName$age$_method(HcgPerson * self, SEL _cmd, NSString* aName, int anAge)
{
    NSLog(@"Hook Instance Method");
    return $HcgPerson_initWithName$age$_super(self, @selector(initWithName:age:), @"hzp", 30);
}

...

// 供宏接口 CHSuper_ 调用的函数指针,用于指向 +[HcgPerson personWithName:age:] 方法的原始实现
// 1.如果 +[HcgPerson personWithName:age:] 方法的原始实现存储在 HcgPerson 的元类对象中
//     则该函数指针指向 HcgPerson 的元类对象中的 +personWithName:age: 方法实现
// 2.如果 +[HcgPerson personWithName:age:] 方法的原始实现存储在 HcgPerson 的父元类对象中
//   则该函数指针指向闭包函数 $HcgPerson_personWithName$age$_closure
//   而闭包函数 $HcgPerson_personWithName$age$_closure 会负责调用 HcgPerson 的父元类对象中的 +personWithName:age: 方法实现
static HcgPerson* (*$HcgPerson_personWithName$age$_super)(id self, SEL _cmd, NSString* aName, int anAge);

...

static HcgPerson* $HcgPerson_personWithName$age$_method(id self, SEL _cmd, NSString* aName, int anAge)
{
    NSLog(@"Hook Class Method");
    return $HcgPerson_personWithName$age$_super(self, @selector(personWithName:age:), @"hcg", 20);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值