粉碎堆栈 - 无法找到 return 地址
Smashing the Stack - Trouble finding return address
我一直在阅读 "Smashing the Stack for Fun and Profit" 并且似乎遇到了与其他人 运行 过去遇到的问题类似的问题;但是我无法弄清楚为什么我的代码仍然无法正常工作。
我想做什么:
考虑以下代码:
void function1(int a, int b, int c){
char buffer1[8];
// char buffer2[10];
int *ret;
ret = (int *) buffer1 + 24;
(*ret) += 7;
}
void main() {
int x;
x = 0;
function1(1,2,3);
x = 1;
printf("%d\n", x);
}
该示例的目标是覆盖 *function1 的 return 地址
* 并跳过 main 中的 x = 1 行。所以,程序应该输出 0 而不是 1。但是,我的输出仍然是 1。所以我不确定我哪里出错了。
使用gdb计算return地址和偏移量
来自程序集的 objdump:
00000000000006db <main>:
6db: 55 push %rbp
6dc: 48 89 e5 mov %rsp,%rbp
6df: 48 83 ec 10 sub [=12=]x10,%rsp
6e3: c7 45 fc 00 00 00 00 movl [=12=]x0,-0x4(%rbp)
6ea: ba 03 00 00 00 mov [=12=]x3,%edx
6ef: be 02 00 00 00 mov [=12=]x2,%esi
6f4: bf 01 00 00 00 mov [=12=]x1,%edi
6f9: e8 b2 ff ff ff callq 6b0 <function1>
6fe: c7 45 fc 01 00 00 00 movl [=12=]x1,-0x4(%rbp)
705: 8b 45 fc mov -0x4(%rbp),%eax
708: 89 c6 mov %eax,%esi
70a: 48 8d 3d 93 00 00 00 lea 0x93(%rip),%rdi # 7a4 <_IO_stdin_used+0x4>
711: b8 00 00 00 00 mov [=12=]x0,%eax
716: e8 45 fe ff ff callq 560 <printf@plt>
71b: 90 nop
71c: c9 leaveq
71d: c3 retq
71e: 66 90 xchg %ax,%ax
因为我试图跳过 x = 1;
,所以 0x705 - 0x6fe = 0x7,我相信这是正确的。
为了确定 buffer1 和调用堆栈上的 return 地址之间的偏移量,我检查了 gdb:
Breakpoint 1, function1 (a=1, b=2, c=3) at example3.c:12
12 ret = (int *) buffer1 + 24;
(gdb) p $rbp
= (void *) 0x7fffffffea80
(gdb) p &buffer1
= (char (*)[8]) 0x7fffffffea70
buffer1 和 return 地址之间的距离应该是:0x7fffffffea80 - 0x7ffffffffea70 + 8 = 24
我还验证了字长是 8(使用 arch
我知道它是 x86_64)。
我的猜测是 return 地址偏移量可能因堆栈金丝雀之类的原因而有所不同,但我如何才能找到实际的 return 地址?
编辑:
函数 1 的反汇编:
00000000000006b0 <function1>:
6b0: 55 push %rbp
6b1: 48 89 e5 mov %rsp,%rbp
6b4: 89 7d ec mov %edi,-0x14(%rbp)
6b7: 89 75 e8 mov %esi,-0x18(%rbp)
6ba: 89 55 e4 mov %edx,-0x1c(%rbp)
6bd: 48 8d 45 f0 lea -0x10(%rbp),%rax
6c1: 48 83 c0 44 add [=14=]x44,%rax
6c5: 48 89 45 f8 mov %rax,-0x8(%rbp)
6c9: 48 8b 45 f8 mov -0x8(%rbp),%rax
6cd: 8b 00 mov (%rax),%eax
6cf: 8d 50 07 lea 0x7(%rax),%edx
6d2: 48 8b 45 f8 mov -0x8(%rbp),%rax
6d6: 89 10 mov %edx,(%rax)
6d8: 90 nop
6d9: 5d pop %rbp
6da: c3 retq
不确定这是否是您的主要问题,但我正在查看
ret = (int *) buffer1 + 24;
Cast 的优先级高于二进制 +
,所以这是 ((int *)buffer1) + 24
。结果是 ret
被设置为比 buffer1
高 96 字节的地址,因为 sizeof(int) == 4
.
你可能打算写
ret = (int *)(buffer1 + 24);
另外,return地址是64位,int
是32位。因此,您可能希望将 ret
声明为 unsigned long *
而不是 int *
,并相应地更改转换,以便您的 *ret += 7
是 64 位添加。它不太可能因为对齐而真正产生影响,但它看起来仍然更正确。
我一直在阅读 "Smashing the Stack for Fun and Profit" 并且似乎遇到了与其他人 运行 过去遇到的问题类似的问题;但是我无法弄清楚为什么我的代码仍然无法正常工作。
我想做什么:
考虑以下代码:
void function1(int a, int b, int c){
char buffer1[8];
// char buffer2[10];
int *ret;
ret = (int *) buffer1 + 24;
(*ret) += 7;
}
void main() {
int x;
x = 0;
function1(1,2,3);
x = 1;
printf("%d\n", x);
}
该示例的目标是覆盖 *function1 的 return 地址 * 并跳过 main 中的 x = 1 行。所以,程序应该输出 0 而不是 1。但是,我的输出仍然是 1。所以我不确定我哪里出错了。
使用gdb计算return地址和偏移量
来自程序集的 objdump:
00000000000006db <main>:
6db: 55 push %rbp
6dc: 48 89 e5 mov %rsp,%rbp
6df: 48 83 ec 10 sub [=12=]x10,%rsp
6e3: c7 45 fc 00 00 00 00 movl [=12=]x0,-0x4(%rbp)
6ea: ba 03 00 00 00 mov [=12=]x3,%edx
6ef: be 02 00 00 00 mov [=12=]x2,%esi
6f4: bf 01 00 00 00 mov [=12=]x1,%edi
6f9: e8 b2 ff ff ff callq 6b0 <function1>
6fe: c7 45 fc 01 00 00 00 movl [=12=]x1,-0x4(%rbp)
705: 8b 45 fc mov -0x4(%rbp),%eax
708: 89 c6 mov %eax,%esi
70a: 48 8d 3d 93 00 00 00 lea 0x93(%rip),%rdi # 7a4 <_IO_stdin_used+0x4>
711: b8 00 00 00 00 mov [=12=]x0,%eax
716: e8 45 fe ff ff callq 560 <printf@plt>
71b: 90 nop
71c: c9 leaveq
71d: c3 retq
71e: 66 90 xchg %ax,%ax
因为我试图跳过 x = 1;
,所以 0x705 - 0x6fe = 0x7,我相信这是正确的。
为了确定 buffer1 和调用堆栈上的 return 地址之间的偏移量,我检查了 gdb:
Breakpoint 1, function1 (a=1, b=2, c=3) at example3.c:12
12 ret = (int *) buffer1 + 24;
(gdb) p $rbp
= (void *) 0x7fffffffea80
(gdb) p &buffer1
= (char (*)[8]) 0x7fffffffea70
buffer1 和 return 地址之间的距离应该是:0x7fffffffea80 - 0x7ffffffffea70 + 8 = 24
我还验证了字长是 8(使用 arch
我知道它是 x86_64)。
我的猜测是 return 地址偏移量可能因堆栈金丝雀之类的原因而有所不同,但我如何才能找到实际的 return 地址?
编辑:
函数 1 的反汇编:
00000000000006b0 <function1>:
6b0: 55 push %rbp
6b1: 48 89 e5 mov %rsp,%rbp
6b4: 89 7d ec mov %edi,-0x14(%rbp)
6b7: 89 75 e8 mov %esi,-0x18(%rbp)
6ba: 89 55 e4 mov %edx,-0x1c(%rbp)
6bd: 48 8d 45 f0 lea -0x10(%rbp),%rax
6c1: 48 83 c0 44 add [=14=]x44,%rax
6c5: 48 89 45 f8 mov %rax,-0x8(%rbp)
6c9: 48 8b 45 f8 mov -0x8(%rbp),%rax
6cd: 8b 00 mov (%rax),%eax
6cf: 8d 50 07 lea 0x7(%rax),%edx
6d2: 48 8b 45 f8 mov -0x8(%rbp),%rax
6d6: 89 10 mov %edx,(%rax)
6d8: 90 nop
6d9: 5d pop %rbp
6da: c3 retq
不确定这是否是您的主要问题,但我正在查看
ret = (int *) buffer1 + 24;
Cast 的优先级高于二进制 +
,所以这是 ((int *)buffer1) + 24
。结果是 ret
被设置为比 buffer1
高 96 字节的地址,因为 sizeof(int) == 4
.
你可能打算写
ret = (int *)(buffer1 + 24);
另外,return地址是64位,int
是32位。因此,您可能希望将 ret
声明为 unsigned long *
而不是 int *
,并相应地更改转换,以便您的 *ret += 7
是 64 位添加。它不太可能因为对齐而真正产生影响,但它看起来仍然更正确。