防止 iOS 上的反射 (objc/runtime)
prevent reflection (objc/runtime) on iOS
我正在开发一个处理敏感数据的静态库。使用库的开发者必须不能在库上使用反射。
在 Android 上,我们通过将 service
和 运行 的 service
开发到单独的进程中的 aar
文件来解决问题;(当该服务 运行 进入另一个进程,然后开发人员无法使用反射)但我想知道 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
是我图书馆的 class。在第一行中,我从 class.
初始化了一个对象
在下一行中,我读取了 class 的变量、方法和 属性 列表并将其记录下来。这是结果:
{
ivars = (
testValue
);
methods = (
printTestValue,
wannatTestIt,
"initWithFrame:"
);
properties = (
);
}
wannaTestIt
是私有方法,testValue
是私有变量。所以我希望使用该库的开发人员无法访问它们。但是,由于库的使用者可以获取到名称,所以使用者最终可以调用该方法来读取iVar的值。
我怎样才能避免这种情况?
如果你想完全"prevent"反思那么,好吧,你必须使用不同的语言。反射是 Objective C 中的关键,"block" 或 "disable" 不可能。
但是,您可以通过混淆来使这个 运行 时间的信息对研究人员的用处大大降低。例如,看看这个工具:https://github.com/Polidea/ios-class-guard。这只是一个例子。我与这个特定项目无关,您可以自由选择不同的混淆器或编写自己的混淆器。
如果您需要的是将反射限制为仅 public API 甚至公开 一些 私有方法和 ivar(没有它们的实际名称) ) 对你来说不好那么你别无选择,只能用不同的语言编写你的敏感代码。您可以使用 Pimpl 设计模式来实现您想要的。这样,您的 classes 将只有 public 方法和一个私有 ivar _impl
(或类似的东西)。其中 _impl
是用 C++ 编写的实现 class 的一个实例(或者 Objective C++ 如果您需要访问 ObjC APIs)和所有 public 方法就像一个代理。像这样:
- (NSInteger)computeSuperSensitiveStuffWithFoo:(Foo *)foo Bar:(Bar *)bar {
return _impl->computeStuff(foo, bar);
}
这样,您所有的私有数据和方法都将封装在 MyClassImpl
class 中。如果您将此类 class 的声明和实现保密(即不要将 MyClassImpl.h
文件与您的库一起分发)并使用像 C++ 这样的语言来实现它,那么您将实现您想要的。
另请注意,如果您选择 Objective C++,则 MyClassImpl
应该是 C++ class(使用 class
关键字声明)而不是 Objective C class(用 @interface
/@end
块声明并在 @implementation
/@end
块内实现)。否则,无论如何您的所有私人数据都可用于反射,但需要研究人员执行几个额外的步骤。
我正在开发一个处理敏感数据的静态库。使用库的开发者必须不能在库上使用反射。
在 Android 上,我们通过将 service
和 运行 的 service
开发到单独的进程中的 aar
文件来解决问题;(当该服务 运行 进入另一个进程,然后开发人员无法使用反射)但我想知道 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
是我图书馆的 class。在第一行中,我从 class.
在下一行中,我读取了 class 的变量、方法和 属性 列表并将其记录下来。这是结果:
{
ivars = (
testValue
);
methods = (
printTestValue,
wannatTestIt,
"initWithFrame:"
);
properties = (
);
}
wannaTestIt
是私有方法,testValue
是私有变量。所以我希望使用该库的开发人员无法访问它们。但是,由于库的使用者可以获取到名称,所以使用者最终可以调用该方法来读取iVar的值。
我怎样才能避免这种情况?
如果你想完全"prevent"反思那么,好吧,你必须使用不同的语言。反射是 Objective C 中的关键,"block" 或 "disable" 不可能。
但是,您可以通过混淆来使这个 运行 时间的信息对研究人员的用处大大降低。例如,看看这个工具:https://github.com/Polidea/ios-class-guard。这只是一个例子。我与这个特定项目无关,您可以自由选择不同的混淆器或编写自己的混淆器。
如果您需要的是将反射限制为仅 public API 甚至公开 一些 私有方法和 ivar(没有它们的实际名称) ) 对你来说不好那么你别无选择,只能用不同的语言编写你的敏感代码。您可以使用 Pimpl 设计模式来实现您想要的。这样,您的 classes 将只有 public 方法和一个私有 ivar _impl
(或类似的东西)。其中 _impl
是用 C++ 编写的实现 class 的一个实例(或者 Objective C++ 如果您需要访问 ObjC APIs)和所有 public 方法就像一个代理。像这样:
- (NSInteger)computeSuperSensitiveStuffWithFoo:(Foo *)foo Bar:(Bar *)bar {
return _impl->computeStuff(foo, bar);
}
这样,您所有的私有数据和方法都将封装在 MyClassImpl
class 中。如果您将此类 class 的声明和实现保密(即不要将 MyClassImpl.h
文件与您的库一起分发)并使用像 C++ 这样的语言来实现它,那么您将实现您想要的。
另请注意,如果您选择 Objective C++,则 MyClassImpl
应该是 C++ class(使用 class
关键字声明)而不是 Objective C class(用 @interface
/@end
块声明并在 @implementation
/@end
块内实现)。否则,无论如何您的所有私人数据都可用于反射,但需要研究人员执行几个额外的步骤。