NSString内容擦除相关

作者: ncnocure | 来源:发表于2017-01-04 17:29 被阅读80次

    测试结论

    1. 常量字符串在正式赋值之前就存在,会保留到整个程序运行期间,无法清除。
    2. 在调用函数结束的时候NSString字符串才会自动清空,之前都能在内存中搜到。
    3. 非常量字符串可以通过念茜的CFStringGetCStringPtr的方式清空。(念茜方法详情
      只想了解怎么清除NSString的朋友看到这里就够了,下面是以上结论的测试过程。

    引子

    最近手头的iOS项目对安全性要求非常高。
    某个敏感数据使用NSString存储,非常敏感,必须即用即清理。NSString对象会通过ARC自动释放,而并没有显式的清除方法,所以并不能确定自动释放之后内容是否自动清除。
    找到念茜博主提供的NSString字符串清除。
    为了验证方法有效性,我直接使用念茜的代码试验

    _text = @"12dfavkasie";  
    memset((__bridge voidvoid *)(_text), 0, _text.length - 1);  
    NSString *myString = [[NSString alloc]initWithFormat:@"information"];  
    NSLog(@"Origal text : %@ \n",myString);  //断点1
    

    “Origal text :”没有显示字符串内容,但是在断点1进行内存扫描依然能搜到一个12dfavkasie。所以为了验证该方法有效性,需要解决如下几个问题。

    1. 断点1搜到的字符串是常量字符串还是NSString没擦除的结果。
    2. NSString是否在最后一次调用的时候自动擦除。
    3. 使用非常量字符串来排除常量字符串干扰,使用这种方法依然能够清除就能证明该方法可以有效清除NSString。

    首先建立可以进行内存扫描的iOS环境。

    iOS扫描内存过程

    1. 使用盘古越狱将手头iPhone 4s iOS 7.1.2 越狱。
    2. 在Cydia上下载OpenSSH。
    3. 在Cydia上添加源:http://grantdouglas.co.uk 下载 memscan。
    4. 在MAC上使用SSH连接OpenSSH。
      ssh root@192.168.2.199
      iPhone手机默认密码为 :alpine
      RA手机,修改为:Rongan1234
    5. 运行iOS中间件工具。
    6. 用工具名字, 获取iOS工具PID如下:
      ps-ax | grep SignTool
      ps-ax | grep Mgr
    7. 获取的PID对应进程的内存。
      memscan -p 64685 -d -o out4.bin
    8. 搜索获取内存中的数据
      grep -c 12345677 out4.bin
      得到数据为0,则内存中找不到该字符串。
      得到数据不为0,使用grep -a查看该字符串出现的具体位置。

    测试过程

    编写用于测试的程序验证如下三个问题:

    1. 断点1搜到的字符串是常量字符串还是NSString没擦除的结果。
      通过程序1确定常量字符串的特性。
    2. NSString是否在最后一次调用的时候自动擦除。
      建立两个NSString,确定两个字符串清除的时间。
    3. 使用非常量字符串来排除常量字符串干扰,使用这种方法依然能够清除就能证明该方法可以有效清除NSString。

    常量字符串是否一直存在?

        NSString *testStr = [[NSString alloc] initWithFormat:@"14642334"];
        NSString *testStr1 = [[NSString alloc] initWithFormat:@"sdfsafd"];
        NSString *testStr2 = [[NSString alloc] initWithFormat:@"dsfdsafd"];
        NSString *testStr3 = [[NSString alloc] initWithFormat:@"dncmviwmaf"];
        
        NSLog(@"test1");
        NSLog(@"test2");
        NSLog(@"test1");
        NSLog(@"test2");
        [testStr compare:testStr1];
        [testStr compare:testStr2];
        [testStr compare:testStr3];
    

    在该段代码运行之前,用memscan获取内存,用grep -C 10 14642334 获取该字符串附近的上下文,结果如下。

    lengthOfBytesUsingEncoding:
    getCString:maxLength:encoding:
    keyEnumerator
    nextObject
    test
    14642334
    sdfsafd
    dsfdsafd
    dncmviwmaf
    test1
    test2
    

    当该函数运行结束之后,查找14642334,结果一样。

    结论

    常量字符串特点如下:

    1. 集中存储在一个位置。
    2. 无论代码有没有运行到常量字符串所在位置,内存中都会包含这个字符串的内容。
      所以之前念茜代码最后搜到的测试字符串应该是常量字符串。

    NSString是否自动清除

    测试代码:

        unsigned char testByteStr[10];//断点0
        testByteStr[0] = '1';//14642334
        testByteStr[1] = '4';
        testByteStr[2] = '6';
        testByteStr[3] = '4';
        testByteStr[4] = '2';
        testByteStr[5] = '3';
        testByteStr[6] = '3';
        testByteStr[7] = '4';
        NSString *testStr = [[NSString alloc] initWithBytes:testByteStr length:8 encoding:NSASCIIStringEncoding];
        testByteStr[0] = '4';//47951438
        testByteStr[1] = '7';
        testByteStr[2] = '9';
        testByteStr[3] = '5';
        testByteStr[4] = '1';
        testByteStr[5] = '4';
        testByteStr[6] = '3';
        testByteStr[7] = '8';
        NSString *testStr2 =[[NSString alloc] initWithBytes:testByteStr length:8 encoding:NSASCIIStringEncoding];
        memset(testByteStr, 0, 8);
        NSLog(@"test");//断点1
        [testStr compare:testStr2];
        NSLog(@"test");//断点2
        NSLog(@"%l",testStr.length);
        NSLog(@"test");//断点3
        testStr = @"123";
        NSLog(@"test");//断点4
    

    结果和分析:
    断点0时,14642334出现0次,47951438出现0次。
    断点1时,14642334出现1次,47951438出现1次。
    testByteStr已经用memset清空,所以内存中唯一的14642334是testStr。唯一的47951438是testStr2。
    断点2时,14642334出现1次,47951438出现1次。
    之后testStr2最后一次调用在断点2前,然而testStr2依然能搜到。所以NSString并没有在最后一次调用时自我清除。
    断点3时,14642334出现1次,47951438出现1次。
    断点4时,14642334出现1次,47951438出现1次。
    断点5为该函数执行结束之后的断点,14642334出现0次,47951438出现0次。

    结论

    NSString只会在所在函数段结束的时候自动清空。

    排除常量字符串干扰,擦除字符串

        unsigned char testByteStr[10];//断点0
        testByteStr[0] = '1';//14642334
        testByteStr[1] = '4';
        testByteStr[2] = '6';
        testByteStr[3] = '4';
        testByteStr[4] = '2';
        testByteStr[5] = '3';
        testByteStr[6] = '3';
        testByteStr[7] = '4';
        NSString *testStr = [[NSString alloc] initWithBytes:testByteStr length:8 encoding:NSASCIIStringEncoding];
        memset(testByteStr , 0 , 8);
        char *str = malloc(9*sizeof(char));//断点1
        str = (char *)CFStringGetCStringPtr((CFStringRef)testStr,CFStringGetSystemEncoding());
        NSLog(@"test");//断点2
        memset(str , 0 , 7);
        NSLog(@"test");//断点3
    

    在Xcode里运行测试程序,在程序运行到断点0,1,2,3的时候使用memscan扫描14642334的数量。
    断点0结果:0
    断点1结果:1
    testByteStr已经清空。内存中唯一14642334是testStr。
    断点2结果:1
    执行CFStringGetCStringPtr之后,内存中依然只有一个14642334。而之前已经试验过testStr字符串在函数结束之后才会清空,所以str指向testStr存储14642334的内存位置。
    断点3结果:0
    清空str之后,testStr也清空了。

    结论

    念茜的方法可以有效清空NSString。

    测试结论

    1. 常量字符串在正式赋值之前就存在,会保留到整个程序运行期间,无法清除。
    2. 在调用函数结束的时候NSString字符串才会自动清空,之前都能在内存中搜到。
    3. 非常量字符串可以通过CFStringGetCStringPtr的方式清空。

    相关文章

      网友评论

        本文标题:NSString内容擦除相关

        本文链接:https://www.haomeiwen.com/subject/umukvttx.html