堆栈eip溢出x86 vs x86_64 easy C代码

时间:2011-12-08 15:04:39

标签: c assembly x86 stack x86-64

让我跳过介绍并跳到好的部分。 我正在阅读“道德黑客手册”并尝试一些示例代码(约为p175)。

----------------------------------------------- ------------------------------------------

目标:在堆栈中溢出EIP

示例代码:

##> cat overflow.c
main(){
    char str1[10];   // declare a 10byte string
    // next, copy 35 bytes of 'A' to 'str1'
    strcpy(str1,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
}

----------------------------------------------- ------------------------------------------

如果我编译&在我的x86笔记本电脑上运行它,然后结果如预期。

使用openSuse 12.1 在X86上生成

##> uname -a
Linux linux-tzxm.site 3.1.0-1.2-desktop #1 SMP PREEMPT 
Thu Nov 3 14:45:45 UTC 2011 (187dde0) i686 i686 i386 GNU/Linux

##> cat /proc/sys/kernel/randomize_va_space 
1

##> gcc version 4.6.2 (SUSE Linux)
##> GNU gdb (GDB) SUSE (7.3-41.1.2)

##> gdb -q overflow

Reading symbols from /home/administrator/Programming/C/testProgs/overflow...done.

(gdb) run

Starting program: /home/administrator/Programming/C/testProgs/overflow 

Program received signal SIGSEGV, Segmentation fault.

0x41414141 in ?? ()

(gdb) info reg eip

eip            0x41414141       0x41414141

----------------------------------------------- ------------------------------------------

但是,如果我在我的x86_64笔记本电脑上做同样的事情,那么结果会有所不同,并且不符合预期(从我的小知识角度来看)

使用openSuse 11.3 在x86_64上生成

##> uname -a
Linux linux-2mna.site 2.6.34.10-0.4-desktop #1 SMP PREEMPT 2011-10-19 22:16:41 +0200 x86_64 x86_64 x86_64 GNU/Linux

##> cat /proc/sys/kernel/randomize_va_space 
1

##> gcc version 4.5.0 20100604
##> GNU gdb (GDB) SUSE (7.1-3.12)

##> gdb -q overflow2

Reading symbols from /home/jojojorn/Documents/Personal/HACKING/C_Prog/Tests/testProgs/overflow2...done.

(gdb) run

Starting program: /home/jojojorn/Documents/Personal/HACKING/C_Prog/Tests/testProgs/overflow2 

Program received signal SIGSEGV, Segmentation fault.

0x0000000000400553 in main () at overflow.c:11
11      }

(gdb) info reg eip

Invalid register `eip'

(gdb) 

----------------------------------------------- ------------------------------------------

所以这是我的问题:

1)为什么我不能在x86_64上的堆栈上溢出EIP? x86_64和x86之间的堆栈行为是否存在差异?

2)当我在x86_64上运行x86编译的二进制文件并使用gdb检查时,结果再次按预期进行。 所以我假设使用gcc 32位和gcc 64位进行区分?对于这个简单的代码,有什么区别和为什么有区别?

3)如果我希望x86_64上的代码与x86上编译的代码一样,是否在编译时设置了gcc参数?

4)我问这个问题,这意味着我还没有正确的知识来提出更好的问题。是否有一些额外的东西进入你的天才头脑我应该被问(以及你会回答哪些)?

此致

2 个答案:

答案 0 :(得分:16)

在x86_64上,指令指针为RIP,而不是EIP ...因此,如果使用64位可执行文件查询EIP中的gdb寄存器,因为那不是有效的64位寄存器,所以不会得到任何值。如果您希望在本机64位平台上将可执行文件保留为32位,则在编译时将gcc标记传递给-m32

如果您想了解x86_64 Unix堆栈与x86 Unix堆栈相比的行为,那么我建议您阅读x86_64 Unix ABI,第3.2和3.4节。

答案 1 :(得分:1)

  1. 并不是说x86_64上没有溢出,它只是一种呈现异常的不同方式。而不是实际告诉你它实际更新rip后无法执行代码0x4141414141414141 ,它告诉你更新之前目标地址无效。这是x86代码和x86_64代码之间的架构差异,无论何时执行64位代码,都是如何处理的。

  2. 同样,您只能在64位代码上使用不同的消息。

  3. 您必须将其编译为32位代码。如果要将其编译为x86_64代码,则无法获得相同的消息。

  4. 如果您要正确调试代码并查看rip指向的位置以及其他寄存器的值,实际上并不难发现这种差异。