Reverse C-string and strcat

2023年11月11日


本文研究图这段C++代码是怎么变成二进制的。

#include <iostream>
using std::endl;
using std::cout;

int main()
{

	char str1[30] = "Many hands";
	char* str2(" make light work.");

	strcat(str1, str2);
	cout << str1 << endl;
}
:Passing C-style string to strcat

在Visual Studio,用VS 2010 platform toolset和release模式编译。然后在IDA Pro打开,不要加载debug symbol。

:The assembly view of IDA does not hint strings

如果你的assembly code用的是ebp addressing,那么编译时要enable omit frame pointers。

中的assembly view (IDA View-A)没有显示任何字符串,但Pseudocode正确显示了C++源代码里的字符串,这是为什么呢?

双击ds:dword_402114跳转到dword_402114所在的rdata section,右击它的值,发现796E614Dh可以表示为ASCII字符串“ynaM”,这正是“Many”的相反。见图。字符串是反过来的,说明该可执行程序用的是little endian。

:796E614Dh is indeed ASCII charaters "ynaM"

Undefine dword_402114, dword_402118, word_40211C, byte_40211E,接着在dword_402114的原来位置define string。回到main function,IDA已经正确显示“Many hands”字符串了。见图

:after combining the string segments, IDA recognizes the whole string "Many hands"

Compiler使用了三个寄存器传输字符串“Many hands”。eax保存"Many",ecx保存“ han”,(e)dx保存“ds”,al(也就是eax)保存the null terminator。

.text:20 mov dword ptr [esp+24h+var_24], eax用的是esp addressing,esp+24h等于ebp。但是如果运行该程序,会发现esp+24h不等于ebp。这是合理的,因为IDA的esp offset是基于该方法进入时的esp计算的。Prologue of a function is usually mov ebp, esp; sub esp, xx,但是这个main 方法没有mov ebp, esp

后面.text:2E到3A都在赋0值。可以undefine这几个变量,redefine string,这样IDA就会用memset来表示这几行,比较简洁。见图

:IDA uses the function memset to present the assignments of 0

奇怪的是pseudocode第10行,IDA用一个新变量v7来获取v3。但其实v3就是str1。

while和strcpy应该就是strcat的内联结果。我没有找到Visual C++的strcat实现,但https://github.com/gcc-mirror/gcc/blob/master/libssp/strcat-chk.c 可以看到gcc的strcat的实现确实需要一个while循环。