Windows逆向工程入门之字符串类型解析与拓展
- 公开视频 -> 链接点击跳转公开课程
- 博客首页 -> 链接点击跳转博客主页
目录
1. 字符串类型
1.1 字符串类型分类
1.1.1 C风格字符串 (char*)
1.1.2 宽字符字符串 (wchar_t*)
1.1.3 C++标准字符串
1.2 字符串表示
1.2.1 字符串常量
1.2.2 宽字符串常量
2. 字符串处理函数
2.1 字符串长度
2.2 字符串复制
2.3 字符串比较
2.4 字符串连接
2.5 字符或子字符串搜索
3. 字符串存储
3.1 静态存储
3.2 动态存储
4. 扩展知识点
4.1 防止字符串解析漏洞
4.2 字符串混淆技术
1. 字符串类型
Windows程序对字符串的操作包括ASCII和Unicode格式的处理,C与C++程序中主要使用以下几种字符串类型。
1.1 字符串类型分类
1.1.1 C风格字符串 (char*
)
C语言中广泛使用的字符串类型,存储形式为指向字符数组的指针,以空字符 ('\0'
) 作为结尾标志。
-
特点:
- 字符串以连续字节的方式存储。
- 需要开发者自行管理内存,存在内存越界及溢出风险。
- 使用ASCII字符表示,通常用于单字节字符集(SBCS)。
-
在逆向工程中的表现:
C风格字符串往往直接以字节数组的形式存储于目标文件的全局或局部数据段。例如,在汇编代码中可看到字符串结尾标志为0x00
。
1.1.2 宽字符字符串 (wchar_t*
)
宽字符字符串是支持Unicode编码的字符串,每个字符通常占用两个字节。广泛用于支持多语言的Windows应用程序。
-
特点:
- 默认使用
wchar_t
类型存储,结尾以L'\0'
标志。 - 支持多语言字符(如中文、日文和阿拉伯文)。
- 常见于Windows API中(例如
MessageBoxW
中使用宽字符字符串)。
- 默认使用
-
在逆向工程中的表现:
内存中常以0x00 00
作为空字符标志结尾,宽字符的十六进制表示往往易于标识。
1.1.3 C++标准字符串
C++标准库引入了以std::string
和std::wstring
为主要实现的字符串操作类。
-
特点:
- 封装了内存管理,开发者无需担心字符串的动态分配和释放。
- 提供了功能丰富的方法库(如长度计算、拼接、查找等)。
std::string
处理窄字符,std::wstring
处理宽字符。
-
在逆向工程中的表现:
C++字符串往往会调用对应的构造函数和析构函数。在逆向工程中,可以通过识别这些符号(如std::basic_string
)来跟踪字符串的分配及操作。
1.2 字符串表示
1.2.1 字符串常量
- 在C/C++中,字符串常量以双引号表示,例如
"Hello, World!"
。 - 编译器会把字符串常量放到程序的只读数据段(
.rdata
段)。 - 在逆向工程中,字符串常量通常显示为ASCII字符,可作为辅助分析程序逻辑的重要线索。
1.2.2 宽字符串常量
- 前缀
L
的字符串常量(如L"Hello, World!"
)则表示宽字符常量,类型为const wchar_t*
。 - 使用Unicode编码,适合多语言支持的应用程序。
- 常存储在只读段中,但因宽字符的字符宽度更大,需特别观察它们占用的内存格式。
2. 字符串处理函数
字符串操作函数是逆向工程分析的一个重要突破口,通过它们可以了解程序如何操作文本数据。以下是C标准库提供的几类字符串处理函数:
2.1 字符串长度
-
strlen
: 计算字符串长度(不包括结尾的空字符)。size_t strlen(const char* str);
-
逆向标志:
程序中,strlen
调用通常伴随着repnz scasb
汇编指令,这是一种快速检测空字符(0x00
)的位置的方式。
2.2 字符串复制
-
strcpy
,strncpy
: 复制字符串到另一内存地址。char* strcpy(char* dest, const char* src);
char* strncpy(char* dest, const char* src, size_t n);
-
逆向标志:
这类函数可能引起缓冲区溢出(如攻击者通过注入超长字符串导致内存破坏)。在反汇编中会注意到连续的字符串赋值指令。
2.3 字符串比较
-
strcmp
,strncmp
: 比较两个字符串是否相等。int strcmp(const char* str1, const char* str2); int strncmp(const char* str1, const char* str2, size_t n);
-
逆向标志:
程序显式验证字符串(如检查用户名或密码)时,会调用这些函数。在汇编中表现为循环比较指令。
2.4 字符串连接
-
strcat
,strncat
: 将两个字符串连接在一起。char* strcat(char* dest, const char* src); char* strncat(char* dest, const char* src, size_t n);
-
逆向标志:
检查目标字符串的存储位置,拷贝及拼接源字符串数据,是构造攻击载体的重要点。
2.5 字符或子字符串搜索
-
strchr
,strstr
:char* strchr(const char* str, int c); // 搜索字符c char* strstr(const char* haystack, const char* needle); // 搜索子字符串needle
-
逆向标志:
这些函数通常用作逻辑控制条件点。例如,通过搜索某关键词决定逻辑分支。
3. 字符串存储
程序中的字符串可以以多种方式存储,不同的存储方式在逆向工程中会展现不同的特性。
3.1 静态存储
字符串常量存储在只读数据段(.rdata
)。它们具有静态且不可修改的特性,可用于程序启动后的内存检测与解析。
- 逆向表现:
可以通过查看数据段内容快速列出常量字符串,用于推测程序功能。
3.2 动态存储
通过malloc
或calloc
在堆上动态分配的字符串需要在使用完毕后手动释放。
3.3 栈分配
局部声明的字符串数组保存在栈上,函数调用结束时自动释放。
- 逆向表现:
栈上数据通过特定函数帧分配(如esp
寄存器操作)。这类数据的生命周期较短。
4. 扩展知识点
4.1 防止字符串解析漏洞
- 缓冲区溢出:对
strcpy
和strcat
等未限定缓冲区大小的函数极易触发溢出漏洞。 - Unicode绕过:通过宽字符的编码错位或超长输入可能导致验证机制失效。
4.2 字符串混淆技术
- 多数恶意软件会采用字符串加密或混淆存储方式。例如:
- Base64编码。
- 自定义XOR加密。
- 分段存储与动态拼接。