为什么 gdb 不能访问 ret 指令的内存?
Why cannot gdb access memory of ret instruction?
asm 中的每个 call
都会导致该指令 push
es return 值,因此一旦 ret
被调用,程序就知道从哪里继续。所以我想检查调用 ret
的地址:
有这个:
#include <stdio.h>
int main()
{
printf("a=%d; b=%d; c=%d", 1, 2, 3);
return 0;
}
我使用 gdb:
(gdb) b printf
+b printf
Breakpoint 1 at 0x1030
(gdb) run
+run
Breakpoint 1, __printf (format=0x555555556004 "a=%d; b=%d; c=%d")
at printf.c:28
28 printf.c: No such file or directory.
(gdb) x/10x $rsp
+x/10x $rsp
0x7fffffffdc28: 0x55555159 0x00005555 0x55555160 0x00005555
0x7fffffffdc38: 0xf7e1c09b 0x00007fff 0x00000000 0x00000000
0x7fffffffdc48: 0xffffdd18 0x00007fff
(gdb) x/i 0x55555159
+x/i 0x55555159
0x55555159: Cannot access memory at address 0x55555159
(gdb)
这里我试图从 return 地址读取指令,但不知何故无法访问该地址。为什么,什么时候它应该是 ret
的有效地址?
正如 Eric Postpischil 评论的那样,您只检查了 return 地址的 一半 ,x86_64
上的 64 位地址。
使用您的程序:
(gdb) b printf
Breakpoint 1 at 0x1030
(gdb) run
Starting program: /tmp/a.out
Breakpoint 1, __printf (format=0x555555556004 "a=%d; b=%d; c=%d") at printf.c:28
28 printf.c: No such file or directory.
(gdb) bt
#0 __printf (format=0x555555556004 "a=%d; b=%d; c=%d") at printf.c:28
#1 0x0000555555555159 in main () at t.c:4
这说明我们期望在栈上找到的return地址是0x0000555555555159
。的确,那正是地址@$rsp
:
(gdb) x/gx $rsp
0x7fffffffdbd8: 0x0000555555555159
查看该地址的指令:
(gdb) x/i 0x0000555555555159
0x555555555159 <main+36>: mov [=12=]x0,%eax
你也可以把整个main
拆开看看你在哪儿,你要去哪儿return:
(gdb) disas main
Dump of assembler code for function main:
0x0000555555555135 <+0>: push %rbp
0x0000555555555136 <+1>: mov %rsp,%rbp
0x0000555555555139 <+4>: mov [=13=]x3,%ecx
0x000055555555513e <+9>: mov [=13=]x2,%edx
0x0000555555555143 <+14>: mov [=13=]x1,%esi
0x0000555555555148 <+19>: lea 0xeb5(%rip),%rdi # 0x555555556004
0x000055555555514f <+26>: mov [=13=]x0,%eax
0x0000555555555154 <+31>: callq 0x555555555030 <printf@plt>
0x0000555555555159 <+36>: mov [=13=]x0,%eax
0x000055555555515e <+41>: pop %rbp
0x000055555555515f <+42>: retq
End of assembler dump.
如你所见,printf
将 return 到的指令确实在地址 0x0000555555555159
.
asm 中的每个 call
都会导致该指令 push
es return 值,因此一旦 ret
被调用,程序就知道从哪里继续。所以我想检查调用 ret
的地址:
有这个:
#include <stdio.h>
int main()
{
printf("a=%d; b=%d; c=%d", 1, 2, 3);
return 0;
}
我使用 gdb:
(gdb) b printf
+b printf
Breakpoint 1 at 0x1030
(gdb) run
+run
Breakpoint 1, __printf (format=0x555555556004 "a=%d; b=%d; c=%d")
at printf.c:28
28 printf.c: No such file or directory.
(gdb) x/10x $rsp
+x/10x $rsp
0x7fffffffdc28: 0x55555159 0x00005555 0x55555160 0x00005555
0x7fffffffdc38: 0xf7e1c09b 0x00007fff 0x00000000 0x00000000
0x7fffffffdc48: 0xffffdd18 0x00007fff
(gdb) x/i 0x55555159
+x/i 0x55555159
0x55555159: Cannot access memory at address 0x55555159
(gdb)
这里我试图从 return 地址读取指令,但不知何故无法访问该地址。为什么,什么时候它应该是 ret
的有效地址?
正如 Eric Postpischil 评论的那样,您只检查了 return 地址的 一半 ,x86_64
上的 64 位地址。
使用您的程序:
(gdb) b printf
Breakpoint 1 at 0x1030
(gdb) run
Starting program: /tmp/a.out
Breakpoint 1, __printf (format=0x555555556004 "a=%d; b=%d; c=%d") at printf.c:28
28 printf.c: No such file or directory.
(gdb) bt
#0 __printf (format=0x555555556004 "a=%d; b=%d; c=%d") at printf.c:28
#1 0x0000555555555159 in main () at t.c:4
这说明我们期望在栈上找到的return地址是0x0000555555555159
。的确,那正是地址@$rsp
:
(gdb) x/gx $rsp
0x7fffffffdbd8: 0x0000555555555159
查看该地址的指令:
(gdb) x/i 0x0000555555555159
0x555555555159 <main+36>: mov [=12=]x0,%eax
你也可以把整个main
拆开看看你在哪儿,你要去哪儿return:
(gdb) disas main
Dump of assembler code for function main:
0x0000555555555135 <+0>: push %rbp
0x0000555555555136 <+1>: mov %rsp,%rbp
0x0000555555555139 <+4>: mov [=13=]x3,%ecx
0x000055555555513e <+9>: mov [=13=]x2,%edx
0x0000555555555143 <+14>: mov [=13=]x1,%esi
0x0000555555555148 <+19>: lea 0xeb5(%rip),%rdi # 0x555555556004
0x000055555555514f <+26>: mov [=13=]x0,%eax
0x0000555555555154 <+31>: callq 0x555555555030 <printf@plt>
0x0000555555555159 <+36>: mov [=13=]x0,%eax
0x000055555555515e <+41>: pop %rbp
0x000055555555515f <+42>: retq
End of assembler dump.
如你所见,printf
将 return 到的指令确实在地址 0x0000555555555159
.