C++逆向学习(一) string
字数 1148 2025-08-05 11:39:26
C++逆向学习:string类的内存布局与扩容机制分析
1. string类的基本内存布局
在Visual Studio环境下,定义一个string类并存储字符串"abcd"时,其内存布局如下:
- size:当前字符串长度(4字节)
- capacity:最大容量(通常比size大)
- allocator:空间配置器
- 字符数据:以
\x00结尾的连续内存
示例内存视图:
[allocator][size][capacity][...][a][b][c][d][\x00]
2. string的扩容机制
通过实验观察string的capacity增长规律:
string str;
for(int i=0; i<100; i++) {
str += 'a';
cout << "size: " << str.size() << " capacity: " << str.capacity() << endl;
}
观察到的capacity变化序列:
15 → 31 → 47 → 70 → 105
扩容特点:
- 初始容量为15(二进制1111)
- 第一次扩容到31(二进制11111)
- 后续扩容按约1.5倍增长
3. 逆向工程视角下的string操作
3.1 基本操作分析
测试程序1:
string input;
cin >> input;
for(int i=0; i<3; i++) input += 'a';
for(int i=0; i<3; i++) input.append("12345abcde");
cout << input;
IDA逆向观察:
- 当
size > capacity时调用Reallocate_xxx函数 - 直接追加字符时:
*(_WORD*)&str_addr[_size] = 97(同时写入\x00) - 追加长字符串时使用
memmove_0函数 - 末尾总是添加
\x00:v9[10] = 0
3.2 字符串连接操作
测试程序2:
string input1, input2, result;
cin >> input1 >> input2;
result = input1 + input2;
cout << result;
g++编译后的逻辑:
- 调用
operator+进行连接 - 使用
operator=赋值 - 输出结果
3.3 基于范围的for循环
测试程序3:
string input1, input2;
cin >> input1 >> input2;
for(auto c : input2) input1 += c;
cout << input1;
逆向分析要点:
- 使用迭代器
begin和end - 通过
operator!=判断循环结束 - 使用
operator+=追加字符 - 使用
operator++移动迭代器
4. 逆向分析技巧总结
- 动态调试:使用Visual Studio等工具观察内存变化(红色表示刚改变的值)
- 静态分析:
- 识别扩容判断逻辑(size vs capacity)
- 注意内存操作函数(memmove等)
- 观察字符串终止符的处理
- 命名规范:在IDA中重命名变量提高可读性
- 编译器差异:
- g++生成的代码通常更简洁
- Visual Studio生成的代码可能包含更多内部细节
5. 关键点备忘
- string内部总是以
\x00结尾 - capacity的增长策略:
- 初始15
- 后续约1.5倍增长
- 小字符追加可能使用WORD写入(同时设置
\x00) - 大字符串追加使用memmove类函数
- 基于范围的for循环转换为迭代器操作
6. 进一步研究方向
- 不同编译器(g++ vs MSVC)的实现差异
- 空间配置器(allocator)的详细工作机制
- reallocation函数的具体实现
- 异常处理机制在string操作中的表现
通过深入理解string类的内部实现,可以更有效地分析C++逆向工程中的字符串相关操作,提高漏洞分析和CTF解题的效率。