美文网首页
怎么hook initialize方法

怎么hook initialize方法

作者: HiIgor | 来源:发表于2019-05-15 11:55 被阅读0次

#import <objc/runtime.h>
#import <UIKit/UIKit.h>


static inline BOOL isClassContainSel(Class class, SEL sel) {
    unsigned int count;
    
    Method *methodList = class_copyMethodList(class,&count);
    for (int i = 0; i < count; i++) {
        Method method = methodList[i];
        NSString *tempMethodString = [NSString stringWithUTF8String:sel_getName(method_getName(method))];
        if ([tempMethodString isEqualToString:NSStringFromSelector(sel)]) {
            return YES;
        }
    }
    return NO;
}

static inline void _hook_exchangeMethod(Class originalClass, SEL originalSel, Class replacedClass, SEL replacedSel){
    BOOL isContain = isClassContainSel(originalClass, originalSel);
    if (!isContain) {
        IMP imp = method_getImplementation(class_getInstanceMethod(originalClass, originalSel));
        if (!imp) {
            return;
        }
        class_addMethod(originalClass, originalSel, imp, nil);
    }
    
    Method originalMethod = class_getInstanceMethod(originalClass, originalSel);
    Method replacedMethod = class_getInstanceMethod(replacedClass, replacedSel);
    IMP replacedMethodIMP = method_getImplementation(replacedMethod);
    // 将样替换的方法往代理类中添加, (一般都能添加成功, 因为代理类中不会有我们自定义的函数)
    BOOL didAddMethod =
    class_addMethod(originalClass,
                    replacedSel,
                    replacedMethodIMP,
                    method_getTypeEncoding(replacedMethod));
    
    if (didAddMethod) {// 添加成功
        // 获取新方法在代理类中的地址
        Method newMethod = class_getInstanceMethod(originalClass, replacedSel);
        // 交互原方法和自定义方法
        method_exchangeImplementations(originalMethod, newMethod);
    }else{// 如果失败, 则证明自定义方法在代理方法中, 直接交互就可以
        method_exchangeImplementations(originalMethod, replacedMethod);
    }
}


typedef void (* _MFIMP)(id, SEL, ...);
typedef void (* _MFNIMP)(void);
@implementation UIViewControllerMethodHooker


BOOL MFObjCIsKindOf(Class cls, Class other)
{
    while (cls != Nil)
    {
        if (cls == other)
        {
            return YES;
        }
        cls = class_getSuperclass(cls);
    }
    return NO;
}

+ (void)hook {
    NSString *executablePath = [[NSBundle mainBundle] executablePath];
    unsigned int classCount = 0;
    const char **classNames = objc_copyClassNamesForImage([executablePath UTF8String], &classCount);
    NSMutableArray *mutableArray = [NSMutableArray array];
    for (int i = 0; i < classCount; i++) {
        NSString *str = [NSString stringWithUTF8String:(classNames[i])];
        [mutableArray addObject:str];
    }

    SEL sel = NSSelectorFromString(@"__mf_hook_after_initialize_");
    Class VCClazz = [UIViewController class];
    Class VCMeta = object_getClass(VCClazz);
    BOOL containss = isClassContainSel(VCMeta, sel);
    if (!containss) {
        IMP imps = method_getImplementation(class_getClassMethod(self, @selector(__replace_initialize_implementation)));
        if (!imps) return;
        class_addMethod(VCMeta, sel, imps, nil);
    }
    
    NSArray *allControllers = [mutableArray copy];
    [allControllers enumerateObjectsUsingBlock:^(NSString * _Nonnull className, NSUInteger idx, BOOL * _Nonnull stop) {
        
        SEL sel_initialize = NSSelectorFromString(@"initialize");
        Class meta = object_getClass(NSClassFromString(className));
        Class clazz = NSClassFromString(className);
        
        if (MFObjCIsKindOf(clazz, VCClazz)) {
            BOOL contains = isClassContainSel(meta, sel_initialize);
            if (!contains) {
                IMP imp = method_getImplementation(class_getClassMethod(self, sel_initialize));
                if (!imp) return;
                class_addMethod(meta, sel_initialize, imp, nil);
            }
            
            // 经过上面的操作之后 必定在本类中有一个 initialize 方法的实现
            Method iMethod = class_getInstanceMethod(meta, sel_initialize);
            _MFIMP initialize0 = (_MFIMP)method_getImplementation(iMethod);
            
            Method newMethod = class_getClassMethod(VCMeta, sel);
            _MFIMP hook = (_MFIMP)method_getImplementation(newMethod);
            
            dispatch_block_t block = ^() {
                initialize0(clazz, sel_initialize);
                hook(clazz, sel);
            };
            
            _MFNIMP p = (_MFNIMP )imp_implementationWithBlock(block);
            method_setImplementation(iMethod, p);
            [clazz description];
            unsigned int count;
            NSMutableArray *methods = [NSMutableArray array];
            Method *methodList = class_copyMethodList(meta, &count);
            for (int i = 0; i < count; i++) {
                Method method = methodList[i];
                NSString *tempMethodString = [NSString stringWithUTF8String:sel_getName(method_getName(method))];
                [methods addObject:tempMethodString];
            }
            
            NSLog(@"%@__%@", NSStringFromClass(meta), methods);
        }
    }];
}

+ (void)__replace_initialize_implementation {
    // 添加你的initialize方法hook代码
}

+ (void)initialize {
    NSLog(@"_______________ hook添加的实现 %@", [self class]);
}

@end

相关文章

网友评论

      本文标题:怎么hook initialize方法

      本文链接:https://www.haomeiwen.com/subject/dzfpaqtx.html