手动操作栈

环境:vs2013
先看一个嵌套一次代码,把这个函数劫持到另一个函数

#include <stdio.h>

//好多感慨啊,,,对理解堆栈有很大帮助啊

void  hello()
{
	printf("hello dong\n");
	getchar();
	return;//return的意义就在于:返回上一层
}//回到栈顶

void main()
{
	int b;

	int a;//在栈中,,又创建了一个栈

	/*这里我们取&a   是a的地址,,但是和a一点关系都没有,我们需要的是指向这个堆栈的一个指针而已,我
	们需要尝试(找到这个堆栈返回的地址的值)就是从(&a)[0]开始一直向下找,找到之后就能就修改它的值了*/
	/*(&a)[4] = ((int *)&a)[3];	//加上这一步的原因  我们进入到了hello这个函数堆栈中,但是hello栈顶是指向main的下一片内存区域也就是(&a)[4] 如果没有保存好(&a)[4]的值,那么将是一个垃圾值,hello返回的时候就不知道回到哪了
	(&a)[3] = (int)hello;*/

	//上面注释的是没有加 int b 时候的代码。。加了int b 这个堆栈有所改变,所以我们需要另外找到堆栈的返回地址,用&b和&a都可以,好像用&b又是(&b)[3]是返回地址
	(&a)[7] = ((int *)&a)[6];//hello栈的返回地址
	(&a)[6] = (int)hello;//修改了这个栈返回的地址,,变成了hello栈的入口地址

	printf("劫持技术\n");//这是一个函数也要push压栈,,但是对于这个程序没有任何影响这里只是提一下

	return;
}

这样做没有任何问题

再来看双层嵌套的代码

#include <stdio.h>

void  hello()
{
	printf("hello dong\n");
	return;//return的意义就在于:返回上一层
}//回到栈顶

void test()
{
	int b;
	int a;//在栈中,,又创建了一个栈
	(&a)[7] = ((int *)&a)[6];
	(&a)[6] = (int)hello;
	printf("劫持技术\n");
	return;
}

int main()
{
	test();//创建栈,,进入到test中
	//hello();
ok:
	printf("ok");
	getchar();
	return 0;
}

这样做问题就出来了:
当我们执行完main函数后,会报错
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
运行时检查失败# 0 ESP的值不正确保存在一个函数调用。这通常是调用一个调用一个调用约定的函数的结果,一个函数指针声明具有一个不同的调用约定。

说的容易懂一点就是,,本来我只给你一块钱买东西吃,结果你买回来两块钱的东西,我肯定就会怀疑你是不是偷了一块钱。。。c++编译器就在做这样的事。他会检查栈是否发生变化。

这是调用hello的图片
这里写图片描述

这是调用test的图片
这里写图片描述

我们可以看出。。在main函数return的时候会去比较ESP 和 EBP的大小。如果我们程序是按正规的路走,那么就是相等的,如果向我们这样,改变栈的结构就可能会发生ESP和EBP不相等的情况。

有人会问,我又没有改变,mian函数的return的地址怎么会发生栈结构改变呢?
就如我上面所说给你一块钱空间,你给我搞了两块钱的空间出来,那你肯定是作弊了啊,你在test中又开辟了一个新的栈。

至于如何解决这个bug,,用c代码实在想不出什么办法,毕竟我们增大了原本main函数中的栈大小。除非用汇编语言强制改变栈顶的地址。用汇编是可以的,亲自尝试过。

	_asm
	{
		//修改栈顶指针
		mov esp, ebp;
		sub esp, 12;
		sub esp, 0C0h;
	}

上面只是个人拙见,希望有人能给我提出错误,大家共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值