【iOS安全】NSTaggedPointerString和__NSCFString
概述
简而言之 :
- NSTaggedPointerString和__NSCFString都是NSString类型。
- NSTaggedPointerString善于存短字符串,__NSCFString善于存一般或长字符串
- 在iOS运行时,系统会根据字符串长度自动在NSTaggedPointerString和__NSCFString之间进行转换,这种转换对于开发者来说通常是透明的。
今天测试一款app时,原本观测到的是NSTaggedPointerString的某函数被调用,自己给值做调用时却hook不到了,细究之下是我给的值太长了,变成了__NSCFString,所以hook -[NSTaggedPointerString xxx:]就hook不到了。
不过frida-trace很有趣的一点是,如果hook __NSCFString,就既可以同时hook到__NSCFString的和NSTaggedPointerString的;如果hook NSTaggedPointerString,却不能hook到NSTaggedPointerString的函数。
1. NSTaggedPointerString
- 定义和原理:NSTaggedPointerString是一种字符串存储优化技术。在Objective - C环境下,当字符串的内容比较短且可以用指针的额外位来存储时,系统会使用NSTaggedPointerString来存储字符串。它利用了指针本身的一些位来直接存储字符串的数据,而不是像普通对象那样通过内存分配和引用的方式存储在堆上。这种方式可以提高性能,减少内存开销,因为它避免了复杂的内存分配和对象初始化过程。
- 示例代码(Objective - C):
NSString *shortString = @"Hello";
,当这个短字符串被创建时,很有可能是以NSTaggedPointerString的形式存储的。
2. __NSCFString
- 定义和原理:__NSCFString是NSString的一种具体的类簇实现。在Foundation框架中,NSString是一个抽象类,它有多种具体的实现类,__NSCFString就是其中之一。它通常用于存储和管理字符串数据,当字符串的内容不符合NSTaggedPointerString的存储条件(例如字符串较长)时,可能会使用__NSCFString来存储。__NSCFString对象存储在堆内存中,通过引用计数等机制来管理内存。
- 示例代码(Objective - C):
NSString *longString = @"This is a very long string that is likely to be stored as __NSCFString";
,对于这种较长的字符串,很可能是以__NSCFString的形式存储的。
3. 两者关系
- 存储方式和性能差异:
- NSTaggedPointerString主要用于存储短字符串,它通过利用指针本身的位来存储字符串内容,性能较好,内存占用少。而__NSCFString用于存储一般情况或者长字符串,存储在堆内存中,相对来说内存管理成本更高,但能够处理更复杂的字符串情况。
- 继承和类型兼容性:
- 从类型系统的角度看,NSTaggedPointerString和__NSCFString都可以被看作是NSString类型。在Objective - C和Swift中,当你使用NSString类型的变量来操作这两种类型的字符串时,编译器和运行时会根据实际情况正确处理它们。例如,你可以将一个NSTaggedPointerString或者__NSCFString赋值给一个NSString类型的变量,并且可以调用NSString的方法来处理它们。
NSString *string1 = @"Short"; // 可能是NSTaggedPointerString
NSString *string2 = @"This is a long string"; // 可能是__NSCFString
[string1 length]; // 正确调用NSString的方法,无论string1是NSTaggedPointerString还是__NSCFString
[string2 uppercaseString]; // 同样正确调用NSString的方法
- 转换关系:
- 在运行时,系统会根据字符串的长度和内容自动在NSTaggedPointerString和__NSCFString之间进行转换(这种转换对于开发者来说通常是透明的)。
当一个短字符串被频繁操作后长度增加,可能会从NSTaggedPointerString转换为__NSCFString;反之,当一个长字符串经过一系列操作后长度变短并且符合NSTaggedPointerString的存储条件,也可能会发生转换。不过这种转换是由系统自动管理的,开发者一般不需要手动干预。
- 在运行时,系统会根据字符串的长度和内容自动在NSTaggedPointerString和__NSCFString之间进行转换(这种转换对于开发者来说通常是透明的)。