一、前言

1.1 叙叙旧

距离上一次写文章已经过去3个月了,当初计划至少一个月一篇,不曾想这一拖就是三个月。一直不写的主要原因是当把一个问题弄清楚了,或者说掌握了一个东西,就觉得没有什么可值得写;另外写文章也会花费一定的时间。不过想想阮一峰和王建硕讨论的写文章一方面可以提高自己的表述能力,一方面可以加深自己对知识的理解,于是便又拿起笔写下今天这篇文章。

1.2 文章摘要

这篇文章主要对函数调用栈的理论进行讲解,然后通过一个简单的例子,通过GDP-peda对汇编代码进行断点跟踪,加深对函数调用栈的理解。此外也对32位CPU的寄存器做一个简单的介绍。

二、基本理论

2.1 寄存器


32位处理器有数据寄存器、变址寄存器、指针寄存器、段寄存器、指令寄存器和标志寄存器,上图中简单介绍了寄存器的名称和基本作用。如果想要更加详细的连接寄存器,请参考Daryl的文章通用32位CPU 常用寄存器及其作用。

2.2 函数调用栈

关于函数调用栈我们需要知道的是栈空间是从高地址向低地址填充的,在进行函数调用的时候,首先将被调用函数的参数压入栈空间,压入参数的顺序是argnarg_nargn​, argn−1arg_{n-1}argn−1​ … arg0arg_0arg0​;接着压入函数的返回地址,函数的返回地址就是call指令的下一条指令的地址;接着压入被调用函数的基地址,基地址存放在EBP寄存器中;最后压入被调用函数的局部变量。关于函数调用栈的更多信息可以参考长亭科技的Jwizard的手把手教你栈溢出从入门到放弃。

三、调试分析

通过一个简单的C语言程序,通过GCC编译器将其编译为32位的程序,然后使用GDB-peda对其进行跟踪调试。通过观察寄存器中值的变化,来更加深刻的理解函数调用栈。

3.1 源代码

#include<stdio.h>
int sum(int a, int b) {int c = 10;int sum;sum = a + b + c;return sum;
}
int main() {int a, b, res;a = 2;b = 3;res = sum(a, b);printf("%d\n", res);return 0;
}

3.2 GCC编译为32位

gcc -g sum.c -o sum -m32

3.3 GDB调试

通过gdb sum命令对sum文件进行调试,在gdb-peda中使用l命令可以列出源代码。

3.4 开始调试

在gdp-peda中输入start命令开始调试,从下图中可以看到寄存器(registers),汇编代码(code),栈空间数据(stack)。此时基地址EBP寄存器的值是0xffffd5a8,栈顶寄存器ESP的值是0xffffd590,而指令寄存器EIP的值则是代码区中正准备执行的指令地址0x804843e。从图中可以看出0x804843b汇编指令分配了0x14个字节的空间供局部变量使用。

3.4.1 给变量a赋值

使用ni命令,执行0x804843e地址的汇编代码,可以发现把2(a的值)赋值给地址为[ebp-0x14] = 0xffffd594

3.4.2 给变量b赋值

使用ni命令,执行0x8048445地址的汇编代码,可以发现把3(b的值)赋值给地址为[ebp-0x10] = 0xffffd598

3.4.3 将b压入栈空间

在压入之前,esp的值为0xffffd590,所以b在栈空间的位置是0xffffd590 - 4 = 0xffffd58c

3.4.4 将a压入栈空间

和压入b同理,不多赘述。

3.4.5 进入sum函数

使用si命令,单步进入sum函数。从下图可以看出执行call指令的时候把call指令的下一条指令的地址0x8048457(见3.4.4图)作为返回地址压入了栈空间。接着需要将main函数的基地址(存放在ebp寄存器)压入栈空间。

3.4.6 压入main函数的基地址

使用ni命令执行0x804840c地址的指令,从上面的理论部分得知在压入调用函数的基地址之后,需要将当前栈顶(esp寄存器的值)赋值给ebp作为被调用函数的基地址,因为接下来就是执行被调用函数中的汇编代码。这里需要注意被调用函数的基地址存储的值是调用函数的基地址。

3.4.7 栈空间分布

此时我们已经完成了调用函数的入栈操作,通过stack命令可以查看当前栈空间的内容0xffffd59c我们暂时不管,这是main函数启动时的相关数据。从高地址到低地址分别存放的是0xffffd598 => main的局部变量b,0xffffd594 => main的局部变量a,0xffffd590 => 暂未使用,
0xffffd58c => sum函数的参数b,0xffffd588 => sum函数的参数a,0xffffd584 => sum函数的返回地址,0xffffd580 => main函数的基地址。

3.4.8 退出操作

在压入main函数的基地址后,执行了sum函数内部的加法操作,这里不做详细介绍。在执行完成以后会把结果放在eax寄存器中。然后执行leave指令,leave指令相当于mov esp,ebp; pop ebp;。执行mov esp,ebp将栈顶地址设置为被调用函数(sum函数)的基地址,被调用函数的基地址就是存储main函数基地址的地址。执行pop ebp,将ebp以下的地址包括ebp全部弹出栈空间(sum函数内部处理的时候也会把一些数据入栈,此时操作完成全部弹出),并把main函数的基地址赋值给ebp,成功完成函数的退栈。

