且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

《逆向工程权威指南》—第3章3.3节 GCC的其他特性

更新时间:2022-10-11 20:42:13

本节书摘来自异步社区《逆向工程权威指南》一书中的第3章3.3节 GCC的其他特性,作者【乌克兰】Dennis Yurichev(丹尼斯),更多章节内容可以访问云栖社区“异步社区”公众号查看。

3.3 GCC的其他特性
只要C语言代码里使用了字符串型常量(可参照3.1.1节的范例),编译器就会把这个字符串常量置于常量字段,以保证其内容不会发生变化。不过GCC有个有趣的特征:它可能会把字符串拆出来单独使用。

我们来看下面这段程序:

#include <stdio.h>
int f1() 
{
         printf ("world\n");
};

int f2() 
{
         printf ("hello world\n");
};

int main() 
{
         f1();
         f2(); 
};

多数的C/C++编译器(包括MSVC编译器)会分配出两个直接对应的字符串,不过GCC 4.8.1的编译结果则更为可圈可点。

指令清单3.10 在IDA中观察GCC 4.8.1 的汇编指令

> f1                  proc near

s                   = dword ptr -1Ch

                    sub     esp, 1Ch
                    mov     [esp+1Ch+s], offset s ; "world\n"
                    call    _puts
                    add     esp, 1Ch
                    retn
f1                  endp

f2                  proc near

s                   = dword ptr -1Ch

                    sub     esp, 1Ch
                    mov     [esp+1Ch+s], offset aHello ; "hello "
                    call    _puts
                    add     esp, 1Ch
                    retn
f2                  endp

aHello              db  'hello'
s                   db  'world', 0xa, 0
在```  
打印字符串“hello world”的时候,这两个词的指针地址实际上是前后相邻的。在调用puts()函数进行输出时,函数本身不知道它所输出的字符串分为两个部分。实际上我们在汇编指令清单中可以看到,这两个字符串没有被“切实”分开。

在f1()函数调用puts()函数时,它输出字符串“world”和外加结束符(数值为零的1个字节),因为puts()函数并不知道字符串可以和前面的字符串连起来形成新的字符串。