详解main函数反汇编代码(超级详细)

一、前言
为了弄清楚**缓冲区溢出攻击**,先花大篇幅讲清楚main函数的反汇编代码是有必要的(见二、main函数的反汇编代码解析)。
二、main函数的反汇编代码解析
1.main函数的源代码
在这里插入图片描述
2.main函数的反汇编代码
在这里插入图片描述
(1)前三行
①lea 0x4(%esp),%ecx

解析:
1)实现的功能:esp寄存器中的值(存的是地址,指向的是栈顶)+4,存入寄存器ecx。
程序计数器(pc) : 0x8048484bb, 即将要执行main函数
在这里插入图片描述
此时esp, ecx的值如下:
在这里插入图片描述
2)为啥要把esp+4后存入ecx?
main函数是由一个_start函数调用执行的。
此时esp指向的栈顶,内容属于_start函数,为了在调用并执行完main函数后回到_start函数继续执行,所以需要先保存一下esp。
那么直接保存不就好了,为啥要esp+4呢?
目前这点没找到有说服力的解释,我谈几点我的猜想:
因为下一条汇编指令会改变esp的值,所以保存esp+a(之所以是+,是因为栈底是高地址,栈顶是低地址),a取多少呢?由于是32位架构的,即4个Byte,故esp+4。
我们来看看esp指向的栈顶,内容是啥。
在这里插入图片描述
确实是一条指令,猜测是_start函数的,但还未执行,就转去执行main函数了。故main函数执行完,需要返回到这条指令继续执行。

②and $0xfffffff0,%esp

解析:
执行该指令之前,esp的值为0xbffff0ac, 没有与16字节对齐。
未对齐的栈调用函数的后果是速度非常慢,因为16字节是x86上的缓存线宽。
执行后,esp的情况如下:
在这里插入图片描述

③pushl -0x4(%ecx)

解析:
pushl表示双字(32位)压栈, 也即把ecx-4后压栈。
ecx-4的值即在未执行main函数之前,esp的值,如下所示:
在这里插入图片描述
当时_start函数的esp执行了这条指令,但是没有执行便调用执行main函数了,之后要返回这条指令进行执行_start函数。
x/i 反汇编

总结
综合指令①~③即保存了_start函数的返回地址,又实现了16字节对齐(为了效率)。

(2)剩余汇编代码解析
在这里插入图片描述
1)先讲个“套路”:
函数调用(main函数也是被调用),汇编代码中,首先要做的工作如下:
①保存调用者的ebp(下文介绍功能);(push %ebp)
在这里插入图片描述
调用者_start函数的ebp一开始为0(挺奇怪的);

②将被调用者的esp存储到ebp;(mov %esp,%ebp)

EBP存储着当前函数栈底的地址,栈低通常作为基址,我们可以通过栈底地址和偏移相加减来获取变量地址(很重要)。

在这里插入图片描述
从esp起,栈的内容属于main函数
在这里插入图片描述
ebp存的就是main函数栈底的地址。

2)存疑点
①push %ecx
为啥要保存ecx的内容?
_start函数的返回地址已经通过“pushl -0x4(%ecx)”存到栈中了啊。ecx的内容已经没啥意义了。
而且调用的foo01函数,就没有push %ecx。

3)⑥给了进一步解释

②sub $0x4,%esp
在调用函数之前要传入参数到栈中,规则是从右往左
可foo01函数,并不需要传参啊,为啥要分配4个字节呢?
在执行这条语句之前,esp的值为0xbffff094!!!赶紧回忆上文提到的16字节对齐

我猜测:因为接下来要调用foo01函数,为了使其栈对齐,而进行了sub $0x4,%esp。

执行该指令后,esp确实是16字节对齐的。
在这里插入图片描述
(3)继续解析剩余汇编代码
①call 0x804840b <foo01>

调用foo01函数

②mov $0x0,%eax

清零操作。在windows中,函数返回值都是放在eax中然后返回,外部从eax中得到返回值。这就代表return 0操作。

③add $0x4,%esp

调用完foo01函数了,不需要考虑其栈对齐了,对应于sub $0x4,%esp

④pop %ecx

对应与push %ecx

⑤pop %ebp

对应于push %ebp

⑥lea -0x4(%ecx),%esp

猜测 : 并不是通过pushl -0x4(%ecx)来返回的
所以需要lea -0x4(%ecx),%esp的方式得到返回地址。

⑦ret

把esp指向的栈中的数值赋给eip(程序计数器),回到_start函数开始执行。
在这里插入图片描述
结合上文,不是00000025,而是0xbffff09c。

三、缓冲区溢出攻击
再次强调,esp存的是内存地址,即指向栈顶。
下一篇博客介绍的**缓冲区溢出攻击**,即esp存的内存地址没变,但该地址指向的内容从返回地址变成了攻击者函数的入口地址。那么执行ret指令后,eip中就是攻击者函数的入口地址了。

四、参考文献
1.Understanding the purpose of some assembly statements
2.ret指令的原图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值