【问题标题】:Stack eip overflow x86 vs x86_64 easy C code堆栈 eip 溢出 x86 vs x86_64 简单 C 代码
【发布时间】:2012-01-16 00:14:51
【问题描述】:

让我跳过介绍并跳到好的部分。 我正在阅读“道德黑客手册”并尝试一些示例代码(大约 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 笔记本电脑上编译并运行它,那么结果符合预期。

在 X86 上使用 openSuse 12.1 的结果

##> 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 笔记本电脑上做同样的事情,那么结果会有所不同并且不像预期的那样(从我的小知识的角度来看)

在 x86_64 上使用 openSuse 11.3 的结果

##> 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) 我问这个问题,这意味着我还没有足够的知识来问更好的问题。我应该问你的天才头脑中是否有一些额外的东西(你会回答)?

真诚的

【问题讨论】:

  • 我认为 x86_64 使用 %rip,gcc 还向堆栈添加了填充以防止这种情况,请尝试使用 -fno-stack-protector。
  • eip/rip 没有溢出。寄存器具有固定大小,您无法将任何内容复制到 eip/rip,因此您无法“溢出”它。溢出的是内存

标签: c assembly x86 stack x86-64


【解决方案1】:

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

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

【讨论】:

  • 如果要将其编译为 32 位,则需要安装 libc6-dev-i386。否则你会得到fatal error: sys/cdefs.h: No such file or directory
【解决方案2】:
  1. 并不是说 x86_64 上没有溢出,只是呈现异常的另一种方式。它实际上并没有告诉您它无法执行代码 0x4141414141414141之后它实际上更新了rip,而是告诉您目标地址在更新之前是无效的。这是 x86 代码和 x86_64 代码之间的架构差异,无论何时执行 64 位代码,都是这样处理的。

  2. 同样,您只会在 64 位代码上获得不同的不同消息。

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

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

【讨论】:

    猜你喜欢
    • 2012-04-02
    • 1970-01-01
    • 2011-11-24
    • 1970-01-01
    • 2012-12-20
    • 2011-03-02
    • 2014-01-17
    • 1970-01-01
    相关资源
    最近更新 更多