iOS使用Runtime和反射机制获取私有方法和私有属性以及替换任意方法

版权声明:本文为博主原创文章,未经博主允许可以转载,但转载时请附上原文地址: https://blog.csdn.net/youshaoduo/article/details/81702005

本文旨在获取重签名包里面对象的属性和方法,也就是说在引用不到该类的头文件的情况下,获取这些方法以及替换这些方法。至于这些类名可以通过IDA分析出来,也可以通过class-dump逆向出头文件(仅限objective-C工程)。

替换任意方法(感谢群内大佬Sun提供。。):

/**
 替换任意方法(包括代理方法)

 @param originalClass 原先的类
 @param originalSel 原先的方法
 @param replacedClass 新的类(这是最强大的地方:可以是任意的类,不需要是原先类的category或者子类)
 @param replacedSel 新的方法
 @param orginReplaceSel 如果实现了代理方法,那么这里要填上代理方法,如果没实现,这里填originalSel
 */
static void bgl_exchangeMethod(Class originalClass, SEL originalSel, Class replacedClass, SEL replacedSel, SEL orginReplaceSel){
    // 原方法
    Method originalMethod = class_getInstanceMethod(originalClass, originalSel);
    Method replacedMethod = class_getInstanceMethod(replacedClass, replacedSel);
    // 如果没有实现 delegate 方法,则手动动态添加
    if (!originalMethod) {
        Method orginReplaceMethod = class_getInstanceMethod(replacedClass, orginReplaceSel);
        BOOL didAddOriginMethod = class_addMethod(originalClass, originalSel, method_getImplementation(orginReplaceMethod), method_getTypeEncoding(orginReplaceMethod));
        if (didAddOriginMethod) {
            NSLog(@"did Add Origin Replace Method");
        }
        return;
    }
    // 向实现 delegate 的类中添加新的方法
    // 这里是向 originalClass 的 replaceSel(@selector(replace_webViewDidFinishLoad:)) 添加 replaceMethod
    BOOL didAddMethod = class_addMethod(originalClass, replacedSel, method_getImplementation(replacedMethod), method_getTypeEncoding(replacedMethod));
    if (didAddMethod) {
        // 添加成功
        NSLog(@"class_addMethod_success --> (%@)", NSStringFromSelector(replacedSel));
        // 重新拿到添加被添加的 method,这里是关键(注意这里 originalClass, 不 replacedClass), 因为替换的方法已经添加到原类中了, 应该交换原类中的两个方法
        Method newMethod = class_getInstanceMethod(originalClass, replacedSel);
        // 实现交换
        method_exchangeImplementations(originalMethod, newMethod);
    }else{
        // 添加失败,则说明已经 hook 过该类的 delegate 方法,防止多次交换。
        NSLog(@"Already hook class --> (%@)",NSStringFromClass(originalClass));
    }
}

获取一个类的所有属性以及类型:

+ (NSDictionary *)getIvarList:(NSObject *)obj {
    NSMutableDictionary * a = [[NSMutableDictionary alloc] init];
    unsigned  int count = 0;
    Ivar *members = class_copyIvarList([obj class], &count);

    for (int i = 0; i < count; i++)
    {
        Ivar var = members[i];
        const char *memberAddress = ivar_getName(var);
        const char *memberType = ivar_getTypeEncoding(var);
        [a setValue:[NSString stringWithUTF8String:memberType] forKey:[NSString stringWithUTF8String:memberAddress]];
        //memberAddress属性名  memberType属性的类型
        NSLog(@"%s  %s", memberAddress, memberType);
    }
    return a;
}

获取一个对象的属性内容并修改(这里需要配合交换方法使用,因为必须获取到该对象,才能取出里面的内容,代码中的self都代表该对象):

Ivar ivar1 = class_getInstanceVariable([self class], "_reqParam");
if (object_getIvar(self, ivar1)) {
    //取出_reqParam的内容。这个可以通过上面的方法看到名称和类型。
    NSMutableDictionary * dic = (NSMutableDictionary *)object_getIvar(self, ivar1);
    NSLog(@"NSMutableDictionaryIvar: %@", dic);
    if ([dic valueForKey:@"factor"] && [dic valueForKey:@"newMobileId"] && [dic objectForKey:@"password"]) {
        //把dic的内容修改一下
        [dic setValue:@"10.0.2" forKey:@"mobileOS"];
    }
    object_setIvar(self, ivar1, dic);
}

获取所有方法:

+ (void)getMethods:(NSObject *)object {
    unsigned int count = 0;
    //所有在.m文件显式实现的方法都会被找到
    Method *mets = class_copyMethodList([object class], &count);
    for(int i=0;i<count;i++){
        NSString *str = [NSString stringWithCString:method_getTypeEncoding(mets[i]) encoding:NSUTF8StringEncoding];
        SEL sel = method_getName(mets[i]);
        NSString *name = [NSString stringWithCString:sel_getName(sel) encoding:NSUTF8StringEncoding];
        NSLog(@"方法名:%@\n属性:%@",name,str);
    }
}

猜你喜欢

转载自blog.csdn.net/youshaoduo/article/details/81702005