【反汇编分析】函数栈帧
来源:互联网 发布:vue.js chrome插件 编辑:程序博客网 时间:2024/05/22 06:20
本节通过反汇编可执行文件得到的文件,研究函数栈帧相关内容;
函数栈帧
栈帧整体示意图如下
示例代码
#include <stdio.h>#include <iostream>using namespace std;int z = 10;int add(int x, int y){ return x+y+z;}int inc20(int x){ int y = 10; return add(x, y);}int main(void){ int a = 30; a = inc20(a); cout << a << endl; return 0;}说明几点
(1)本节只研究main和inc20、add之间的函数栈帧,对于cout,以及main函数之前和之后的启动和结束代码不作研究;
例子整体栈帧示意图如下
反汇编代码
080486ac <_Z3addii>: 80486ac:55 push %ebp 80486ad:89 e5 mov %esp,%ebp 80486af:8b 55 08 mov 0x8(%ebp),%edx 80486b2:8b 45 0c mov 0xc(%ebp),%eax 80486b5:01 c2 add %eax,%edx 80486b7:a1 84 9a 04 08 mov 0x8049a84,%eax 80486bc:01 d0 add %edx,%eax 80486be:5d pop %ebp 80486bf:c3 ret 080486c0 <_Z5inc20i>: 80486c0:55 push %ebp 80486c1:89 e5 mov %esp,%ebp 80486c3:83 ec 10 sub $0x10,%esp 80486c6:c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%ebp) 80486cd:ff 75 fc pushl -0x4(%ebp) 80486d0:ff 75 08 pushl 0x8(%ebp) 80486d3:e8 d4 ff ff ff call 80486ac <_Z3addii> 80486d8:83 c4 08 add $0x8,%esp 80486db:c9 leave 80486dc:c3 ret 080486dd <main>: 80486dd:8d 4c 24 04 lea 0x4(%esp),%ecx 80486e1:83 e4 f0 and $0xfffffff0,%esp 80486e4:ff 71 fc pushl -0x4(%ecx) 80486e7:55 push %ebp 80486e8:89 e5 mov %esp,%ebp 80486ea:51 push %ecx 80486eb:83 ec 14 sub $0x14,%esp 80486ee:c7 45 f4 1e 00 00 00 movl $0x1e,-0xc(%ebp) 80486f5:ff 75 f4 pushl -0xc(%ebp) 80486f8:e8 c3 ff ff ff call 80486c0 <_Z5inc20i> 80486fd:83 c4 04 add $0x4,%esp 8048700:89 45 f4 mov %eax,-0xc(%ebp) 8048703:83 ec 08 sub $0x8,%esp 8048706:ff 75 f4 pushl -0xc(%ebp) 8048709:68 c0 9a 04 08 push $0x8049ac0 804870e:e8 e9 fd ff ff call 80484fc <_ZNSolsEi@plt> 8048713:83 c4 10 add $0x10,%esp 8048716:83 ec 08 sub $0x8,%esp 8048719:68 6c 85 04 08 push $0x804856c 804871e:50 push %eax 804871f:e8 38 fe ff ff call 804855c <_ZNSolsEPFRSoS_E@plt> 8048724:83 c4 10 add $0x10,%esp 8048727:b8 00 00 00 00 mov $0x0,%eax 804872c:8b 4d fc mov -0x4(%ebp),%ecx 804872f:c9 leave 8048730:8d 61 fc lea -0x4(%ecx),%esp 8048733:c3 ret说明几点
(1)首先在_Z3addii找出z变量的地址和相关信息;
sykpour@sykpour:~/Desktop$ readelf -s test | grep 8049a84 75: 08049a84 4 OBJECT GLOBAL DEFAULT 23 z(2)立即数前面的标识是$,popl为双字(单字为16字节)出栈,对于寄存器而言pop %esp也是栈中双字赋值给esp;如movl $0xa,-0x4(%ebp)表示将立即数0xa存放到ebp+4地址处;而mov 0x8(%ebp),%edx表示将ebp+8地址处的内容存放到edx寄存器中;
汇编注释
080486ac <_Z3addii>: 80486ac:55 push %ebp 80486ad:89 e5 mov %esp,%ebp 80486af:8b 55 08 mov 0x8(%ebp),%edx #取参数x到edx 80486b2:8b 45 0c mov 0xc(%ebp),%eax #取参数y到eax 80486b5:01 c2 add %eax,%edx #x=x+y; 80486b7:a1 84 9a 04 08 mov 0x8049a84,%eax #取z的内容到eax 80486bc:01 d0 add %edx,%eax #z=z+x; 80486be:5d pop %ebp 80486bf:c3 ret 080486c0 <_Z5inc20i>: 80486c0:55 push %ebp 80486c1:89 e5 mov %esp,%ebp 80486c3:83 ec 10 sub $0x10,%esp 80486c6:c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%ebp) #局部变量y的值 80486cd:ff 75 fc pushl -0x4(%ebp) #add的参数y 80486d0:ff 75 08 pushl 0x8(%ebp) #add的参数x,ebp是在main函数的栈中找的值 80486d3:e8 d4 ff ff ff call 80486ac <_Z3addii> 80486d8:83 c4 08 add $0x8,%esp #调整栈指针 80486db:c9 leave 80486dc:c3 ret 080486dd <main>: 80486dd:8d 4c 24 04 lea 0x4(%esp),%ecx 80486e1:83 e4 f0 and $0xfffffff0,%esp 80486e4:ff 71 fc pushl -0x4(%ecx) 80486e7:55 push %ebp #保存栈帧寄存器 80486e8:89 e5 mov %esp,%ebp #帧指针指向栈指针 80486ea:51 push %ecx #保护ecx寄存器的内容 80486eb:83 ec 14 sub $0x14,%esp #调整栈指针,存放局部变量 80486ee:c7 45 f4 1e 00 00 00 movl $0x1e,-0xc(%ebp) #局部变量a的值 80486f5:ff 75 f4 pushl -0xc(%ebp) #inc20的参数x 80486f8:e8 c3 ff ff ff call 80486c0 <_Z5inc20i> 80486fd:83 c4 04 add $0x4,%esp #调整栈指针 8048700:89 45 f4 mov %eax,-0xc(%ebp) #cout打印的参数,直接从add的eax中取回的 8048703:83 ec 08 sub $0x8,%esp 8048706:ff 75 f4 pushl -0xc(%ebp) 8048709:68 c0 9a 04 08 push $0x8049ac0 804870e:e8 e9 fd ff ff call 80484fc <_ZNSolsEi@plt>
越界访问
在使用gets这样的函数时,很有可能使用栈中分配一个数组来保存字符串,但是字符串的长度却超过了分配的空间,这有可能会带来很严重的问题;
代码片段
#include <stdio.h>using namespace std;int main(void){ char buf[16]; gets(buf); puts(buf); return 0;}
反汇编
080484fc <main>: 80484fc:8d 4c 24 04 lea 0x4(%esp),%ecx 8048500:83 e4 f0 and $0xfffffff0,%esp 8048503:ff 71 fc pushl -0x4(%ecx) 8048506:55 push %ebp 8048507:89 e5 mov %esp,%ebp 8048509:51 push %ecx 804850a:83 ec 14 sub $0x14,%esp 804850d:83 ec 0c sub $0xc,%esp 8048510:8d 45 e8 lea -0x18(%ebp),%eax 8048513:50 push %eax 8048514:e8 83 fe ff ff call 804839c <gets@plt> 8048519:83 c4 10 add $0x10,%esp 804851c:83 ec 0c sub $0xc,%esp 804851f:8d 45 e8 lea -0x18(%ebp),%eax 8048522:50 push %eax 8048523:e8 94 fe ff ff call 80483bc <puts@plt> 8048528:83 c4 10 add $0x10,%esp 804852b:b8 00 00 00 00 mov $0x0,%eax 8048530:8b 4d fc mov -0x4(%ebp),%ecx 8048533:c9 leave 8048534:8d 61 fc lea -0x4(%ecx),%esp 8048537:c3 ret 8048538:90 nop 8048539:90 nop 804853a:90 nop 804853b:90 nop 804853c:90 nop 804853d:90 nop 804853e:90 nop 804853f:90 nop
main函数栈帧示意图
说明几点:
(1)通过示意图发现,如果gets输入超过16个字节,那么保存的ebp和ecx的值都有可能受到破坏,也就极有可能发生段错误;
(2)如果修改main函数上的返回地址,也就有可能使得程序跳转到不安全的代码中去;
汇编注释
8048506:55 push %ebp #保存帧指针 8048507:89 e5 mov %esp,%ebp #帧指针指向栈指针 8048509:51 push %ecx 804850a:83 ec 14 sub $0x14,%esp 804850d:83 ec 0c sub $0xc,%esp 8048510:8d 45 e8 lea -0x18(%ebp),%eax #取buf的地址 8048513:50 push %eax 8048514:e8 83 fe ff ff call 804839c <gets@plt>
0 0
- 【反汇编分析】函数栈帧
- C++ 函数反汇编跟踪以及栈结构分析
- 反汇编深入分析函数调用
- 反汇编深入分析函数调用
- 反汇编深入分析函数调用
- 反汇编深入分析函数调用
- 反汇编代码分析--函数调用
- C++反汇编代码分析--函数调用
- C++反汇编代码分析--函数调用
- 反汇编深入分析函数调用
- C++反汇编代码分析--函数调用
- C++反汇编代码分析--函数调用
- 反汇编代码分析--函数调用
- 反汇编及函数调用堆栈分析
- cpp反汇编分析之构造函数
- C++反汇编代码分析--函数调用
- 函数调用过程(反汇编分析)
- 反汇编分析objc函数枢纽objc_msgSend
- NSString基础用法
- 短信应用——短信(会话)删除
- nodejs 搭建IM即时通讯平台
- 蓝桥杯---矩形运算(求相交部分)
- 《精通Linux设备驱动程序开发》——块设备驱动程序
- 【反汇编分析】函数栈帧
- 柴郡猫技术--C++中的PIMPL设计模式
- 第三周项目 2 测试与设计
- 【leetcode】Merge k Sorted Lists
- [POJ3922]Now解题报告
- Annotation笔记
- BZOJ 2152 (树形DP)
- oc中不允许方法重载
- 逆序对的求法 归并排序