一道面试题重新拾起C语言

今天一个技术群里有人发了一个脉脉上的面试题,如下:
在这里插入图片描述

这个题如果只用大学的C语言知识肯定无法解决的。还好我以前看过《深入理解计算机系统》这本书,知道一个程序其实就是一堆地址和一堆指令组成,这个提明显需要在子函数里面修改父函数的栈地址。我们知道栈地址是从高地址往的地址分配内存的,如下图所示:
在这里插入图片描述
在做函数跳转的时候,有两个很关键的寄存器,ebp(64位是rbp)和esp(64位是rsp)。ebp是保存的一个函数的栈基地址,esp是保存的当前执行代码的地址。也就是所有函数里面分配的临时变量都会在ebp和esp记录的地址之间。做函数跳转的时候,首先会保存父函数的当前栈帧地址,也就是ebp寄存器的值,然后把ebp切换到当前的esp,开始执行新的函数代码。

有了这些基础知识,思路也就有了:我们需要在pass函数里面先获取到当前ebp的值,然后倒推上一个函数的esp的值,然后给减去分配临时变量的偏移量,赋值为456即可。
下面开始解这个题:
先把如下C语言代码编译后,生成汇编代码:

#include <stdio.h>

void pass()
{
}
int main()
{
    int x = 123;
    pass();
    printf("%d\n", x);

    return 0;
}

objdump -D a.out之后main函数和pass函数如下:

080483c4 <pass>:
 80483c4:   55                      push   %ebp
 80483c5:   89 e5                   mov    %esp,%ebp
 80483c7:   5d                      pop    %ebp
 80483c8:   c3                      ret

080483c9 <main>:
 80483c9:   55                      push   %ebp
 80483ca:   89 e5                   mov    %esp,%ebp
 80483cc:   83 e4 f0                and    $0xfffffff0,%esp
 80483cf:   83 ec 20                sub    $0x20,%esp
 80483d2:   c7 44 24 1c 7b 00 00    movl   $0x7b,0x1c(%esp)
 80483d9:   00.
 80483da:   e8 e5 ff ff ff          call   80483c4 <pass>
 80483df:   b8 c4 84 04 08          mov    $0x80484c4,%eax
 80483e4:   8b 54 24 1c             mov    0x1c(%esp),%edx
 80483e8:   89 54 24 04             mov    %edx,0x4(%esp)
 80483ec:   89 04 24                mov    %eax,(%esp)
 80483ef:   e8 00 ff ff ff          call   80482f4 <printf@plt>
 80483f4:   b8 00 00 00 00          mov    $0x0,%eax
 80483f9:   c9                      leave
 80483fa:   c3                      ret

这里可以通过“movl $0x7b,0x1c(%esp)”看到变量x的地址是esp地址加上0x1c。而由于产生了函数调用,并且在pass函数里面需要保存ebp的地址,所以这里esp会往下偏移8个地址(原因是call指令和push指令都会做一次入栈操作)。我们通过汇编获取到当前函数的ebp就可以计算出来上一个函数的esp寄存器的值了。所以我们最终的解题代码如下:

#include <stdio.h>

void pass()
{
    int ebp = 0;
    asm("movl %%ebp, %0  \n\t":"=r"(ebp));
    int *px = (int*) (ebp +0x1c + 0x8);
    *px = 456;
}

int main()
{
    int x = 123;
    pass();
    printf("%d\n", x);

    return 0;
}

需要注意的是以上的方法只能够在32位系统上面正确运行,如果在64位系统上面,需要操作的是rbp,并且地址需要使用64位地址来存放。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值