利用栈帧改变变量的值及强行插入第三个函数

利用栈帧 改变另一个变量的值

在之前学习了栈帧结构后,我们可不可以不通过某一个变量名来改变该变量的值?
答案是可以的。代码如下:

#include <stdio.h>
#include <windows.h>
int Myadd(int x,int y)
{
    int z=0;
    int *p=&x;
    p++;
    printf("Myadd:%#x\n",*p);
    *p=10;
    printf("Myadd:%#x\n",*p);
    z=x+y;
    return z;
}
int main()
{
    int a=0xAAAAAAAA;
    int b=0XBBBBBBBB;
    int c=Myadd(a,b);
    printf("you should run here!\n");
    printf("result:%d\n",c);
    system("pause");
    return 0;
}

其实很简单,我们对x取地址,当前指针指向x的地址,令指针下移即可指向b,可以通过指针来改变b变量的值,实际上在这个过程中,我们并没有通过b变量的变量名来改变b的值。

强行插入第三个函数

通过栈帧结构,我们知道函数调用返回时,是要将call命令的下一条指令的地址压入栈中,如果我们通过改写这个地址,是否可以强行跳转至我们想要程序跳转的函数,如果可以,那么该如何返回本身应该执行的函数呢?
下面我们具体说明一下:

#include <stdio.h>
#include <windows.h>
int bug()
{
    Sleep(1000);
    printf("i am a bug!\n");
    Sleep(3000);
    system("pause");
}
int Myadd(int x,int y)
{
    int z=0;
    int *p=&x;
    p--;
    *p=bug;
    z=x+y;
    return z;
}
int main()
{
    int a=0xAAAAAAAA;
    int b=0XBBBBBBBB;
    int c=Myadd(a,b);
    printf("you should run here!\n");
    printf("result:%d\n",c);
    system("pause");
    return 0;
}

类似于修改变量的例子,我们通过修改指针的位置可以找到之前被压入栈中的main函数的返回地址,并且通过改写改地址(修改为我们要插入函数的地址),使得函数Myadd并没有返回main函数而是跳转至了我们自己写的bug函数。
这里写图片描述
在实际运行时,我们可以发现程序确实是跳转进了我们的bug函数中,但实际上,程序在结束时是挂掉的,因为我们并没有处理如何从bug函数返回我们的main函数。
我们回想一下刚才我们是强行跳转至第三函数的,是通过修改栈中main函数的返回地址来实现的,但是我们并没有将这个地址保存下来,所以我们从bug函数想要回到main函数,程序也不知道他要回到那里继续执行,所以这个操作必须由我们完成。

#include <stdio.h>
#include <windows.h>
void *main_ret = NULL;
int bug()
{
    int first=0;
    int *p=&first;
    p+=2;
    *p=main_ret;

    Sleep(1000);
    printf("This is bug!\n");
    Sleep(3000);

}
int Myadd(int x,int y)
{
    int z=0;
    int *p=&x;
    p--;
    printf("begin...Myadd\n");
    main_ret=*p;
    *p=bug;
    z=x+y;
    printf("end...Myadd\n");
    return z;
}
int main()
{
    int a=10;
    int b=20;
    int c=0;
    printf("begin...main\n");

    c = Myadd(a, b);
    _asm{
        sub esp,4
    }//平衡栈帧
    printf("This is main!\n");
    printf("result:%d\n",c);
    printf("end...main\n");
    system("pause");
    return 0;
}

这里写图片描述
通过这个截图我们可以看到函数调用的过程:
main函数–>Myadd–>bug–>main
调用Myadd函数使用了call指令,而调用bug函数是通过更改地址的方式,但返回时两个函数均使用了ret指令才能返回。
_asm是在c语言中插入汇编代码,令esp-4是为了平衡esp的位置,在我们返回main函数时,通过我们的人为操作,esp相比于正常状态是不平衡的,所以我们通过在c语言中插入一段汇编代码来平衡栈帧。

以上:就是通过栈帧结构来改变变量的值,或者强行改变函数跳转。
因此我们在写程序中,对于调用函数的过程要非常清楚,并且还要函数在调用过程中关心内存的变化、返回值、几个函数跳转的过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值