Runtime中的property_getAttributes和property_getName区别

前言

进来项目由于后台人员的离职缺失, 导致后台进度变慢, 接口也给的慢了, 界面早就写好了, 等接口的过程中, 研究了一下逆向开发, 刚刚接触, 好像发现了一个新世界的大门, 甚是欢喜, 也发现了自身知识储备的不足, 努力学习中! 下面讲不间断记录遇到的一些问题, 以及一些解决思路, 供大家参考, 如有错误欢迎指正!

正文

由于逆向iOS平台需要越狱设备等硬件因素, 而本人有缺少一台越狱手机, 于是瞄上了Mac端, 比较直观!

Hopper Disassember V4 中反编译能得到类文件和方法名, 通过类名, 方法名判断开发者意图; 得到类名, 第一反应就是通过类名获取到这个类的方法属性名称, 得到名称, 还想得到数据类型等信息, 就引入了下面的问题, Runtime为我们提供了方法, 可以得到类的属性名称, 代码如下:

1. 上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void kk_LogClassPropertyList(Class cls) {
unsigned int count;
objc_property_t *propertyList = class_copyPropertyList(cls, &count);
for (int i = 0; i < count; i++) {
objc_property_t proprety = propertyList[i];
const char *getName = property_getName(proprety);
NSString *name1 = [NSString stringWithCString:getName encoding:NSUTF8StringEncoding];

const char *getAtt = property_getAttributes(proprety);
NSString *name2 = [NSString stringWithCString:getAtt encoding:NSUTF8StringEncoding];

NSLog(@"property_getName: -----> %@", name1);
NSLog(@"property_getAttributes: -----> %@", name2);

}
}

如上代码, 我们可以看到

class_copyPropertyList //属性列表

property_getName //获取属性名字

property_getAttributes //获取属性名称特性

打印结果如下图:

2. 看文档

如图, 可以很直观的看出来区别, property_getName只打印出了属性名字, 而property_getAttributes打印的信息更多一点, 你可能要问了, 那些T, TQ等等都是写什么意思, 我也带着疑问, 就来看了官方文档;打开Dash, 搜索property_getAttributes, 仔细查阅, 发现如下结果:

再接着看:


这个就一清二楚了, 很直观了, 例如Td(double类型), Tf(float类型)等, 根据你的需要查阅就好了!

3. 看源码

知道了 property_getAttributesproperty_getName的用途, 又开始好奇他的实现, 于是上源码, 下载最新的objc4-723, 打开, 并且搜索property_getAttributes:

1
2
3
4
5
6
7
8
9
const char *property_getName(objc_property_t prop)
{
return prop->name;
}

const char *property_getAttributes(objc_property_t prop)
{
return prop->attributes;
}

nameattributes分别指向了property_t结构体:

1
2
3
4
struct property_t {
const char *name;
const char *attributes;
};

搜索发现nameattributes赋值分别为:

1
2
3
property_t& prop = plist->get(plist->count++);
prop.name = strdupIfMutable(name)
prop.attributes = copyPropertyAttributeString(attrs, count);

copyPropertyAttributeString的实现为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const char *
copyPropertyAttributeString(const objc_property_attribute_t *attrs,
unsigned int count)
{
char *result;
unsigned int i;
if (count == 0) return strdup("");

#if DEBUG
// debug build: sanitize input
for (i = 0; i < count; i++) {
assert(attrs[i].name);
assert(strlen(attrs[i].name) > 0);
assert(! strchr(attrs[i].name, ','));
assert(! strchr(attrs[i].name, '"'));
if (attrs[i].value) assert(! strchr(attrs[i].value, ','));
}
#endif

size_t len = 0;
for (i = 0; i < count; i++) {
if (attrs[i].value) {
size_t namelen = strlen(attrs[i].name);
if (namelen > 1) namelen += 2; // long names get quoted
len += namelen + strlen(attrs[i].value) + 1;
}
}

result = (char *)malloc(len + 1);
char *s = result;
for (i = 0; i < count; i++) {
if (attrs[i].value) {
size_t namelen = strlen(attrs[i].name);
if (namelen > 1) {
s += sprintf(s, "\"%s\"%s,", attrs[i].name, attrs[i].value);
} else {
s += sprintf(s, "%s%s,", attrs[i].name, attrs[i].value);
}
}
}

// remove trailing ',' if any
if (s > result) s[-1] = '\0';

return result;
}

copyPropertyAttributeString第一个参数也是一个结构体指针, 如下:

1
2
3
4
typedef struct {
const char * _Nonnull name; /**< The name of the attribute */
const char * _Nonnull value; /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;

name赋值:

1
2
3
4
5
6
7
8
9
static inline char *
strdupIfMutable(const char *str) {
size_t size = strlen(str) + 1;
if (_dyld_is_memory_immutable(str, size)) {
return (char *)str;
} else {
return (char *)memdup(str, size);
}
}

strdupIfMutable传入的参数为一个char型字符, 如果在内存中存在, 就返回, 如果不存在, 释放那块地址空间, 然后memcpy()函数从src内存中拷贝n个字节到dest内存区域,但是源和目的的内存区域不能重叠。

总结

小问题, 引出大思考, 底层还是要了解的, 否则只能抓瞎, 你觉得呢?

看到这就是真爱,打个赏呗~