我已经完成了关于粉碎堆栈的演练。这里http://insecure.org/stf/smashstack.html和我在Trying to smash the stack找到的一个{{3}}。我理解会发生什么,但我不能让它正常工作。
这与其他场景一样。我需要跳过x = 1并打印0作为x的值。
我编译:
gcc file.c
原始代码:
void function(){
char buffer[8];
}
void main(){
int x;
x = 0;
function();
x = 1;
printf("%d\n", x);
}
当我跑步时
objdump -dS a.out
我得到了
0000000000400530 <function>:
400530: 55 push %rbp
400531: 48 89 e5 mov %rsp,%rbp
400534: 5d pop %rbp
400535: c3 retq
0000000000400536 <main>:
400536: 55 push %rbp
400537: 48 89 e5 mov %rsp,%rbp
40053a: 48 83 ec 20 sub $0x20,%rsp
40053e: 89 7d ec mov %edi,-0x14(%rbp)
400541: 48 89 75 e0 mov %rsi,-0x20(%rbp)
400545: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
40054c: b8 00 00 00 00 mov $0x0,%eax
400551: e8 da ff ff ff callq 400530 <function>
400556: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
40055d: 8b 45 fc mov -0x4(%rbp),%eax
400560: 89 c6 mov %eax,%esi
400562: bf 10 06 40 00 mov $0x400610,%edi
400567: b8 00 00 00 00 mov $0x0,%eax
40056c: e8 9f fe ff ff callq 400410 <printf@plt>
400571: c9 leaveq
400572: c3 retq
400573: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40057a: 00 00 00
40057d: 0f 1f 00 nopl (%rax)
在函数中,我需要弄清楚返回地址超出缓冲区开头的字节数。我不确定这个价值。但是因为从函数的beginnig到返回有6个字节;我会在缓冲区中添加7个字节吗?
然后我需要跳过指令 X = 1; 因为该指令长7个字节。我会将7添加到返回指针吗?
这样的东西?
void function(){
char buffer[8];
int *ret = buffer + 7;
(*ret) += 7;
}
void main(){
int x;
x = 0;
function();
x = 1;
printf("%d\n", x);
}
这会抛出警告:
warning: initialization from incompatible pointer type [enabled by default]
int *ret = buffer1 + 5;
^
输出是1.我做错了什么?你能解释一下如何做到正确以及为什么这是正确的方法?
谢谢。
答案 0 :(得分:1)
我们知道在堆栈上创建自动变量 - 因此获取自动变量的地址会产生指向堆栈的指针。当您调用void函数时,它的返回地址被压入堆栈,该地址的大小取决于您的平台(通常为4或8个字节)。因此,如果将自动变量的地址传递给函数,然后在该地址之前写入内存,则会损坏返回地址并粉碎堆栈。这是一个例子:
#include <stdlib.h>
#include <stdio.h>
static void f(int *p)
{
p[0] = 0x30303030;
p[1] = 0x31313131;
*(p - 1) = 0x35353535;
*(p - 2) = 0x36363636;
}
int main()
{
int a = 0x41424344;
int b = 0x45464748;
int c = 0x494a4b5c;
f(&b);
printf("%08x %08x %08x\n", a, b, c);
return 0;
}
我使用'gcc -g'在linux上编译了这个并在gdb下运行并得到了这个:
Program received signal SIGSEGV, Segmentation fault.
0x000000000040056a in f (p=0x7fffffffde74) at smash.c:10
10 }
(gdb) bt
#0 0x000000000040056a in f (p=0x7fffffffde74) at smash.c:10
#1 0x3636363600400594 in ?? ()
#2 0x3030303035353535 in ?? ()
#3 0x494a4b5c31313131 in ?? ()
#4 0x0000000000000000 in ?? ()
(gdb)
如您所见,父函数地址现在包含一些我的幻数。我在64位linux上运行它,所以我应该使用64位整数来完全覆盖返回地址 - 因为我保持低位字未触及。
答案 1 :(得分:1)
尝试下面的函数,我为32位编译器编写了尝试使用(-m32
gcc标志)或者稍加努力就可以使它与64位编译器一起工作(注意在你的{{ 1}}列出调用objdump
与下一条指令之间的7
字节偏移量,因此请使用function
代替7
。
8