在iOS上防止反射(objc/runtime)



我正在研究一个处理敏感数据的静态库。使用库的开发人员不能在库上使用反射,这是必须的。

在Android上,我们通过与service s一起开发aar文件并将service运行到单独的进程中来解决问题;(当服务运行到另一个进程中时,开发人员不能使用反射),但我想知道iOS中是否存在类似的东西?

我们可以在一个单独的进程中执行静态库吗?如果不是,我们如何避免对静态库的反射?

例如:

        MyTestObject *obj = [[[myTestView alloc] init ];
        //===========================================   
        Class clazz = [obj class];
        u_int count;
        Ivar* ivars = class_copyIvarList(clazz, &count);
        NSMutableArray* ivarArray = [NSMutableArray arrayWithCapacity:count];
        for (int i = 0; i < count ; i++)
        {
            const char* ivarName = ivar_getName(ivars[i]);
            [ivarArray addObject:[NSString  stringWithCString:ivarName encoding:NSUTF8StringEncoding]];
        }
        free(ivars);
        objc_property_t* properties = class_copyPropertyList(clazz, &count);
        NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
        for (int i = 0; i < count ; i++)
        {
            const char* propertyName = property_getName(properties[i]);
            [propertyArray addObject:[NSString  stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
        }
        free(properties);
        Method* methods = class_copyMethodList(clazz, &count);
        NSMutableArray* methodArray = [NSMutableArray arrayWithCapacity:count];
        for (int i = 0; i < count ; i++)
        {
            SEL selector = method_getName(methods[i]);
            const char* methodName = sel_getName(selector);
            [methodArray addObject:[NSString  stringWithCString:methodName encoding:NSUTF8StringEncoding]];
        }
        free(methods);
        NSDictionary* classDump = [NSDictionary dictionaryWithObjectsAndKeys:
                                   ivarArray, @"ivars",
                                   propertyArray, @"properties",
                                   methodArray, @"methods",
                                   nil];
        NSLog(@"%@", classDump);
        //======================================================
        int v2 = [[obj valueForKey:@"testValue"] intValue];
        SEL s = NSSelectorFromString(@"wannatTestIt");
        [obj performSelector:s];

MyTestObject是一个类从我的图书馆。在第一行,我从这个类初始化一个对象。

在下一行中,我读取了类的变量、方法和属性列表,并将其记录下来。结果如下:

    {
    ivars =     (
        testValue
    );
    methods =     (
        printTestValue,
        wannatTestIt,
        "initWithFrame:"
    );
    properties =     (
    );
}

wannaTestIt是私有方法,testValue是私有变量。所以我希望使用库的开发人员不能访问它们。但是,由于标准库的用户可以获得名称,因此用户最终可以调用该方法来读取iVar的值。

我该如何预防?

如果你想完全"防止"反射,那么,你必须使用不同的语言。反射在Objective C中是一个关键的东西,不可能"阻止"或"禁用"它。

但是,您可以通过混淆这些运行时信息来降低其对研究人员的用处。例如,看看这个工具:https://github.com/Polidea/ios-class-guard。这只是一个例子。我和这个特殊的项目没有关系,你可以自由地选择一个不同的混淆器,或者自己写一个。

如果你需要的是限制反射到公共API,甚至公开私有方法和变量的数量(没有它们的实际名称)对你来说是不合适的,那么你别无选择,只能用另一种语言编写敏感代码。您可以使用Pimpl设计模式来实现您想要的。这样,您的类将只有公共方法和单个私有变量_impl(或类似的东西)。其中_impl是用c++(或Objective c++,如果你需要访问ObjC api)编写的实现类的实例,所有的公共方法都像代理一样。像这样:

- (NSInteger)computeSuperSensitiveStuffWithFoo:(Foo *)foo Bar:(Bar *)bar {
    return _impl->computeStuff(foo, bar);
}

这样,所有的私有数据和方法都将封装在MyClassImpl类中。如果你保持这样的类的声明和实现是私有的(即不分发MyClassImpl.h文件与你的库),并使用像c++这样的语言来实现它,那么你将实现你想要的。

还请注意,如果你选择Objective c++,那么MyClassImpl应该是一个c++类(用class关键字声明),而不是Objective C类(用@interface/@end块声明,并在@implementation/@end块内实现)。否则,你所有的私人数据无论如何都会被反射,但这需要研究人员采取一些额外的步骤。

相关内容

  • 没有找到相关文章

最新更新