[c语言]利用栈帧结构特性来偷偷偷偷偷偷偷地悄无声息地调用函数

在上一篇文章栈帧和函数调用的关系? 用最直白的语言解释一下.,我们阐述了过程调用和栈帧的关系,相信大家已经对函数开辟的栈帧的结构有了认识,如下图所示
这里写图片描述
我们接着用上一篇myadd函数的栈帧结构演示一下
这里写图片描述
仔细观察,在开辟myadd函数的栈帧之前的初始化动作(形参实例化结束后)把执行完myadd函数后要执行的内容保存到了这里
这里写图片描述
如何定位这里的位置呢? 注意我们传参的参数A, 就在A的下面一个地方的地址.
所以我们可以用一个指针p指向a,再把指针p–;就指向这里.之后就可以修改这里面保存的地址来实现悄无声息地跳转.
我们首先写一个BUG函数

void BUG()
{
    printf("hello,im bug"); 
    Sleep(2000);

}

再在myadd函数里面把下一条执行的指令修改为bug函数

int myadd(int a,int b)
{
    int *p=&a;
    p--;//这时候p就指向调转地址了
    ret=*p;// 在修改之前先把原来的地址保存一下 保存在ret 里面  void* ret=null
       *p=&BUG;//然后将此处修改为bug函数地址


}

我们这时候运行一下就会发现程序崩溃了,因为正常调用BUG函数会使用call指令,把BUG函数调用完后的返回地址给确定了,而非正常调用后BUG函数并没有明确返回地址.
但是我们可以把BUG函数的返回地址给确定了
还是通过栈帧结构发现
如果我们在其函数内部定义一个临时变量x,x往上两个单元的地址就是BUG函数结束后的返回地址.
之前我们已经把myadd函数结束后要执行下一条程序的地址保存在ret里面了,把ret里的值给BUG函数结束后的返回地址就行了.
代码如下

void BUG()
{
    int x;
        int *q=&x; 
    q+=2;
    *q=ret;
    printf("hello,im bug\n");
        Sleep(2000);

}

运行结束后我们发现程序现在运行起来没有任何问题了.但是当整个程序结束的时候会报出EBP位置不正确的错误,这是为什么呢?
因为在正常调用开始时会push esp,然后在调用结束的时候会pop esp

但是在非正常调用的时候没有进行push esp的操作,而进行了pop esp的操作.这样esp就不在正确的位置上.
如何解决的呢?
在main函数里插入一段汇编代码


int main()
{
    int a=0XAAAAAAAA;
    int b=0xBBBBBBBB;
    int c=myadd(a,b);
    // 这是插入的汇编代码
        __asm{
        sub esp, 4
    }

    printf("main:you would   run here!\n");
    printf("res : %d\n",c);
    getchar();
    return 0;
}

至此,就完成了隐式的调用BUG函数
附上源码

#include<stdio.h>
#include<windows.h>
void *ret=NULL;  //只要是指针 都是4个字节,所以void *可以定义指针 可以接受任何类型数据
void BUG()
{
    int x;
    //my add 非法调用,(非call调用  就少了push 入栈的过程,而在返回的时候ret pop了)

    int *q=&x; 
    q+=2;
    *q=ret;
    printf("hello,im bug\n");//注意无论在哪修改 都是在函数执行完后返回的
        Sleep(2000);

}
int myadd(int a,int b)
{
    int *p=&a;
    p--;
    ret=*p;//注意 p解引用出来也是地址(需要返回的地址) 所以直接赋值给ret!
    *p=&BUG;

    printf("myadd调用结束,现在开始进入bug函数\n");

}
int main()
{
    int a=0XAAAAAAAA;
    int b=0xBBBBBBBB;
    int c=myadd(a,b);
        __asm{
        sub esp, 4
    }

    printf("main:you would   run here!\n");
    printf("res : %d\n",c);
    getchar();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值