擦除NSString的底层缓冲区的特殊问题

时间:2014-05-20 16:26:50

标签: ios objective-c

我正在使用黑客攻击和保护iOS应用程序(相关部分“Here”)中概述的技术来擦除NSString的基础缓冲区,如下所示

代码:

NSString *s = [NSString stringWithFormat:@"Hello"];
unsigned char *text = (unsigned char*)CFStringGetCStringPtr((CFStringRef)s, CFStringGetSystemEncoding());
if (text != NULL)
{
    memset(text, 0, [s length]);
}

这是有效的,除非字符串是某个值。

// The following crashes with EXC_ACCESS_ERROR on memset
NSString *s = [NSString stringWithFormat:@"No"];
NSString *s = [NSString stringWithFormat:@"Yes"];

// These work fine though
NSString *s = [NSString stringWithFormat:@"Hello"];
NSString *s = [NSString stringWithFormat:@"Do"];
NSString *s = [@"N" stringByAppendingString:@"o"];

看起来某些字符串不是在堆上创建的,而是通过使其指向只读字符串表进行优化,即使该字符串是在堆上创建的。

有没有人对这种行为有更深入的了解?

2 个答案:

答案 0 :(得分:1)

实际上,常量字符串不会在堆上创建并且位于只读内存中。这包括一些看起来像运行时但是编译时常量的例子,你的例子就是这样的陈述。

使用此语句片段,没有理由不使它成为编译时常量。

[NSString stringWithFormat:@"No"]

相当于:

@"No"

建议,提交请求安全字符串类的错误报告,我有。有几个已经提交,我被告知,如果有足够的(无论金额多少)是文件,它将实现它。

可以继承NSString,但这并不容易,但是你将控制实际的缓冲区,并且由于Apple改变了实现细节,它不应该受到可能的失败。我成功地做到了。

答案 1 :(得分:1)

NSString *s = [NSString stringWithFormat:@"No"];将优化为NSString *s = @"No";,因为格式中没有替换。分配文字将为您提供指向已加载二进制文件的只读文本段的指针。

NSString *s = [@"N" stringByAppendingString:@"o"];将在堆上创建一个新字符串并返回对它的引用。即使数据类型NSString是只读的,堆也是可读写的。

当您获得指向底层数据的CString指针时,它指向第一种情况下的只读数据,或者指向第二种情况下的读写数据。 memset将在只读内存上失败,但在读写时会成功。