环境: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;
}
上面只是个人拙见,希望有人能给我提出错误,大家共同进步。