最后执行ret指令,类似pop eip。把函数的返回地址赋值给eip,使其继续执行。

基于GDB-peda汇编调试理解函数调用栈相关推荐

  1. c语言中staloc是什么意思,C语言函数调用栈(三)

    6 调用栈实例分析 本节通过代码实例分析函数调用过程中栈帧的布局.形成和消亡. 6.1 栈帧的布局 示例代码如下: //StackReg.c #include //获取函数运行时寄存器%ebp和%es ...

  2. 【软件开发底层知识修炼】十七 快速学习GDB调试四 使用GDB进行函数调用栈的查看

    上一篇文章学习了如何使用GDB数据断点进行内存监测:[软件开发底层知识修炼]十五 快速学习GDB调试三 使用GDB的数据断点监测变量是否改变 本篇文章继续上一篇文章的学习:如何使用GDB进行函数调用栈 ...

  3. 【深入理解函数栈帧:探索函数调用的内部机制】

    本章我们要介绍的不是数学中的函数,而是C语言中的函数哟! 本章重点 了解汇编指令 深刻理解函数调用过程 样例代码: #include <stdio.h> int MyAdd(int a, ...

  4. gdb汇编调试c程序

    关于GDB调试C程序的常用命令与手段就不多说了,这里主要介绍一下如何对C程序做到汇编指令级别的调试. 首先是获取汇编代码,这可以通过disassemble命令或x命令或类似的命令: 1 2 3 4 5 ...

  5. 第19部分- Linux ARM汇编 函数调用栈使用-阶乘

    第19部分- Linux ARM汇编 函数调用栈使用-阶乘 调用栈我们以阶乘为例.阶乘比较经典. 堆栈定义:堆栈是仅由当前动态激活拥有的内存区域. 我们先来看下阶乘的C代码如下: int factor ...

  6. 汇总: pwn分析工具GDB + peda + objdump + readelf

    汇总: pwn分析工具GDB + peda + objdump + readelf 前言 1.GDB的基本操作 2.GDB增强工具peda 3.GNU工具链 (GNU Toolchain): objd ...

  7. C 语言 函数调用栈

    From:https://www.cnblogs.com/clover-toeic/p/3755401.html    https://www.cnblogs.com/clover-toeic/p/3 ...

  8. c理c利用计算机怎么弹,通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的...

    通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的 计算机的工作方式: 现代计算机的基本体系结构都是采用冯诺依曼结构,冯诺依曼的设计思想最重要之处是"存储程序"的这个概念 ...

  9. 64位x86的函数调用栈布局

    作者:gfree.wind@gmail.com 博客:blog.focus-linux.net    linuxfocus.blog.chinaunix.net 在看本文之前,如果不了解x86的32位 ...

最新文章

  1. Spring管理Strust的Action
  2. Metasploit 使用后门和Rootkit维持访问
  3. 文件bookDetails.html,查看源码: BookShopping.rar_bookdetails.jsp - VerySource
  4. BZOJ2055 80人环游世界
  5. nginx+tomcat实现Windows系统下的负载均衡搭建教程
  6. anaconda2-keras安装;keras后端修改
  7. Linux下用GDB调试程序崩溃错误
  8. 用命令行编译和运行C语言程序
  9. paip.提升用户体验---c++ 右键菜单以及socket接口
  10. qtableview及自定义model的使用,对比qtablewidget性能及内存优化
  11. 如何制作离线tts?
  12. 5053刷奥迪Q5隐藏功能
  13. 【Java】每日一点Java小知识 --- day6
  14. 浙江大学计算机学院 金小刚,金小刚(浙江大学CADCG国家重点实验室教授)_百度百科...
  15. [redis] 10 种数据结构详解
  16. hive sql中传date 指定后的“%Y-%m-%d“格式,需要加引号
  17. FBI 网站都被黑了?
  18. 操作系统:图文详解神秘的”内存映射“
  19. 从今天开始给自己定一个小目标
  20. 视频的格式也支持批量消音?一学就会

热门文章

  1. 通过游戏编程学Python(6)— 英汉词典、背单词
  2. 惠普179fnw打印机使用说明_惠普HP Color Laser MFP 179fnw一体机驱动
  3. PS照片转手绘之(白发魔女)
  4. RPC-BDY(1)-一个最简单RPC实现
  5. Ubuntu 20.04 gcc9 linux-sgx v2.9出现-fcf-protection -mfunction-return冲突
  6. 下载安装eclipse Jee
  7. Arduino与Proteus仿真实例-DS1307实时时钟驱动仿真
  8. DDD实战课(3):实战篇上
  9. 乐视 LeTMC-520体感摄像头 ROS驱动
  10. 【linux】程序找不到动态库.so的解决办法|查看.so动态库信息|.so动态库加载顺序