原文:https://github.com/angrave/SystemProgramming/wiki/Memory%2C-Part-3%3A-Smashing-the-Stack-Example
每个线程使用栈内存。栈“向下增长” - 如果函数调用另一个函数,则栈扩展到较小的内存地址。栈内存包括非静态自动(临时)变量,参数值和返回地址。如果缓冲区太小某些数据(例如来自用户的输入值),那么很可能会覆盖其他栈变量甚至返回地址。栈内容的精确布局和自动变量的顺序取决于体系结构和编译器。然而,通过一些调查工作,我们可以学习如何故意粉碎特定架构的栈。
下面的示例演示了返回地址如何存储在栈中。对于特定的 32 位架构 Live Linux Machine ,我们确定返回地址存储在自动变量地址上方两个指针(8 个字节)的地址处。代码故意更改栈值,以便在输入函数返回时,而不是继续在 main 方法内部,它会跳转到 exploit 函数。
// Overwrites the return address on the following machine:
// http://cs-education.github.io/sys/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void breakout() {
puts("Welcome. Have a shell...");
system("/bin/sh");
}
void input() {
void *p;
printf("Address of stack variable: %p\n", &p);
printf("Something that looks like a return address on stack: %p\n", *((&p)+2));
// Let's change it to point to the start of our sneaky function.
*((&p)+2) = breakout;
}
int main() {
printf("main() code starts at %p\n",main);
input();
while (1) {
puts("Hello");
sleep(1);
}
return 0;
}
有很多计算机倾向于解决这个问题。