我正在阅读“黑客:剥削的艺术”这本书。作者:Jon Erickson。
在本书的一部分中,他给出了C代码,然后使用gdb遍历相应的程序集,解释说明和内存活动。
我在Mac OS X上工作,所以事情与他在书中提到的有点不同(他正在使用Linux)。
无论如何,我有这个C程序:
1 #include <stdio.h>
2 #include <string.h>
3
4 int main()
5 {
6 char str_a[20];
7
8 strcpy(str_a, "Hello, world!\n");
9 printf(str_a);
10 }
这是相应的otool对象转储(我刚刚包含main):
_main:
0000000100000ea0 pushq %rbp
0000000100000ea1 movq %rsp,%rbp
0000000100000ea4 subq $0x30,%rsp
0000000100000ea8 movq 0x00000189(%rip),%rax
0000000100000eaf movq (%rax),%rax
0000000100000eb2 movq %rax,0xf8(%rbp)
0000000100000eb6 leaq 0xd4(%rbp),%rax
0000000100000eba movq %rax,%rcx
0000000100000ebd movq $0x77202c6f6c6c6548,%rdx
0000000100000ec7 movq %rdx,(%rcx)
0000000100000eca movb $0x00,0x0e(%rcx)
0000000100000ece movw $0x0a21,0x0c(%rcx)
0000000100000ed4 movl $0x646c726f,0x08(%rcx)
0000000100000edb movq %rcx,0xe8(%rbp)
0000000100000edf xorb %cl,%cl
0000000100000ee1 movq %rax,%rdi
0000000100000ee4 movb %cl,%al
0000000100000ee6 callq 0x100000f1e ; symbol stub for: _printf
0000000100000eeb movl 0xf4(%rbp),%eax
0000000100000eee movq 0x00000143(%rip),%rcx
0000000100000ef5 movq (%rcx),%rcx
0000000100000ef8 movq 0xf8(%rbp),%rdx
0000000100000efc cmpq %rdx,%rcx
0000000100000eff movl %eax,0xd0(%rbp)
0000000100000f02 jne 0x100000f0d
0000000100000f04 movl 0xd0(%rbp),%eax
0000000100000f07 addq $0x30,%rsp
0000000100000f0b popq %rbp
0000000100000f0c ret
0000000100000f0d callq 0x100000f12 ; symbol stub for: ___stack_chk_fail
行。你会注意到printf()的子程序调用:
0000000100000ee6 callq 0x100000f1e ; symbol stub for: _printf
但是对strcpy()的调用在哪里?
还有两个异常现象。首先,如果我在gdp中为strcpy()设置断点:
break strcpy
程序无需停止即可完成执行。似乎strcpy()实际上并没有被调用。
其次,当我编译代码时:
gcc -g -o char_array2 char_array2.c
我收到了警告:
char_array2.c: In function ‘main’:
char_array2.c:9: warning: format not a string literal and no format arguments
char_array2.c:9: warning: format not a string literal and no format arguments
我不确定这是否与丢失的子程序调用有关,但我认为无论如何我都会将其作为数据点包含在内。
在我看来,好像编译器已经决定strcpy()不是必需的,并且已经优化了代码以便在没有它的情况下工作。该计划确实按预期工作,打印“Hello,world!&#39;对于标准输出,但是对strcpy()的这个缺失调用让我想知道究竟发生了什么。
在本书的Erickson的例子中,是对strcpy()的调用,所以也许他的编译器和编译器的工作方式有所不同。我在LLVM上:
的i686-苹果darwin11-LLVM-GCC-4.2
任何想法都会感激不尽!
提前致谢,我希望你能发现这个有趣的。
汤姆
答案 0 :(得分:9)
就在这里:
0000000100000ebd movq $0x77202c6f6c6c6548,%rdx
0000000100000ec7 movq %rdx,(%rcx)
0000000100000eca movb $0x00,0x0e(%rcx)
0000000100000ece movw $0x0a21,0x0c(%rcx)
0000000100000ed4 movl $0x646c726f,0x08(%rcx)