strcpy 在汇编层面的优化

逆向工程 拆卸
2021-06-18 21:48:11

我正在编写小型 C 程序来自学如何使用 GDB 反汇编代码。有问题的C是:

void function( char **pointer )
{
   *pointer = malloc(100);
   strcpy(*pointer,"This is text");
}

拆解是:

0x400620:    push   %rbp
0x400621:    mov    %rsp,%rbp
0x400624:    sub    $0x10,%rsp
0x400628:    mov    %rdi,-0x8(%rbp)
0x40062c:    mov    $0x64,%edi
0x400631:    callq  0x4004f0 <malloc@plt>
0x400636:    mov    %rax,%rdx
0x400639:    mov    -0x8(%rbp),%rax
0x40063d:    mov    %rdx,(%rax)
0x400640:    mov    -0x8(%rbp),%rax
0x400644:    mov    (%rax),%rax
0x400647:    movabs $0x2073692073696854,%rcx
0x400651:    mov    %rcx,(%rax)
0x400654:    movl   $0x74786574,0x8(%rax)
0x40065b:    movb   $0x0,0xc(%rax)
0x40065f:    leaveq 
0x400660:    retq   

我理解序言:0x400620- 0x400624我也知道指针在这里被初始化为 100 个字符:0x400628- 0x40063d

我似乎无法弄清楚在strcpy做什么,我不明白如何检查0x400647和 中列出的地址的内容0x400654

有人可以帮我解决这个问题吗?

2个回答

因此,我假设您了解堆栈帧初始化部分以及malloc通过 PLT(程序链接表)调用

0x400636:    mov    %rax,%rdx

该行获取malloc函数的返回码并将其保存在rdx寄存器中。这个值对应你刚刚通过malloc调用创建的内存空间的地址

0x400639:    mov    -0x8(%rbp),%rax

在这里,您获取我们所在函数的第一个参数(char **pointer根据您的源代码)并将其存储在rax寄存器中。

0x40063d:    mov    %rdx,(%rax)

该行将分配的内存区域的地址传送给pointer变量。

0x400640:    mov    -0x8(%rbp),%rax

functionin的第一个参数的(不必要的)副本rax(寄存器已经存储了这个值,可能是编译器没有足够优化的故障)。

0x400644:    mov    (%rax),%rax

设置rax为 指向的地址pointer

0x400647:    movabs $0x2073692073696854,%rcx

要理解这一点,您需要分解这个幻数0x2073692073696854并将其切成碎片。让我们使用gdb

(gdb) p /c 0x54
$1 = 84 'T'
(gdb) p /c 0x68
$2 = 104 'h'
(gdb) p /c 0x69
$3 = 105 'i'
(gdb) p /c 0x73
$4 = 115 's'
(gdb) p /c 0x20
$5 = 32 ' '
(gdb) ...

我猜你现在开始明白这个大数字是什么意思了......

0x400651:    mov    %rcx,(%rax)

在这一行,之前的幻数存储在 指向的地址中pointer

0x400654:    movl   $0x74786574,0x8(%rax)

实际上,最后一个幻数是字符串的结尾(它对应于单词text)。

0x40065b:    movb   $0x0,0xc(%rax)

复制\0字符以在正确的位置结束字符串(0xc是字符串的大小,是字符串rax的起始地址)。

查看 16 进制数字0x400647并将它们转换为 ascii 字符,逐字节(2 位 x 2 位)。结果敲响了警钟吗?

由于您的源strcpy是一个常量字符串,编译器优化“逐字节复制静态字符串的内容,直到\0达到”以“以最快的方式用预期的字节填充目标”。

如果你想看看优化后的内存是什么样子strcpy,设置一个断点0x40065b然后回车x/20b *$rax