我正在使用gdb调试我的代码,并遇到了这个问题。 gdb显示如下:
(gdb) ni
0x08048ca5 in getbufn ()
(gdb) disas 0x08048c98
Dump of assembler code for function getbufn:
0x08048c89 <+0>: push %ebp
0x08048c8a <+1>: mov %esp,%ebp
0x08048c8c <+3>: sub $0x208,%esp
0x08048c92 <+9>: lea -0x200(%ebp),%eax
0x08048c98 <+15>: mov %eax,(%esp)
0x08048c9b <+18>: call 0x8048bf4 <Gets>
0x08048ca0 <+23>: mov $0x1,%eax
=> 0x08048ca5 <+28>: leave
0x08048ca6 <+29>: ret
End of assembler dump.
(gdb) p /x $ebp
$1 = 0x55683950
(gdb) p /x $esp
$2 = 0x55683748
(gdb) ni
0x08048ca6 in getbufn ()
(gdb) p /x $ebp
$3 = 0x4030201
(gdb) p /x $esp
$4 = 0x55683954
(gdb) x /1xw $esp
0x55683954: 0x55683750
(gdb) si
Cannot access memory at address 0x4030205
(gdb)
0x08048ca6中的代码是“ret”,表示jmp(%esp),addl 0x4,%esp 所以我想知道为什么gdb的最后一句是“无法访问地址0x4030205的内存” 它应该在地址0x55683750中执行指令代码吗?
THX!
答案 0 :(得分:1)
嗨 -
; Enter subroutine: build stack frame
0x08048c89 <+0>: push %ebp ; Save the old buffer pointer
0x08048c8a <+1>: mov %esp,%ebp ; Save the current stack pointer
0x08048c8c <+3>: sub $0x208,%esp ; Allocate space for local variables
0x08048c92 <+9>: lea -0x200(%ebp),%eax ; call "gets()" subroutine
0x08048c98 <+15>: mov %eax,(%esp)
0x08048c9b <+18>: call 0x8048bf4 <Gets>
0x08048ca0 <+23>: mov $0x1,%eax ; eax <= 1
=> 0x08048ca5 <+28>: leave ; we *think* we're leaving the subroutine...but
0x08048ca6 <+29>: ret ; in fact we crash at this point
结论:
“gets()”中的某些内容会破坏您的堆栈,因此无法从子例程返回。
建议:
不要使用“gets()”。这不安全。大多数编译器实际上 WARN 你不安全。使用“fgets()”(或输入字符串的任意数量的其他选择)代替:
http://cboard.cprogramming.com/c-programming/137352-gets-unsafe-method-alternatives.html
... IMHO
答案 1 :(得分:0)
“=&gt;”指向 about 执行的指令,在这种情况下是“离开”。并且“离开”定义为首先将esp
设置为ebp
,然后弹出ebp
。将esp
设置为ebp
(0x4030201
后,一个错误的地址和一些看起来很可疑的地址就是从字节1,2,3,4中生成的,流行音乐失败。
您可能希望在调用ebp
之前和之后查看Gets()
的值。我的猜测是对Gets()
的调用导致该寄存器被修改,这不应该发生,因为ebp
通常是被调用者保存。
请注意,虽然使用512字节的堆栈缓冲区调用Gets()
可能不可取,但在这种情况下,缓冲区溢出不会导致崩溃。缓冲区溢出可能会使ret
在其他位置跳转,但不会导致ebp
被修改。