- 问题背景
- 解决方法
- 总结
问题背景
在iOS逆向过程中,尽管可以根据class-dump获取应用相关头文件,但是如果成员变量没有声明为@property
,就无法获取到这部分变量的实例对象。
解决方法
在正向开发中,有一种方法可以根据实例对象获取到变量名。参考IOS高级教程2:反射根据变量的引用获取变量名。可以写出如下C风格的代码:
#import <objc/runtime.h>
/**
* 根据成员变量的实例对象获取在类中对应的变量名
*
* @param self 类自身的实例对象id
* @param instance 类中变量的实例对象id
*
* @return 实例对象的变量名
*/
NSString *getNameWithInstance(id self, id instance)
{
unsigned int numIvars = 0;
NSString *key=nil;
Ivar * ivars = class_copyIvarList([self class], &numIvars);
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = ivars[i];
const char *type = ivar_getTypeEncoding(thisIvar);
NSString *stringType = [NSString stringWithCString:type encoding:NSUTF8StringEncoding];
if (![stringType hasPrefix:@"@"]) {
continue;
}
if ((object_getIvar(self, thisIvar) == instance)) {
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
break;
}
}
free(ivars);
return key;
}
那么反过来,如何根据变量名获取实例对象呢。有如下代码:
#import <objc/runtime.h>
/**
* 根据成员变量在类中对应的变量名获取实例对象
*
* @param self 类自身的实例对象id
* @param name 成员变量在类中对应的变量名
*
* @return 变量名对应的实例对象
*/
id getInstanceWithName(id self, NSString* name)
{
unsigned int numIvars = 0;
NSString *key=nil;
id ret;
Ivar * ivars = class_copyIvarList([self class], &numIvars);
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = ivars[i];
const char *type = ivar_getTypeEncoding(thisIvar);
NSString *stringType = [NSString stringWithCString:type encoding:NSUTF8StringEncoding];
if (![stringType hasPrefix:@"@"]) {
continue;
}
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
if([key isEqualToString:name])
{
ret = (object_getIvar(self, thisIvar));
break;
}
}
free(ivars);
return ret;
}
总结
这些技巧,要靠看苹果官方文档。或者在网络上善于发现已有的解决方法,并加以修改。