先看源程序:
#include <stdio.h>
#include <unistd.h>
void bar(void)
{
printf("Hello,World\n");
_exit(0);
}
void foo(void)
{
void *a[1];
a[2]=(void *)bar;
}
int main()
{
foo();
return 0;
}
测试环境:centos32bit
输出结果:
这个程序的关键之处在于对数组a的越界处理,以前尝试从C代码角度来解释原因,一直没有得到答案。从汇编语言解释就很简单,我们直接看汇编代码:
foo函数中有一个变量a,或者说成是a[0]更合适,地址是ebp-4
这是屡一下栈中变量分布:
a[0] a[1] a[2]
ebp-4 ebp ebp+4(eip)
ebp+4地址中存放的应该是main函数的return语句地址,我们却把bar函数地址替换了return语句地址,所以foo函数结束后,cpu本来要转到main中的return语句,由于foo越界访问数组更改了eip,cpu转向了bar,就出现了调用bar函数的现象。
在不同的测试环境下,可以通过修改数组a的类型,比如int;a的长度,越界的长度也要对应修改。就可以实现不走main中的return,而走bar函数。