欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

透析栈帧——栈帧的应用

程序员文章站 2024-01-01 21:48:58
...

应用一:不调用变量本身,而修改该变量的数据

代码如下:

#include <stdio.h>
#include <windows.h>

int myadd(int x, int y)
{
	int *p = &x;
	p++;
	printf("before: %d\n",*p);
	*p = 30;
	printf("after: %d\n", y);
}

int main()
{
	int a = 10;
	int b = 20;
	myadd(a, b);
	printf("main:you should running here!\n ");
	system("pause");
	return 0;
}

透析栈帧——栈帧的应用

首先,让指针p指向x的地址,p++后指针向上移动,此时p指向y的地址,故而*P==y==20; 当给*p赋值30后,此时p仍指向y的地址,相当于给y赋值,所以y==30。

运行结果如下:

透析栈帧——栈帧的应用


应用二:非法调用第三方函数

代码如下:

#include <stdio.h>
#include <Windows.h>

void *ret = NULL;

void bug()
{
	int x;
	int *q = &x;
	q += 2;
	*q = ret;
	printf("bug: I am bug!\n");
	Sleep(2000);
}

int myadd(int x, int y)
{
	int *p = &x;
	p--;
	ret = *p;
	*p = bug;
	printf("myadd: myadd is called,begin return...\n");
}

int main()
{
	int a = 10;
	int b = 20;
	int c = myadd(a, b);
	__asm{                  
		sub esp,4
	}
	printf("main:you should running here!\n ");
	system("pause");
	return 0;
}

在栈帧结构中,函数调用返回时,是利用函数被调用之前所保存call指令的下一条指令的地址而回到main函数,当我们改写这个地址时,此时函数便可强行跳转至另一个函数中去。

对于上面这个代码而言,函数的调用过程为:main函数—>myadd函数—>bug函数—>main函数

在main函数中
执行到c=myadd(a,b)语句时,程序跳转至myadd函数
在myadd函数中
(1)指针p先指向x的地址
(2)执行p--找到main函数的返回地址
(3)将该地址保存(ret=*p)
(4)将p指向的地址改为bug函数的返回地址
(5)执行输出语句
(6)myadd函数结束,程序跳转至bug函数
在bug函数中
(1)定义变量x,定位bug函数
(2)指针q先指向x的地址
(3)执行q+=2语句找到执行完bug函数后所要返回的地址
(4)执行*q=ret语句将该地址改为main函数的返回地址
(5)执行输出语句
(6)休眠2s
(7)bug函数结束,程序跳转至main函数
在main函数中
执行__asm{ sub esp,4} 语句,在c语言中插入汇编代码,sub esp,4 就是 esp-4 ,目的是平衡栈帧。每一个函数在被调用时都是通过call指令调用的,此时执行push指令将地址入栈,在调用完返回时是通过ret指令返回的,此时执行pop指令将地址出栈,一入一出,栈帧刚好平衡。在调用bug函数时,我们是通过修改地址的方式调用的,没有执行push指令,但在返回时,我们通过ret指令返回,执行了pop指令,无入有出,此时栈帧结构不平衡,所以我们要执行esp-4这步语句来使栈帧结构达到平衡。

运行结果如下:

透析栈帧——栈帧的应用


上一篇:

下一篇: